Annotation of libelwix/src/net.c, revision 1.9.6.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.9.6.2 ! misho 6: * $Id: net.c,v 1.9.6.1 2014/02/10 16:36:08 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: /*
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 */
1.9.6.2 ! misho 245: host = gethostbyname2(psHost, !strchr(psHost, ':') ? AF_INET : AF_INET6);
1.1 misho 246: if (!host) {
247: elwix_SetErr(EINVAL, "Resolver #%d - %s", h_errno, hstrerror(h_errno));
248: return NULL;
249: } else {
250: memset(addr, 0, sizeof(sockaddr_t));
251: addr->sa.sa_family = host->h_addrtype;
252: }
253: } else {
254: memset(addr, 0, sizeof(sockaddr_t));
255: addr->sa.sa_family = AF_LOCAL;
256: }
257:
258:
259: switch (addr->sa.sa_family) {
260: case AF_INET:
261: addr->sin.sin_len = sizeof(struct sockaddr_in);
262: addr->sin.sin_family = AF_INET;
263: addr->sin.sin_port = htons(port);
264: memcpy(&addr->sin.sin_addr, host->h_addr, sizeof addr->sin.sin_addr);
265: return addr;
266: case AF_INET6:
267: addr->sin6.sin6_len = sizeof(struct sockaddr_in6);
268: addr->sin6.sin6_family = AF_INET6;
269: addr->sin6.sin6_port = htons(port);
270: memcpy(&addr->sin6.sin6_addr, host->h_addr, sizeof addr->sin6.sin6_addr);
271: return addr;
272: case AF_LOCAL:
273: addr->sun.sun_len = sizeof(struct sockaddr_un);
274: addr->sun.sun_family = AF_LOCAL;
275: memset(addr->sun.sun_path, 0, sizeof addr->sun.sun_path);
276: snprintf(addr->sun.sun_path, sizeof addr->sun.sun_path, "%s-%hu", psHost, port);
277: return addr;
278: default:
279: elwix_SetErr(EPROTONOSUPPORT, "Unsuported address family %d", addr->sa.sa_family);
280: break;
281: }
282:
283: return NULL;
284: }
285:
286: /*
287: * e_addrcmp() - Compare network addresses
288: *
289: * @a = 1st address
290: * @b = 2nd address
291: * @p = compare and ports, if family is AF_INET or AF_INET6
292: * return: 0 is equal or !=0 is different
293: */
294: int
295: e_addrcmp(sockaddr_t * __restrict a, sockaddr_t * __restrict b, int p)
296: {
297: if (a && b && a->sa.sa_family == b->sa.sa_family)
298: switch (a->sa.sa_family) {
299: case AF_LOCAL:
300: return strcmp(a->sun.sun_path, b->sun.sun_path);
301: case AF_INET:
302: if (p && (a->sin.sin_port - b->sin.sin_port))
303: return (int) !!(a->sin.sin_port - b->sin.sin_port);
304: else
305: return memcmp(&a->sin.sin_addr, &b->sin.sin_addr,
306: sizeof a->sin.sin_addr);
307: case AF_INET6:
308: if (p && (a->sin6.sin6_port - b->sin6.sin6_port))
309: return (int) !!(a->sin6.sin6_port - b->sin6.sin6_port);
310: else
311: return memcmp(&a->sin6.sin6_addr, &b->sin6.sin6_addr,
312: sizeof a->sin6.sin6_addr);
313: case AF_LINK:
314: return memcmp(&a->sdl.sdl_data, &b->sdl.sdl_data,
315: sizeof a->sdl.sdl_data);
316: }
317:
318: return (int) !!(a - b);
319: }
320:
321: /*
322: * e_usleep() - usleep() replacement for ELWIX
323: *
324: * @usec = microseconds for sleep
325: * return: -1 interrupted by signal or 0 ok
326: */
1.2 misho 327: int
1.1 misho 328: e_usleep(u_int usec)
329: {
330: struct timeval tv = { (time_t) (usec / 1000000), (long) (usec % 1000000) };
331:
332: return select(0, NULL, NULL, NULL, &tv);
333: }
1.3 misho 334:
335: /*
336: * e_innet() - Test address match in network
337: *
338: * @net = network
339: * @addr = address
340: * return: -1 error, 0 match or 1 not match
341: */
342: int
343: e_innet(netaddr_t * __restrict net, inaddr_t * __restrict addr)
344: {
345: register int i;
346: int ret = 0;
347:
348: if (!net || !addr)
349: return -1;
350:
351: switch (net->addr.sa.sa_family) {
352: case AF_INET:
353: for (i = 0; i < sizeof(struct in_addr); i++) {
354: ret = ((caddr_t) &net->addr.sin.sin_addr.s_addr)[i] &
355: net->mask.in.s4_addr[i];
356: ret -= addr->in.s4_addr[i] & net->mask.in.s4_addr[i];
357: if (ret)
358: break;
359: }
360: break;
361: case AF_INET6:
362: for (i = 0; i < sizeof(struct in6_addr); i++) {
363: ret = net->addr.sin6.sin6_addr.s6_addr[i] &
364: net->mask.in6.s6_addr[i];
365: ret -= addr->in6.s6_addr[i] & net->mask.in6.s6_addr[i];
366: if (ret)
367: break;
368: }
369: break;
370: default:
371: return -1;
372: }
373:
374: return !!ret;
375: }
1.4 misho 376:
377: /*
378: * e_getnet() - Get network from string
379: *
380: * @net = Network string (format: <net[/cidr]>)
381: * return: NULL error or !=NULL network should be e_free()
382: */
383: netaddr_t *
384: e_getnet(const char *net)
385: {
386: netaddr_t *n;
387: char *str, *wrk;
388: struct hostent *host;
389:
390: n = e_malloc(sizeof(netaddr_t));
391: if (!n) {
392: LOGERR;
393: return NULL;
394: } else
395: memset(n, 0, sizeof(netaddr_t));
396: str = e_strdup(net);
397: if (!str) {
398: LOGERR;
399: e_free(n);
400: return NULL;
401: }
402: wrk = strchr(str, '/');
403: if (wrk)
404: *wrk++ = 0;
405:
406: host = gethostbyname2(str, strchr(str, ':') ? AF_INET6 : AF_INET);
407: if (!host) {
408: elwix_SetErr(EINVAL, "Resolver #%d - %s", h_errno, hstrerror(h_errno));
409: e_free(str);
410: e_free(n);
411: return NULL;
412: }
413: switch (host->h_addrtype) {
414: case AF_INET:
415: n->addr.sin.sin_len = sizeof(struct sockaddr_in);
416: n->addr.sin.sin_family = host->h_addrtype;
417: memcpy(&n->addr.sin.sin_addr, host->h_addr, sizeof n->addr.sin.sin_addr);
418: if (wrk)
419: n->mask.in.s_addr = E_CIDRMASK(strtol(wrk, NULL, 10));
420: else
421: n->mask.in.s_addr = 0xFFFFFFFF;
422: break;
423: case AF_INET6:
424: n->addr.sin6.sin6_len = sizeof(struct sockaddr_in6);
425: n->addr.sin6.sin6_family = host->h_addrtype;
426: memcpy(&n->addr.sin6.sin6_addr, host->h_addr, sizeof n->addr.sin6.sin6_addr);
427: /* TODO: should support ipv6 mask */
428: break;
429: default:
430: elwix_SetErr(EINVAL, "Unsupported family #%d", host->h_addrtype);
431: e_free(str);
432: e_free(n);
433: return NULL;
434: }
435:
436: e_free(str);
437: return n;
438: }
1.7 misho 439:
440: /*
441: * e_ether_addr() - Get or set ethernet address from interface name
442: *
443: * @ifname = interface name
444: * @addr = if addr is !=NULL then set this for new address
445: * return: NULL error or !=NULL get ethernet address
446: */
447: ether_addr_t *
448: e_ether_addr(const char *ifname, ether_addr_t * __restrict addr)
449: {
450: ether_addr_t *a = NULL;
451: struct ifaddrs *p, *ifa = NULL;
452:
453: if (!ifname)
454: return NULL;
455:
456: a = e_malloc(sizeof(ether_addr_t));
457: if (!a)
458: return NULL;
459: else
460: memset(a, 0, sizeof(ether_addr_t));
461:
462: getifaddrs(&ifa);
463: for (p = ifa; p && p->ifa_name; p++)
464: if (p->ifa_name && !strcmp(p->ifa_name, ifname) && p->ifa_addr &&
465: p->ifa_addr->sa_family == AF_LINK) {
466: memcpy(a, LLADDR((struct sockaddr_dl*) p->ifa_addr), sizeof(ether_addr_t));
467: break;
468: }
469: freeifaddrs(ifa);
470:
471: return a;
472: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>