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