Annotation of libelwix/src/net.c, revision 1.6.4.2
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.6.4.2 ! misho 6: * $Id: net.c,v 1.6.4.1 2013/07/08 01:11: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:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
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++ = ':';
79: i = *in++;
80: if (i > 0xf) {
81: out[1] = hexlist[i & 0xf];
82: i >>= 4;
83: } else
84: out[1] = hexlist[0];
85:
86: out[0] = hexlist[i];
87: out += 2;
88: }
89:
90: *out = 0;
91: return obuf;
92: }
93:
1.1 misho 94: /*
95: * e_ether_ntoa() - Convert ethernet address to string
96: *
97: * @n = ethernet address structure, like struct ether_addr
98: * @a = string
99: * @len = string length
100: * return: NULL error or !=NULL string a
101: */
1.2 misho 102: char *
1.6.4.2 ! misho 103: e_ether_ntoa(const ether_addr_t * __restrict n, char * __restrict a, int len)
1.1 misho 104: {
105: if (!n || !a)
106: return NULL;
107:
108: memset(a, 0, len);
109: if (snprintf(a, len, "%02x:%02x:%02x:%02x:%02x:%02x",
110: n->ether_addr_octet[0], n->ether_addr_octet[1],
111: n->ether_addr_octet[2], n->ether_addr_octet[3],
112: n->ether_addr_octet[4], n->ether_addr_octet[5]) < 17)
113: return NULL;
114:
115: return a;
116: }
117:
118: /*
119: * e_ether_aton() - Convert string to ethernet address
120: *
121: * @a = string
122: * @e = ethernet address structure, like struct ether_addr
123: * return: NULL error or !=NULL ethernet address structure
124: */
1.6.4.2 ! misho 125: ether_addr_t *
! 126: e_ether_aton(const char *a, ether_addr_t * __restrict e)
1.1 misho 127: {
128: int i;
129: u_int o0, o1, o2, o3, o4, o5;
130:
131: if (!a || !e)
132: return NULL;
133:
134: i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5);
135: if (i != 6)
136: return NULL;
137:
138: e->ether_addr_octet[0] = o0;
139: e->ether_addr_octet[1] = o1;
140: e->ether_addr_octet[2] = o2;
141: e->ether_addr_octet[3] = o3;
142: e->ether_addr_octet[4] = o4;
143: e->ether_addr_octet[5] = o5;
144:
145: return e;
146: }
147:
148: /*
149: * e_n2port() - Extract port from network structure
150: *
151: * @addr = Address
152: * return: 0 not supported family type or port number
153: */
1.2 misho 154: u_short
1.1 misho 155: e_n2port(sockaddr_t * __restrict addr)
156: {
157: u_short port = 0;
158:
159: if (!addr)
160: return port;
161:
162: switch (addr->sa.sa_family) {
163: case AF_INET:
164: return ntohs(addr->sin.sin_port);
165: case AF_INET6:
166: return ntohs(addr->sin6.sin6_port);
167: default:
168: break;
169: }
170:
171: return port;
172: }
173:
174: /*
175: * e_n2addr() - Extract address from network structure
176: *
177: * @addr = Address
178: * @val = Value for store string address
179: * return: NULL error or !=NULL string address from val
180: */
181: const char *
182: e_n2addr(sockaddr_t * __restrict addr, ait_val_t * __restrict val)
183: {
1.5 misho 184: char *s, str[INET6_ADDRSTRLEN] = { 0 };
1.1 misho 185: const char *ret = NULL;
186:
187: if (!addr || !val)
188: return ret;
189:
190: AIT_INIT_VAL(val);
191: switch (addr->sa.sa_family) {
192: case AF_INET:
193: if (!inet_ntop(AF_INET, &addr->sin.sin_addr, str, INET_ADDRSTRLEN)) {
194: LOGERR;
195: return ret;
196: } else
197: ret = str;
198: break;
199: case AF_INET6:
200: if (!inet_ntop(AF_INET6, &addr->sin6.sin6_addr, str, INET6_ADDRSTRLEN)) {
201: LOGERR;
202: return ret;
203: } else
204: ret = str;
205: break;
206: case AF_LOCAL:
207: ret = addr->sun.sun_path;
208: break;
1.5 misho 209: case AF_LINK:
1.6 misho 210: if (!(s = e_link_ntoa(&addr->sdl))) {
1.5 misho 211: LOGERR;
212: return ret;
213: } else
214: ret = s;
215: break;
1.1 misho 216: default:
217: elwix_SetErr(EPROTONOSUPPORT, "Unsuported address family %d",
218: addr->sa.sa_family);
219: return ret;
220: }
221:
222: AIT_SET_STR(val, ret);
223: return (const char*) AIT_GET_STR(val);
224: }
225:
226: /*
227: * e_gethostbyname() - Get host and port and make network structure
228: *
229: * @psHost = Hostname
230: * @port = Port
231: * @addr = Network address structure
232: * return: NULL error or !=NULL network structure
233: */
234: sockaddr_t *
235: e_gethostbyname(const char *psHost, u_short port, sockaddr_t * __restrict addr)
236: {
237: struct hostent *host = NULL;
238:
239: if (!psHost || !addr)
240: return NULL;
241:
242: if (*psHost != '/') {
243: /* resolver */
244: if (!addr->sa.sa_family)
245: host = gethostbyname(psHost);
246: else
247: host = gethostbyname2(psHost, addr->sa.sa_family);
248: if (!host) {
249: elwix_SetErr(EINVAL, "Resolver #%d - %s", h_errno, hstrerror(h_errno));
250: return NULL;
251: } else {
252: memset(addr, 0, sizeof(sockaddr_t));
253: addr->sa.sa_family = host->h_addrtype;
254: }
255: } else {
256: memset(addr, 0, sizeof(sockaddr_t));
257: addr->sa.sa_family = AF_LOCAL;
258: }
259:
260:
261: switch (addr->sa.sa_family) {
262: case AF_INET:
263: addr->sin.sin_len = sizeof(struct sockaddr_in);
264: addr->sin.sin_family = AF_INET;
265: addr->sin.sin_port = htons(port);
266: memcpy(&addr->sin.sin_addr, host->h_addr, sizeof addr->sin.sin_addr);
267: return addr;
268: case AF_INET6:
269: addr->sin6.sin6_len = sizeof(struct sockaddr_in6);
270: addr->sin6.sin6_family = AF_INET6;
271: addr->sin6.sin6_port = htons(port);
272: memcpy(&addr->sin6.sin6_addr, host->h_addr, sizeof addr->sin6.sin6_addr);
273: return addr;
274: case AF_LOCAL:
275: addr->sun.sun_len = sizeof(struct sockaddr_un);
276: addr->sun.sun_family = AF_LOCAL;
277: memset(addr->sun.sun_path, 0, sizeof addr->sun.sun_path);
278: snprintf(addr->sun.sun_path, sizeof addr->sun.sun_path, "%s-%hu", psHost, port);
279: return addr;
280: default:
281: elwix_SetErr(EPROTONOSUPPORT, "Unsuported address family %d", addr->sa.sa_family);
282: break;
283: }
284:
285: return NULL;
286: }
287:
288: /*
289: * e_addrcmp() - Compare network addresses
290: *
291: * @a = 1st address
292: * @b = 2nd address
293: * @p = compare and ports, if family is AF_INET or AF_INET6
294: * return: 0 is equal or !=0 is different
295: */
296: int
297: e_addrcmp(sockaddr_t * __restrict a, sockaddr_t * __restrict b, int p)
298: {
299: if (a && b && a->sa.sa_family == b->sa.sa_family)
300: switch (a->sa.sa_family) {
301: case AF_LOCAL:
302: return strcmp(a->sun.sun_path, b->sun.sun_path);
303: case AF_INET:
304: if (p && (a->sin.sin_port - b->sin.sin_port))
305: return (int) !!(a->sin.sin_port - b->sin.sin_port);
306: else
307: return memcmp(&a->sin.sin_addr, &b->sin.sin_addr,
308: sizeof a->sin.sin_addr);
309: case AF_INET6:
310: if (p && (a->sin6.sin6_port - b->sin6.sin6_port))
311: return (int) !!(a->sin6.sin6_port - b->sin6.sin6_port);
312: else
313: return memcmp(&a->sin6.sin6_addr, &b->sin6.sin6_addr,
314: sizeof a->sin6.sin6_addr);
315: case AF_LINK:
316: return memcmp(&a->sdl.sdl_data, &b->sdl.sdl_data,
317: sizeof a->sdl.sdl_data);
318: }
319:
320: return (int) !!(a - b);
321: }
322:
323: /*
324: * e_usleep() - usleep() replacement for ELWIX
325: *
326: * @usec = microseconds for sleep
327: * return: -1 interrupted by signal or 0 ok
328: */
1.2 misho 329: int
1.1 misho 330: e_usleep(u_int usec)
331: {
332: struct timeval tv = { (time_t) (usec / 1000000), (long) (usec % 1000000) };
333:
334: return select(0, NULL, NULL, NULL, &tv);
335: }
1.3 misho 336:
337: /*
338: * e_innet() - Test address match in network
339: *
340: * @net = network
341: * @addr = address
342: * return: -1 error, 0 match or 1 not match
343: */
344: int
345: e_innet(netaddr_t * __restrict net, inaddr_t * __restrict addr)
346: {
347: register int i;
348: int ret = 0;
349:
350: if (!net || !addr)
351: return -1;
352:
353: switch (net->addr.sa.sa_family) {
354: case AF_INET:
355: for (i = 0; i < sizeof(struct in_addr); i++) {
356: ret = ((caddr_t) &net->addr.sin.sin_addr.s_addr)[i] &
357: net->mask.in.s4_addr[i];
358: ret -= addr->in.s4_addr[i] & net->mask.in.s4_addr[i];
359: if (ret)
360: break;
361: }
362: break;
363: case AF_INET6:
364: for (i = 0; i < sizeof(struct in6_addr); i++) {
365: ret = net->addr.sin6.sin6_addr.s6_addr[i] &
366: net->mask.in6.s6_addr[i];
367: ret -= addr->in6.s6_addr[i] & net->mask.in6.s6_addr[i];
368: if (ret)
369: break;
370: }
371: break;
372: default:
373: return -1;
374: }
375:
376: return !!ret;
377: }
1.4 misho 378:
379: /*
380: * e_getnet() - Get network from string
381: *
382: * @net = Network string (format: <net[/cidr]>)
383: * return: NULL error or !=NULL network should be e_free()
384: */
385: netaddr_t *
386: e_getnet(const char *net)
387: {
388: netaddr_t *n;
389: char *str, *wrk;
390: struct hostent *host;
391:
392: n = e_malloc(sizeof(netaddr_t));
393: if (!n) {
394: LOGERR;
395: return NULL;
396: } else
397: memset(n, 0, sizeof(netaddr_t));
398: str = e_strdup(net);
399: if (!str) {
400: LOGERR;
401: e_free(n);
402: return NULL;
403: }
404: wrk = strchr(str, '/');
405: if (wrk)
406: *wrk++ = 0;
407:
408: host = gethostbyname2(str, strchr(str, ':') ? AF_INET6 : AF_INET);
409: if (!host) {
410: elwix_SetErr(EINVAL, "Resolver #%d - %s", h_errno, hstrerror(h_errno));
411: e_free(str);
412: e_free(n);
413: return NULL;
414: }
415: switch (host->h_addrtype) {
416: case AF_INET:
417: n->addr.sin.sin_len = sizeof(struct sockaddr_in);
418: n->addr.sin.sin_family = host->h_addrtype;
419: memcpy(&n->addr.sin.sin_addr, host->h_addr, sizeof n->addr.sin.sin_addr);
420: if (wrk)
421: n->mask.in.s_addr = E_CIDRMASK(strtol(wrk, NULL, 10));
422: else
423: n->mask.in.s_addr = 0xFFFFFFFF;
424: break;
425: case AF_INET6:
426: n->addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
427: n->addr.sin6.sin6_family = host->h_addrtype;
428: memcpy(&n->addr.sin6.sin6_addr, host->h_addr, sizeof n->addr.sin6.sin6_addr);
429: /* TODO: should support ipv6 mask */
430: break;
431: default:
432: elwix_SetErr(EINVAL, "Unsupported family #%d", host->h_addrtype);
433: e_free(str);
434: e_free(n);
435: return NULL;
436: }
437:
438: e_free(str);
439: return n;
440: }
1.6.4.1 misho 441:
442: /*
443: * e_ether_addr() - Get or set ethernet address from interface name
444: *
445: * @ifname = interface name
446: * @addr = if addr is !=NULL then set this for new address
447: * return: NULL error or !=NULL get ethernet address
448: */
449: ether_addr_t *
450: e_ether_addr(const char *ifname, ether_addr_t * __restrict addr)
451: {
452: ether_addr_t *a = NULL;
453: struct ifaddrs *p, *ifa = NULL;
454:
455: if (!ifname)
456: return NULL;
457:
458: a = e_malloc(sizeof(ether_addr_t));
459: if (!a)
460: return NULL;
461: else
462: memset(a, 0, sizeof(ether_addr_t));
463:
464: getifaddrs(&ifa);
1.6.4.2 ! misho 465: for (p = ifa; p && p->ifa_name; p++)
! 466: if (p->ifa_name && !strcmp(p->ifa_name, ifname) && p->ifa_addr &&
1.6.4.1 misho 467: p->ifa_addr->sa_family == AF_LINK) {
468: memcpy(a, LLADDR((struct sockaddr_dl*) p->ifa_addr), sizeof(ether_addr_t));
469: break;
470: }
471: freeifaddrs(ifa);
472:
473: return a;
474: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>