Annotation of libelwix/src/net.c, revision 1.10.10.8
1.1 misho 1: /*************************************************************************
2: * (C) 2013 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
1.10.10.8! misho 6: * $Id: net.c,v 1.10.10.7 2014/12/17 01:12:34 misho Exp $
1.1 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.9 misho 15: Copyright 2004 - 2014
1.1 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
1.6 misho 49: static char hexlist[] = "0123456789abcdef";
50:
51: /*
52: * e_link_ntoa() - String ethernet address from link address
53: *
54: * @sdl = link address
55: * return: =NULL error or !=NULL ethernet address, should be e_free()
56: */
57: char *
58: e_link_ntoa(const struct sockaddr_dl *sdl)
59: {
60: static char obuf[64];
61: char *out = obuf;
62: int i;
63: u_char *in = (u_char*) LLADDR(sdl);
64: u_char *inlim = in + sdl->sdl_alen;
65: int firsttime = 1;
66:
67: if (sdl->sdl_nlen) {
68: memcpy(obuf, sdl->sdl_data, sdl->sdl_nlen);
69: out += sdl->sdl_nlen;
70: if (sdl->sdl_alen)
71: *out++ = '!';
72: }
73:
74: while (in < inlim) {
75: if (firsttime)
76: firsttime ^= firsttime;
77: else
78: *out++ = ':';
1.8 misho 79:
1.6 misho 80: i = *in++;
81: if (i > 0xf) {
82: out[1] = hexlist[i & 0xf];
83: i >>= 4;
1.8 misho 84: } else {
85: out[1] = hexlist[i];
86: i = 0;
87: }
1.6 misho 88:
89: out[0] = hexlist[i];
90: out += 2;
91: }
92:
93: *out = 0;
94: return obuf;
95: }
96:
1.1 misho 97: /*
1.10.10.4 misho 98: * e_link_addr() - String ethernet address to link address
99: *
100: * @mac = ethernet address
101: * @sdl = link address
102: * return: -1 error or 0 ok
103: */
104: int
105: e_link_addr(const char *mac, struct sockaddr_dl * __restrict sdl)
106: {
107: if (!mac || !sdl)
108: return -1;
109: if (!sdl->sdl_len)
110: sdl->sdl_len = sizeof(struct sockaddr_dl);
111:
112: link_addr(mac, sdl);
113: return 0;
114: }
115:
116: /*
1.1 misho 117: * e_ether_ntoa() - Convert ethernet address to string
118: *
119: * @n = ethernet address structure, like struct ether_addr
120: * @a = string
121: * @len = string length
122: * return: NULL error or !=NULL string a
123: */
1.2 misho 124: char *
1.7 misho 125: e_ether_ntoa(const ether_addr_t * __restrict n, char * __restrict a, int len)
1.1 misho 126: {
127: if (!n || !a)
128: return NULL;
129:
130: memset(a, 0, len);
1.8 misho 131: if (snprintf(a, len, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
1.10.10.7 misho 132: n->octet[0], n->octet[1],
133: n->octet[2], n->octet[3],
134: n->octet[4], n->octet[5]) < 17)
1.1 misho 135: return NULL;
136:
137: return a;
138: }
139:
140: /*
141: * e_ether_aton() - Convert string to ethernet address
142: *
143: * @a = string
144: * @e = ethernet address structure, like struct ether_addr
145: * return: NULL error or !=NULL ethernet address structure
146: */
1.7 misho 147: ether_addr_t *
148: e_ether_aton(const char *a, ether_addr_t * __restrict e)
1.1 misho 149: {
150: int i;
151:
152: if (!a || !e)
153: return NULL;
154:
1.8 misho 155: i = sscanf(a, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
1.10.10.7 misho 156: &e->octet[0],
157: &e->octet[1],
158: &e->octet[2],
159: &e->octet[3],
160: &e->octet[4],
161: &e->octet[5]);
1.1 misho 162: if (i != 6)
163: return NULL;
164:
165: return e;
166: }
167:
168: /*
169: * e_n2port() - Extract port from network structure
170: *
171: * @addr = Address
172: * return: 0 not supported family type or port number
173: */
1.2 misho 174: u_short
1.1 misho 175: e_n2port(sockaddr_t * __restrict addr)
176: {
177: u_short port = 0;
178:
179: if (!addr)
180: return port;
181:
182: switch (addr->sa.sa_family) {
183: case AF_INET:
184: return ntohs(addr->sin.sin_port);
185: case AF_INET6:
186: return ntohs(addr->sin6.sin6_port);
187: default:
188: break;
189: }
190:
191: return port;
192: }
193:
194: /*
195: * e_n2addr() - Extract address from network structure
196: *
197: * @addr = Address
198: * @val = Value for store string address
199: * return: NULL error or !=NULL string address from val
200: */
201: const char *
202: e_n2addr(sockaddr_t * __restrict addr, ait_val_t * __restrict val)
203: {
1.5 misho 204: char *s, str[INET6_ADDRSTRLEN] = { 0 };
1.1 misho 205: const char *ret = NULL;
206:
207: if (!addr || !val)
208: return ret;
209:
210: AIT_INIT_VAL(val);
211: switch (addr->sa.sa_family) {
212: case AF_INET:
213: if (!inet_ntop(AF_INET, &addr->sin.sin_addr, str, INET_ADDRSTRLEN)) {
214: LOGERR;
215: return ret;
216: } else
217: ret = str;
218: break;
219: case AF_INET6:
220: if (!inet_ntop(AF_INET6, &addr->sin6.sin6_addr, str, INET6_ADDRSTRLEN)) {
221: LOGERR;
222: return ret;
223: } else
224: ret = str;
225: break;
226: case AF_LOCAL:
227: ret = addr->sun.sun_path;
228: break;
1.5 misho 229: case AF_LINK:
1.6 misho 230: if (!(s = e_link_ntoa(&addr->sdl))) {
1.5 misho 231: LOGERR;
232: return ret;
233: } else
234: ret = s;
235: break;
1.1 misho 236: default:
237: elwix_SetErr(EPROTONOSUPPORT, "Unsuported address family %d",
238: addr->sa.sa_family);
239: return ret;
240: }
241:
242: AIT_SET_STR(val, ret);
243: return (const char*) AIT_GET_STR(val);
244: }
245:
246: /*
247: * e_gethostbyname() - Get host and port and make network structure
248: *
249: * @psHost = Hostname
250: * @port = Port
251: * @addr = Network address structure
252: * return: NULL error or !=NULL network structure
253: */
254: sockaddr_t *
255: e_gethostbyname(const char *psHost, u_short port, sockaddr_t * __restrict addr)
256: {
257: struct hostent *host = NULL;
258:
259: if (!psHost || !addr)
260: return NULL;
261:
262: if (*psHost != '/') {
263: /* resolver */
1.10 misho 264: host = gethostbyname2(psHost, !strchr(psHost, ':') ? AF_INET : AF_INET6);
1.1 misho 265: if (!host) {
266: elwix_SetErr(EINVAL, "Resolver #%d - %s", h_errno, hstrerror(h_errno));
267: return NULL;
268: } else {
269: memset(addr, 0, sizeof(sockaddr_t));
270: addr->sa.sa_family = host->h_addrtype;
271: }
272: } else {
273: memset(addr, 0, sizeof(sockaddr_t));
274: addr->sa.sa_family = AF_LOCAL;
275: }
276:
277:
278: switch (addr->sa.sa_family) {
279: case AF_INET:
280: addr->sin.sin_len = sizeof(struct sockaddr_in);
281: addr->sin.sin_family = AF_INET;
282: addr->sin.sin_port = htons(port);
283: memcpy(&addr->sin.sin_addr, host->h_addr, sizeof addr->sin.sin_addr);
284: return addr;
285: case AF_INET6:
286: addr->sin6.sin6_len = sizeof(struct sockaddr_in6);
287: addr->sin6.sin6_family = AF_INET6;
288: addr->sin6.sin6_port = htons(port);
289: memcpy(&addr->sin6.sin6_addr, host->h_addr, sizeof addr->sin6.sin6_addr);
290: return addr;
291: case AF_LOCAL:
292: addr->sun.sun_len = sizeof(struct sockaddr_un);
293: addr->sun.sun_family = AF_LOCAL;
294: memset(addr->sun.sun_path, 0, sizeof addr->sun.sun_path);
295: snprintf(addr->sun.sun_path, sizeof addr->sun.sun_path, "%s-%hu", psHost, port);
296: return addr;
297: default:
298: elwix_SetErr(EPROTONOSUPPORT, "Unsuported address family %d", addr->sa.sa_family);
299: break;
300: }
301:
302: return NULL;
303: }
304:
305: /*
306: * e_addrcmp() - Compare network addresses
307: *
308: * @a = 1st address
309: * @b = 2nd address
310: * @p = compare and ports, if family is AF_INET or AF_INET6
311: * return: 0 is equal or !=0 is different
312: */
313: int
314: e_addrcmp(sockaddr_t * __restrict a, sockaddr_t * __restrict b, int p)
315: {
316: if (a && b && a->sa.sa_family == b->sa.sa_family)
317: switch (a->sa.sa_family) {
318: case AF_LOCAL:
319: return strcmp(a->sun.sun_path, b->sun.sun_path);
320: case AF_INET:
321: if (p && (a->sin.sin_port - b->sin.sin_port))
322: return (int) !!(a->sin.sin_port - b->sin.sin_port);
323: else
324: return memcmp(&a->sin.sin_addr, &b->sin.sin_addr,
325: sizeof a->sin.sin_addr);
326: case AF_INET6:
327: if (p && (a->sin6.sin6_port - b->sin6.sin6_port))
328: return (int) !!(a->sin6.sin6_port - b->sin6.sin6_port);
329: else
330: return memcmp(&a->sin6.sin6_addr, &b->sin6.sin6_addr,
331: sizeof a->sin6.sin6_addr);
332: case AF_LINK:
333: return memcmp(&a->sdl.sdl_data, &b->sdl.sdl_data,
334: sizeof a->sdl.sdl_data);
1.10.10.8! misho 335: case AF_UNSPEC:
! 336: return memcmp(a, b, sizeof(sockaddr_t));
1.1 misho 337: }
338:
339: return (int) !!(a - b);
340: }
341:
342: /*
343: * e_usleep() - usleep() replacement for ELWIX
344: *
345: * @usec = microseconds for sleep
346: * return: -1 interrupted by signal or 0 ok
347: */
1.2 misho 348: int
1.1 misho 349: e_usleep(u_int usec)
350: {
351: struct timeval tv = { (time_t) (usec / 1000000), (long) (usec % 1000000) };
352:
353: return select(0, NULL, NULL, NULL, &tv);
354: }
1.3 misho 355:
356: /*
357: * e_innet() - Test address match in network
358: *
359: * @net = network
360: * @addr = address
361: * return: -1 error, 0 match or 1 not match
362: */
363: int
364: e_innet(netaddr_t * __restrict net, inaddr_t * __restrict addr)
365: {
366: register int i;
367: int ret = 0;
368:
369: if (!net || !addr)
370: return -1;
371:
372: switch (net->addr.sa.sa_family) {
373: case AF_INET:
374: for (i = 0; i < sizeof(struct in_addr); i++) {
375: ret = ((caddr_t) &net->addr.sin.sin_addr.s_addr)[i] &
376: net->mask.in.s4_addr[i];
377: ret -= addr->in.s4_addr[i] & net->mask.in.s4_addr[i];
378: if (ret)
379: break;
380: }
381: break;
382: case AF_INET6:
383: for (i = 0; i < sizeof(struct in6_addr); i++) {
384: ret = net->addr.sin6.sin6_addr.s6_addr[i] &
385: net->mask.in6.s6_addr[i];
386: ret -= addr->in6.s6_addr[i] & net->mask.in6.s6_addr[i];
387: if (ret)
388: break;
389: }
390: break;
391: default:
392: return -1;
393: }
394:
395: return !!ret;
396: }
1.4 misho 397:
398: /*
399: * e_getnet() - Get network from string
400: *
401: * @net = Network string (format: <net[/cidr]>)
402: * return: NULL error or !=NULL network should be e_free()
403: */
404: netaddr_t *
405: e_getnet(const char *net)
406: {
407: netaddr_t *n;
408: char *str, *wrk;
409: struct hostent *host;
410:
411: n = e_malloc(sizeof(netaddr_t));
412: if (!n) {
413: LOGERR;
414: return NULL;
415: } else
416: memset(n, 0, sizeof(netaddr_t));
417: str = e_strdup(net);
418: if (!str) {
419: LOGERR;
420: e_free(n);
421: return NULL;
422: }
423: wrk = strchr(str, '/');
424: if (wrk)
425: *wrk++ = 0;
426:
427: host = gethostbyname2(str, strchr(str, ':') ? AF_INET6 : AF_INET);
428: if (!host) {
429: elwix_SetErr(EINVAL, "Resolver #%d - %s", h_errno, hstrerror(h_errno));
430: e_free(str);
431: e_free(n);
432: return NULL;
433: }
434: switch (host->h_addrtype) {
435: case AF_INET:
436: n->addr.sin.sin_len = sizeof(struct sockaddr_in);
437: n->addr.sin.sin_family = host->h_addrtype;
438: memcpy(&n->addr.sin.sin_addr, host->h_addr, sizeof n->addr.sin.sin_addr);
439: if (wrk)
440: n->mask.in.s_addr = E_CIDRMASK(strtol(wrk, NULL, 10));
441: else
442: n->mask.in.s_addr = 0xFFFFFFFF;
443: break;
444: case AF_INET6:
445: n->addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
446: n->addr.sin6.sin6_family = host->h_addrtype;
447: memcpy(&n->addr.sin6.sin6_addr, host->h_addr, sizeof n->addr.sin6.sin6_addr);
448: /* TODO: should support ipv6 mask */
449: break;
450: default:
451: elwix_SetErr(EINVAL, "Unsupported family #%d", host->h_addrtype);
452: e_free(str);
453: e_free(n);
454: return NULL;
455: }
456:
457: e_free(str);
458: return n;
459: }
1.7 misho 460:
461: /*
462: * e_ether_addr() - Get or set ethernet address from interface name
463: *
464: * @ifname = interface name
465: * @addr = if addr is !=NULL then set this for new address
1.10.10.2 misho 466: * return: NULL error or !=NULL get ethernet address should be e_free()
1.7 misho 467: */
468: ether_addr_t *
469: e_ether_addr(const char *ifname, ether_addr_t * __restrict addr)
470: {
471: ether_addr_t *a = NULL;
472: struct ifaddrs *p, *ifa = NULL;
473:
474: if (!ifname)
475: return NULL;
476:
477: a = e_malloc(sizeof(ether_addr_t));
478: if (!a)
479: return NULL;
480: else
481: memset(a, 0, sizeof(ether_addr_t));
482:
483: getifaddrs(&ifa);
484: for (p = ifa; p && p->ifa_name; p++)
485: if (p->ifa_name && !strcmp(p->ifa_name, ifname) && p->ifa_addr &&
486: p->ifa_addr->sa_family == AF_LINK) {
487: memcpy(a, LLADDR((struct sockaddr_dl*) p->ifa_addr), sizeof(ether_addr_t));
488: break;
489: }
490: freeifaddrs(ifa);
491:
492: return a;
493: }
1.10.10.1 misho 494:
495: /*
496: * e_get1stiface() - Get first interface of host
497: *
498: * @szIface = interface string buffer
499: * @iflen = size of interface buffer
500: * return: -1 error or 0 ok
501: */
502: int
503: e_get1stiface(char *szIface, int iflen)
504: {
505: struct ifaddrs *ifa;
506:
507: if (!szIface || !iflen)
508: return -1;
509:
510: getifaddrs(&ifa);
511: strlcpy(szIface, ifa->ifa_name, iflen);
512: freeifaddrs(ifa);
513: return 0;
514: }
1.10.10.3 misho 515:
516: /*
517: * e_getifacebyname() - Get interface and make network structure
518: *
519: * @psIface = Interface, if =NULL first interface
520: * @addr = Network address structure
521: * return: NULL error or !=NULL network structure
522: */
523: sockaddr_t *
524: e_getifacebyname(const char *psIface, sockaddr_t * __restrict addr)
525: {
526: char szIface[64] = { [0 ... 63] = 0 };
527: struct ifaddrs *p, *ifa = NULL;
528:
529: if (!addr)
530: return NULL;
531:
532: memset(addr, 0, sizeof(sockaddr_t));
533: getifaddrs(&ifa);
534: strlcpy(szIface, psIface ? psIface : ifa->ifa_name, sizeof szIface);
535: for (p = ifa; p && p->ifa_name; p++)
536: if (p->ifa_name && !strcmp(p->ifa_name, szIface) && p->ifa_addr &&
537: p->ifa_addr->sa_family == AF_LINK) {
538: memcpy(&addr->sdl, p->ifa_addr, sizeof(struct sockaddr_dl));
539: break;
540: }
541: freeifaddrs(ifa);
542:
543: return addr;
544: }
1.10.10.4 misho 545:
546: /*
547: * e_getlinkbyname() - Get host ethernet address and make network structure
548: *
549: * @psHost = Host ethernet address
550: * @addr = Network address structure
551: * return: NULL error or !=NULL network structure
552: */
553: sockaddr_t *
554: e_getlinkbyname(const char *psHost, sockaddr_t * __restrict addr)
555: {
1.10.10.6 misho 556: ait_val_t v;
557: sockaddr_t *a = addr;
558:
559: if (!psHost || !addr)
1.10.10.4 misho 560: return NULL;
561: else
562: memset(addr, 0, sizeof(sockaddr_t));
563:
1.10.10.6 misho 564: AIT_INIT_VAL2(&v, string);
565: if (!strchr(psHost, '.'))
566: AIT_SET_STR(&v, ":");
567: AIT_SET_STRCAT(&v, psHost);
568:
1.10.10.4 misho 569: addr->sdl.sdl_len = sizeof(struct sockaddr_dl);
1.10.10.6 misho 570: if (e_link_addr(AIT_GET_STR(&v), &addr->sdl))
571: a = NULL;
1.10.10.4 misho 572:
1.10.10.6 misho 573: AIT_FREE_VAL(&v);
574: return a;
1.10.10.4 misho 575: }
1.10.10.7 misho 576:
577: /*
578: * e_getlinkbyether() - Get ethernet address and make network structure
579: *
580: * @mac = Ethernet address
581: * @idx = Interface index
582: * @type = Interface type
583: * @iface = Interface name
584: * @addr = Network address structure
585: * return: NULL error or !=NULL network structure
586: */
587: sockaddr_t *
588: e_getlinkbyether(const ether_addr_t * __restrict mac, u_short idx, u_char type,
589: const char *iface, sockaddr_t * __restrict addr)
590: {
591: sockaddr_t *a = addr;
592:
593: if (!addr)
594: return NULL;
595: else
596: memset(addr, 0, sizeof(sockaddr_t));
597:
598: addr->sdl.sdl_len = sizeof(struct sockaddr_dl);
599: addr->sdl.sdl_family = AF_LINK;
600: addr->sdl.sdl_index = idx;
601: addr->sdl.sdl_type = type;
602: if (iface && *iface) {
603: addr->sdl.sdl_nlen = strlen(iface);
604: memcpy(addr->sdl.sdl_data, iface, addr->sdl.sdl_nlen);
605: }
606: addr->sdl.sdl_alen = sizeof(ether_addr_t);
607: memcpy(LLADDR(&addr->sdl), mac, addr->sdl.sdl_alen);
608:
609: return a;
610: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>