libs/nixio: add missing file in previous commit, revert unrelated change
[project/luci.git] / libs / nixio / src / address.c
1 /*
2 * nixio - Linux I/O library for lua
3 *
4 * Copyright (C) 2009 Steven Barth <steven@midlink.org>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include "nixio.h"
20 #include <sys/types.h>
21 #include <sys/param.h>
22 #include <errno.h>
23 #include <string.h>
24
25 #ifdef __linux__
26 #include <linux/netdevice.h>
27
28 /* struct net_device_stats is buggy on amd64, redefine it */
29 struct nixio__nds {
30 uint32_t rx_packets;
31 uint32_t tx_packets;
32 uint32_t rx_bytes;
33 uint32_t tx_bytes;
34 uint32_t rx_errors;
35 uint32_t tx_errors;
36 uint32_t rx_dropped;
37 uint32_t tx_dropped;
38 uint32_t multicast;
39 uint32_t collisions;
40
41 uint32_t rx_length_errors;
42 uint32_t rx_over_errors;
43 uint32_t rx_crc_errors;
44 uint32_t rx_frame_errors;
45 uint32_t rx_fifo_errors;
46 uint32_t rx_missed_errors;
47
48 uint32_t tx_aborted_errors;
49 uint32_t tx_carrier_errors;
50 uint32_t tx_fifo_errors;
51 uint32_t tx_heartbeat_errors;
52 uint32_t tx_window_errors;
53
54 uint32_t rx_compressed;
55 uint32_t tx_compressed;
56 };
57 #endif
58
59 #ifndef NI_MAXHOST
60 #define NI_MAXHOST 1025
61 #endif
62
63 /**
64 * address pushing helper
65 */
66 int nixio__addr_parse(nixio_addr *addr, struct sockaddr *saddr) {
67 void *baddr;
68
69 addr->family = saddr->sa_family;
70 if (saddr->sa_family == AF_INET) {
71 struct sockaddr_in *inetaddr = (struct sockaddr_in*)saddr;
72 addr->port = ntohs(inetaddr->sin_port);
73 baddr = &inetaddr->sin_addr;
74 } else if (saddr->sa_family == AF_INET6) {
75 struct sockaddr_in6 *inet6addr = (struct sockaddr_in6*)saddr;
76 addr->port = ntohs(inet6addr->sin6_port);
77 baddr = &inet6addr->sin6_addr;
78 #ifdef AF_PACKET
79 } else if (saddr->sa_family == AF_PACKET) {
80 struct sockaddr_ll *etheradddr = (struct sockaddr_ll*)saddr;
81 addr->prefix = etheradddr->sll_hatype;
82 addr->port = etheradddr->sll_ifindex;
83 char *c = addr->host;
84 for (size_t i = 0; i < etheradddr->sll_halen; i++) {
85 *c++ = nixio__bin2hex[(etheradddr->sll_addr[i] & 0xf0) >> 4];
86 *c++ = nixio__bin2hex[(etheradddr->sll_addr[i] & 0x0f)];
87 *c++ = ':';
88 }
89 *(c-1) = 0;
90 return 0;
91 #endif
92 } else {
93 errno = EAFNOSUPPORT;
94 return -1;
95 }
96
97 if (!inet_ntop(saddr->sa_family, baddr, addr->host, sizeof(addr->host))) {
98 return -1;
99 }
100
101 return 0;
102 }
103
104 /**
105 * address pulling helper
106 */
107 int nixio__addr_write(nixio_addr *addr, struct sockaddr *saddr) {
108 if (addr->family == AF_UNSPEC) {
109 if (strchr(addr->host, ':')) {
110 addr->family = AF_INET6;
111 } else {
112 addr->family = AF_INET;
113 }
114 }
115 if (addr->family == AF_INET) {
116 struct sockaddr_in *inetaddr = (struct sockaddr_in *)saddr;
117 memset(inetaddr, 0, sizeof(struct sockaddr_in));
118
119 if (inet_pton(AF_INET, addr->host, &inetaddr->sin_addr) < 1) {
120 return -1;
121 }
122
123 inetaddr->sin_family = AF_INET;
124 inetaddr->sin_port = htons((uint16_t)addr->port);
125 return 0;
126 } else if (addr->family == AF_INET6) {
127 struct sockaddr_in6 *inet6addr = (struct sockaddr_in6 *)saddr;
128 memset(inet6addr, 0, sizeof(struct sockaddr_in6));
129
130 if (inet_pton(AF_INET6, addr->host, &inet6addr->sin6_addr) < 1) {
131 return -1;
132 }
133
134 inet6addr->sin6_family = AF_INET6;
135 inet6addr->sin6_port = htons((uint16_t)addr->port);
136 return 0;
137 } else {
138 errno = EAFNOSUPPORT;
139 return -1;
140 }
141 }
142
143 /**
144 * netmask to prefix helper
145 */
146 int nixio__addr_prefix(struct sockaddr *saddr) {
147 int prefix = 0;
148 size_t len;
149 uint8_t *addr;
150
151 if (saddr->sa_family == AF_INET) {
152 addr = (uint8_t*)(&((struct sockaddr_in*)saddr)->sin_addr);
153 len = 4;
154 } else if (saddr->sa_family == AF_INET6) {
155 addr = (uint8_t*)(&((struct sockaddr_in6*)saddr)->sin6_addr);
156 len = 16;
157 } else {
158 errno = EAFNOSUPPORT;
159 return -1;
160 }
161
162 for (size_t i = 0; i < len; i++) {
163 if (addr[i] == 0xff) {
164 prefix += 8;
165 } else if (addr[i] == 0x00) {
166 break;
167 } else {
168 for (uint8_t c = addr[i]; c; c <<= 1) {
169 prefix++;
170 }
171 }
172 }
173
174 return prefix;
175 }
176
177 /**
178 * getaddrinfo(host, family, port)
179 */
180 static int nixio_getaddrinfo(lua_State *L) {
181 const char *host = NULL;
182 if (!lua_isnoneornil(L, 1)) {
183 host = luaL_checklstring(L, 1, NULL);
184 }
185 const char *family = luaL_optlstring(L, 2, "any", NULL);
186 const char *port = lua_tolstring(L, 3, NULL);
187
188 struct addrinfo hints, *result, *rp;
189 memset(&hints, 0, sizeof(hints));
190
191 if (!strcmp(family, "any")) {
192 hints.ai_family = AF_UNSPEC;
193 } else if (!strcmp(family, "inet")) {
194 hints.ai_family = AF_INET;
195 } else if (!strcmp(family, "inet6")) {
196 hints.ai_family = AF_INET6;
197 } else {
198 return luaL_argerror(L, 2, "supported values: any, inet, inet6");
199 }
200
201 hints.ai_socktype = 0;
202 hints.ai_protocol = 0;
203
204 int aistat = getaddrinfo(host, port, &hints, &result);
205 if (aistat) {
206 lua_pushnil(L);
207 lua_pushinteger(L, aistat);
208 lua_pushstring(L, gai_strerror(aistat));
209 return 3;
210 }
211
212 /* create socket object */
213 lua_newtable(L);
214 int i = 1;
215
216 for (rp = result; rp != NULL; rp = rp->ai_next) {
217 /* avoid duplicate results */
218 #ifndef __WINNT__
219 if (!port && rp->ai_socktype != SOCK_STREAM) {
220 continue;
221 }
222 #endif
223
224 if (rp->ai_family == AF_INET || rp->ai_family == AF_INET6) {
225 lua_createtable(L, 0, port ? 4 : 2);
226 if (rp->ai_family == AF_INET) {
227 lua_pushliteral(L, "inet");
228 } else if (rp->ai_family == AF_INET6) {
229 lua_pushliteral(L, "inet6");
230 }
231 lua_setfield(L, -2, "family");
232
233 if (port) {
234 switch (rp->ai_socktype) {
235 case SOCK_STREAM:
236 lua_pushliteral(L, "stream");
237 break;
238 case SOCK_DGRAM:
239 lua_pushliteral(L, "dgram");
240 break;
241 case SOCK_RAW:
242 lua_pushliteral(L, "raw");
243 break;
244 default:
245 lua_pushnil(L);
246 break;
247 }
248 lua_setfield(L, -2, "socktype");
249 }
250
251 nixio_addr addr;
252 if (nixio__addr_parse(&addr, rp->ai_addr)) {
253 freeaddrinfo(result);
254 return nixio__perror_s(L);
255 }
256
257 if (port) {
258 lua_pushinteger(L, addr.port);
259 lua_setfield(L, -2, "port");
260 }
261
262 lua_pushstring(L, addr.host);
263 lua_setfield(L, -2, "address");
264 lua_rawseti(L, -2, i++);
265 }
266 }
267
268 freeaddrinfo(result);
269
270 return 1;
271 }
272
273 /**
274 * getnameinfo(address, family)
275 */
276 static int nixio_getnameinfo(lua_State *L) {
277 const char *ip = luaL_checkstring(L, 1);
278 const char *family = luaL_optstring(L, 2, NULL);
279 char host[NI_MAXHOST];
280
281 struct sockaddr_storage saddr;
282 nixio_addr addr;
283 memset(&addr, 0, sizeof(addr));
284 strncpy(addr.host, ip, sizeof(addr.host) - 1);
285
286 if (!family) {
287 addr.family = AF_UNSPEC;
288 } else if (!strcmp(family, "inet")) {
289 addr.family = AF_INET;
290 } else if (!strcmp(family, "inet6")) {
291 addr.family = AF_INET6;
292 } else {
293 return luaL_argerror(L, 2, "supported values: inet, inet6");
294 }
295
296 nixio__addr_write(&addr, (struct sockaddr *)&saddr);
297
298 int res = getnameinfo((struct sockaddr *)&saddr, sizeof(saddr),
299 host, sizeof(host), NULL, 0, NI_NAMEREQD);
300 if (res) {
301 lua_pushnil(L);
302 lua_pushinteger(L, res);
303 lua_pushstring(L, gai_strerror(res));
304 return 3;
305 } else {
306 lua_pushstring(L, host);
307 return 1;
308 }
309 }
310
311 /**
312 * getsockname()
313 */
314 static int nixio_sock_getsockname(lua_State *L) {
315 int sockfd = nixio__checksockfd(L);
316 struct sockaddr_storage saddr;
317 socklen_t addrlen = sizeof(saddr);
318 nixio_addr addr;
319
320 if (getsockname(sockfd, (struct sockaddr*)&saddr, &addrlen) ||
321 nixio__addr_parse(&addr, (struct sockaddr*)&saddr)) {
322 return nixio__perror_s(L);
323 }
324
325 lua_pushstring(L, addr.host);
326 lua_pushinteger(L, addr.port);
327 return 2;
328 }
329
330 /**
331 * getpeername()
332 */
333 static int nixio_sock_getpeername(lua_State *L) {
334 int sockfd = nixio__checksockfd(L);
335 struct sockaddr_storage saddr;
336 socklen_t addrlen = sizeof(saddr);
337 nixio_addr addr;
338
339 if (getpeername(sockfd, (struct sockaddr*)&saddr, &addrlen) ||
340 nixio__addr_parse(&addr, (struct sockaddr*)&saddr)) {
341 return nixio__perror_s(L);
342 }
343
344 lua_pushstring(L, addr.host);
345 lua_pushinteger(L, addr.port);
346 return 2;
347 }
348
349 #if defined(__linux__) || defined(BSD)
350 #ifdef BSD
351 #include <net/if.h>
352 #endif
353 #include <ifaddrs.h>
354
355 static int nixio_getifaddrs(lua_State *L) {
356 nixio_addr addr;
357 struct ifaddrs *ifaddr, *c;
358 if (getifaddrs(&ifaddr) == -1) {
359 return nixio__perror(L);
360 }
361
362 lua_newtable(L);
363 unsigned int i = 1;
364
365 for (c = ifaddr; c; c = c->ifa_next) {
366 lua_newtable(L);
367
368 lua_pushstring(L, c->ifa_name);
369 lua_setfield(L, -2, "name");
370
371 lua_createtable(L, 0, 7);
372 lua_pushboolean(L, c->ifa_flags & IFF_UP);
373 lua_setfield(L, -2, "up");
374
375 lua_pushboolean(L, c->ifa_flags & IFF_BROADCAST);
376 lua_setfield(L, -2, "broadcast");
377
378 lua_pushboolean(L, c->ifa_flags & IFF_LOOPBACK);
379 lua_setfield(L, -2, "loopback");
380
381 lua_pushboolean(L, c->ifa_flags & IFF_POINTOPOINT);
382 lua_setfield(L, -2, "pointtopoint");
383
384 lua_pushboolean(L, c->ifa_flags & IFF_NOARP);
385 lua_setfield(L, -2, "noarp");
386
387 lua_pushboolean(L, c->ifa_flags & IFF_PROMISC);
388 lua_setfield(L, -2, "promisc");
389
390 lua_pushboolean(L, c->ifa_flags & IFF_MULTICAST);
391 lua_setfield(L, -2, "multicast");
392 lua_setfield(L, -2, "flags");
393
394 if (c->ifa_addr) {
395 if (!nixio__addr_parse(&addr, c->ifa_addr)) {
396 lua_pushstring(L, addr.host);
397 lua_setfield(L, -2, "addr");
398 }
399
400 if (c->ifa_addr->sa_family == AF_INET) {
401 lua_pushliteral(L, "inet");
402 } else if (c->ifa_addr->sa_family == AF_INET6) {
403 lua_pushliteral(L, "inet6");
404 #ifdef AF_PACKET
405 } else if (c->ifa_addr->sa_family == AF_PACKET) {
406 lua_pushliteral(L, "packet");
407 #endif
408 } else {
409 lua_pushliteral(L, "unknown");
410 }
411 lua_setfield(L, -2, "family");
412
413 #ifdef __linux__
414 if (c->ifa_addr->sa_family == AF_PACKET) {
415 lua_pushinteger(L, addr.port);
416 lua_setfield(L, -2, "ifindex");
417
418 lua_pushinteger(L, addr.prefix);
419 lua_setfield(L, -2, "hatype");
420 }
421 #endif
422 }
423
424 #ifdef __linux__
425 if (c->ifa_data && (!c->ifa_addr
426 || c->ifa_addr->sa_family == AF_PACKET)) {
427 if (!c->ifa_addr) {
428 lua_pushliteral(L, "packet");
429 lua_setfield(L, -2, "family");
430 }
431
432 lua_createtable(L, 0, 10);
433 struct nixio__nds *stats = c->ifa_data;
434
435 lua_pushnumber(L, stats->rx_packets);
436 lua_setfield(L, -2, "rx_packets");
437
438 lua_pushnumber(L, stats->tx_packets);
439 lua_setfield(L, -2, "tx_packets");
440
441 lua_pushnumber(L, stats->rx_bytes);
442 lua_setfield(L, -2, "rx_bytes");
443
444 lua_pushnumber(L, stats->tx_bytes);
445 lua_setfield(L, -2, "tx_bytes");
446
447 lua_pushnumber(L, stats->rx_errors);
448 lua_setfield(L, -2, "rx_errors");
449
450 lua_pushnumber(L, stats->tx_errors);
451 lua_setfield(L, -2, "tx_errors");
452
453 lua_pushnumber(L, stats->rx_dropped);
454 lua_setfield(L, -2, "rx_dropped");
455
456 lua_pushnumber(L, stats->tx_dropped);
457 lua_setfield(L, -2, "tx_dropped");
458
459 lua_pushnumber(L, stats->multicast);
460 lua_setfield(L, -2, "multicast");
461
462 lua_pushnumber(L, stats->collisions);
463 lua_setfield(L, -2, "collisions");
464 } else {
465 lua_newtable(L);
466 }
467 lua_setfield(L, -2, "data");
468 #endif
469
470 if (c->ifa_netmask && !nixio__addr_parse(&addr, c->ifa_netmask)) {
471 lua_pushstring(L, addr.host);
472 lua_setfield(L, -2, "netmask");
473
474 lua_pushinteger(L, nixio__addr_prefix(c->ifa_netmask));
475 lua_setfield(L, -2, "prefix");
476 }
477
478 if (c->ifa_broadaddr && !nixio__addr_parse(&addr, c->ifa_broadaddr)) {
479 lua_pushstring(L, addr.host);
480 lua_setfield(L, -2, "broadaddr");
481 }
482
483 if (c->ifa_dstaddr && !nixio__addr_parse(&addr, c->ifa_dstaddr)) {
484 lua_pushstring(L, addr.host);
485 lua_setfield(L, -2, "dstaddr");
486 }
487
488 lua_rawseti(L, -2, i++);
489 }
490
491 freeifaddrs(ifaddr);
492 return 1;
493 }
494 #endif
495
496
497 /* module table */
498 static const luaL_reg R[] = {
499 #if defined(__linux__) || defined(BSD)
500 {"getifaddrs", nixio_getifaddrs},
501 #endif
502 {"getaddrinfo", nixio_getaddrinfo},
503 {"getnameinfo", nixio_getnameinfo},
504 {NULL, NULL}
505 };
506
507 /* object table */
508 static const luaL_reg M[] = {
509 {"getsockname", nixio_sock_getsockname},
510 {"getpeername", nixio_sock_getpeername},
511 {NULL, NULL}
512 };
513
514 void nixio_open_address(lua_State *L) {
515 luaL_register(L, NULL, R);
516
517 lua_pushvalue(L, -2);
518 luaL_register(L, NULL, M);
519 lua_pop(L, 1);
520 }