1 /*
2 * net.c
3 * (C)1999-2011 by Marc Huber <Marc.Huber@web.de>
4 * All rights reserved.
5 *
6 * $Id: net.c,v 1.42 2016/06/05 12:19:16 marc Exp marc $
7 *
8 */
9
10 #include "misc/sysconf.h"
11 #include <arpa/inet.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #include <netinet/in.h>
16 #include <netdb.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <pwd.h>
20 #include <grp.h>
21 #include <sys/stat.h>
22 #include "misc/net.h"
23
24 static const char rcsid[] __attribute__ ((used)) = "$Id: net.c,v 1.42 2016/06/05 12:19:16 marc Exp marc $";
25
su_get_port(sockaddr_union * sa)26 uint16_t su_get_port(sockaddr_union * sa)
27 {
28 switch (sa->sa.sa_family) {
29 #ifdef AF_INET
30 case AF_INET:
31 return ntohs(sa->sin.sin_port);
32 #endif /* AF_INET */
33 #ifdef AF_INET6
34 case AF_INET6:
35 return ntohs(sa->sin6.sin6_port);
36 #endif /* AF_INET6 */
37 }
38 return 0;
39 }
40
su_set_port(sockaddr_union * sa,uint16_t port)41 int su_set_port(sockaddr_union * sa, uint16_t port)
42 {
43 switch (sa->sa.sa_family) {
44 #ifdef AF_INET
45 case AF_INET:
46 sa->sin.sin_port = htons(port);
47 return 0;
48 #endif /* AF_INET */
49 #ifdef AF_INET6
50 case AF_INET6:
51 sa->sin6.sin6_port = htons(port);
52 return 0;
53 #endif /* AF_INET6 */
54 }
55 return -1;
56 }
57
su_convert(sockaddr_union * sa,u_int af)58 int su_convert(sockaddr_union * sa, u_int af)
59 {
60 if (sa->sa.sa_family == af)
61 return 0;
62
63 #if defined(AF_INET) && defined(AF_INET6)
64 if (sa->sa.sa_family == AF_INET && af == AF_INET6) {
65 sockaddr_union su;
66 su = *sa;
67 memset(sa, 0, sizeof(sockaddr_union));
68 sa->sin6.sin6_port = su.sin.sin_port;
69 sa->sa.sa_family = AF_INET6;
70 if (!su_copy_addr(sa, &su))
71 return 0;
72 *sa = su;
73 return -1;
74 }
75
76 if (sa->sa.sa_family == AF_INET6 && af == AF_INET) {
77 if (IN6_IS_ADDR_V4MAPPED(&sa->sin6.sin6_addr)) {
78 sockaddr_union su;
79 su = *sa;
80 memset(sa, 0, sizeof(sockaddr_union));
81 sa->sin.sin_port = su.sin6.sin6_port;
82 sa->sa.sa_family = AF_INET;
83 if (!su_copy_addr(sa, &su))
84 return 0;
85 *sa = su;
86 }
87 return -1;
88 }
89 #endif
90
91 return -1;
92 }
93
su_equal_addr(sockaddr_union * dst,sockaddr_union * src)94 int su_equal_addr(sockaddr_union * dst, sockaddr_union * src)
95 {
96 if (dst->sa.sa_family == src->sa.sa_family) {
97 switch (dst->sa.sa_family) {
98 #ifdef AF_UNIX
99 case AF_UNIX:
100 return !strcmp(dst->sun.sun_path, src->sun.sun_path);
101 #endif /* AF_UNIX */
102 #ifdef AF_INET
103 case AF_INET:
104 return (dst->sin.sin_addr.s_addr == src->sin.sin_addr.s_addr);
105 #endif /* AF_INET */
106 #ifdef AF_INET6
107 case AF_INET6:
108 return IN6_ARE_ADDR_EQUAL(&dst->sin6.sin6_addr, &src->sin6.sin6_addr);
109 #endif /* AF_INET6 */
110 }
111 }
112 #if defined(AF_INET) && defined(AF_INET6)
113 if (dst->sa.sa_family == AF_INET && src->sa.sa_family == AF_INET6)
114 return (IN6_IS_ADDR_V4MAPPED(&src->sin6.sin6_addr) && dst->sin.sin_addr.s_addr == src->sin6.sin6_addr.s6_addr32[3]);
115
116 if (dst->sa.sa_family == AF_INET6 && src->sa.sa_family == AF_INET)
117 return (IN6_IS_ADDR_V4MAPPED(&dst->sin6.sin6_addr) && dst->sin6.sin6_addr.s6_addr32[3] == src->sin.sin_addr.s_addr);
118 #endif /* defined(AF_INET) && defined(AF_INET6) */
119
120 return 0;
121 }
122
su_equal(sockaddr_union * dst,sockaddr_union * src)123 int su_equal(sockaddr_union * dst, sockaddr_union * src)
124 {
125 return (su_equal_addr(dst, src)
126 && su_get_port(dst) == su_get_port(src));
127 }
128
su_cmp_addr(sockaddr_union * dst,sockaddr_union * src)129 int su_cmp_addr(sockaddr_union * dst, sockaddr_union * src)
130 {
131 if (dst->sa.sa_family == src->sa.sa_family) {
132 switch (dst->sa.sa_family) {
133 #ifdef AF_UNIX
134 case AF_UNIX:
135 return strcmp(dst->sun.sun_path, src->sun.sun_path);
136 #endif /* AF_UNIX */
137 #ifdef AF_INET
138 case AF_INET:
139 if (dst->sin.sin_addr.s_addr < src->sin.sin_addr.s_addr)
140 return -1;
141 if (dst->sin.sin_addr.s_addr > src->sin.sin_addr.s_addr)
142 return +1;
143 return 0;
144 #endif /* AF_INET */
145 #ifdef AF_INET6
146 case AF_INET6:
147 return memcmp(&dst->sin6.sin6_addr, &src->sin6.sin6_addr, (size_t) 16);
148 #endif /* AF_INET6 */
149 }
150 }
151 #if defined(AF_INET) && defined(AF_INET6)
152 if (dst->sa.sa_family == AF_INET && src->sa.sa_family == AF_INET6) {
153 if (!IN6_IS_ADDR_V4MAPPED(&src->sin6.sin6_addr))
154 return -1;
155 if (dst->sin.sin_addr.s_addr < src->sin6.sin6_addr.s6_addr32[3])
156 return -1;
157 if (dst->sin.sin_addr.s_addr > src->sin6.sin6_addr.s6_addr32[3])
158 return +1;
159 return 0;
160 }
161
162 if (dst->sa.sa_family == AF_INET6 && src->sa.sa_family == AF_INET) {
163 if (!IN6_IS_ADDR_V4MAPPED(&dst->sin6.sin6_addr))
164 return -1;
165 if (dst->sin6.sin6_addr.s6_addr32[3] < src->sin.sin_addr.s_addr)
166 return -1;
167 if (dst->sin6.sin6_addr.s6_addr32[3] > src->sin.sin_addr.s_addr)
168 return +1;
169 return 0;
170 }
171 #endif /* defined(AF_INET) && defined(AF_INET6) */
172 return -1;
173 }
174
su_cmp(sockaddr_union * dst,sockaddr_union * src)175 int su_cmp(sockaddr_union * dst, sockaddr_union * src)
176 {
177 int r = su_cmp_addr(dst, src);
178 if (r)
179 return r;
180 if (su_get_port(dst) < su_get_port(src))
181 return -1;
182 if (su_get_port(dst) > su_get_port(src))
183 return +1;
184 return 0;
185 }
186
su_copy_addr(sockaddr_union * dst,sockaddr_union * src)187 int su_copy_addr(sockaddr_union * dst, sockaddr_union * src)
188 {
189 if (dst->sa.sa_family == src->sa.sa_family)
190 switch (dst->sa.sa_family) {
191 #ifdef AF_UNIX
192 case AF_UNIX:
193 strcpy(dst->sun.sun_path, src->sun.sun_path);
194 #ifdef WITH_SUN_LEN
195 dst->sun.sun_len = src->sun.sun_len;
196 #endif /* WITH_SUN_LEN */
197 return 0;
198 #endif /* AF_UNIX */
199 #ifdef AF_INET
200 case AF_INET:
201 dst->sin.sin_addr.s_addr = src->sin.sin_addr.s_addr;
202 return 0;
203 #endif /* AF_INET */
204 #ifdef AF_INET6
205 case AF_INET6:
206 dst->sin6.sin6_addr.s6_addr32[0] = src->sin6.sin6_addr.s6_addr32[0];
207 dst->sin6.sin6_addr.s6_addr32[1] = src->sin6.sin6_addr.s6_addr32[1];
208 dst->sin6.sin6_addr.s6_addr32[2] = src->sin6.sin6_addr.s6_addr32[2];
209 dst->sin6.sin6_addr.s6_addr32[3] = src->sin6.sin6_addr.s6_addr32[3];
210 return 0;
211 #endif /* AF_INET6 */
212 }
213 #if defined(AF_INET) && defined(AF_INET6)
214 if (dst->sa.sa_family == AF_INET && src->sa.sa_family == AF_INET6) {
215 if (!IN6_IS_ADDR_V4MAPPED(&src->sin6.sin6_addr))
216 return -1;
217
218 dst->sin.sin_addr.s_addr = src->sin6.sin6_addr.s6_addr32[3];
219 return 0;
220 }
221
222 if (dst->sa.sa_family == AF_INET6 && src->sa.sa_family == AF_INET) {
223 dst->sin6.sin6_addr.s6_addr32[0] = dst->sin6.sin6_addr.s6_addr32[1] = 0;
224 dst->sin6.sin6_addr.s6_addr32[2] = htonl(0xFFFF);
225 dst->sin6.sin6_addr.s6_addr32[3] = src->sin.sin_addr.s_addr;
226 return 0;
227 }
228 #endif /* defined(AF_INET) && defined(AF_INET6) */
229
230 return -1;
231 }
232
service_to_port(uint16_t * p,char * service,int proto)233 int service_to_port(uint16_t * p, char *service, int proto)
234 {
235 int i;
236 if (1 != sscanf(service, "%d", &i)) {
237 struct servent *se;
238 if ((se = getservbyname(service, proto == SOCK_STREAM ? "tcp" : "udp")))
239 *p = ntohs(se->s_port);
240 return 0;
241 }
242 if (i & ~0xffff)
243 return -1;
244 *p = (uint16_t) i;
245 return 0;
246 }
247
have_inet6()248 int have_inet6()
249 {
250 static int result = 0;
251 #ifdef AF_INET6
252 static int initialized = 0;
253 if (!initialized) {
254 int so = socket(AF_INET6, SOCK_STREAM, 0);
255 if (so > -1) {
256 close(so);
257 result = -1;
258 }
259 initialized = -1;
260 }
261 #endif /* AF_INET6 */
262 return result;
263 }
264
inet_wildcard()265 char *inet_wildcard()
266 {
267 static char *wildcard;
268 if (!wildcard)
269 wildcard = have_inet6()? "::" : "0.0.0.0";
270 return wildcard;
271 }
272
inet_any()273 char *inet_any()
274 {
275 static char *any;
276 if (!any)
277 any = have_inet6()? "::/0" : "0.0.0.0/0";
278 return any;
279 }
280
su_len(sockaddr_union * sa)281 socklen_t su_len(sockaddr_union * sa)
282 {
283 switch (sa->sa.sa_family) {
284 #ifdef AF_UNIX
285 case AF_UNIX:
286 return (socklen_t) sizeof(struct sockaddr_un);
287 #endif /* AF_UNIX */
288 #ifdef AF_INET
289 case AF_INET:
290 return (socklen_t) sizeof(struct sockaddr_in);
291 #endif /* AF_INET */
292 #ifdef AF_INET6
293 case AF_INET6:
294 return (socklen_t) sizeof(struct sockaddr_in6);
295 #endif /* AF_INET6 */
296 }
297 return (socklen_t) sizeof(struct sockaddr);
298 }
299
su_socket(int domain,int type,int protocol)300 int su_socket(int domain, int type, int protocol)
301 {
302 int s = socket(domain, type, protocol);
303 if (s > -1) {
304 fcntl(s, F_SETFD, fcntl(s, F_GETFD, 0) | FD_CLOEXEC);
305 fcntl(s, F_SETFL, O_NONBLOCK);
306 }
307 return s;
308 }
309
su_bind(int s,sockaddr_union * sa)310 int su_bind(int s, sockaddr_union * sa)
311 {
312 int one = 1;
313
314 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &one, (socklen_t) sizeof(one));
315 setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) &one, (socklen_t) sizeof(one));
316 #if defined(IPPROTO_IPV6) && defined(IPV6_BINDV6ONLY)
317 one = 0;
318 setsockopt(s, IPPROTO_IPV6, IPV6_BINDV6ONLY, (char *) &one, (socklen_t) sizeof(one));
319 #endif
320
321 return bind(s, &sa->sa, su_len(sa));
322 }
323
324
su_ntop(sockaddr_union * sa,char * dst,size_t cnt)325 char *su_ntop(sockaddr_union * sa, char *dst, size_t cnt)
326 {
327 switch (sa->sa.sa_family) {
328 #ifdef AF_UNIX
329 case AF_UNIX:
330 if (strlen(sa->sun.sun_path) >= (size_t)-- cnt)
331 return NULL;
332 strcpy(dst, sa->sun.sun_path);
333 return dst;
334 #endif /* AF_UNIX */
335 #ifdef AF_INET
336 case AF_INET:
337 {
338 char *a;
339 a = inet_ntoa(sa->sin.sin_addr);
340 if (strlen(a) >= (size_t)-- cnt)
341 return NULL;
342 strcpy(dst, a);
343 return dst;
344 }
345 #endif /* AF_INET */
346 #ifdef AF_INET6
347 case AF_INET6:
348 return (char *) inet_ntop(AF_INET6, &sa->sin6.sin6_addr, dst, (socklen_t) cnt);
349 #endif /* AF_INET6 */
350 }
351 return NULL;
352 }
353
su_pton_p(sockaddr_union * su,char * src,uint16_t port)354 int su_pton_p(sockaddr_union * su, char *src, uint16_t port)
355 {
356 size_t l = strlen(src);
357 char *s = alloca(l + 1);
358 strncpy(s, src, l + 1);
359 char *t = s;
360 if (*s == '[') {
361 s++, t++, l--;
362 while (*t && *t != ']')
363 t++, l--;
364 if (*t) {
365 *t++ = 0;
366 if (*t == ':') {
367 int u = atoi(++t);
368 if (u > -1)
369 port = u;
370 }
371 }
372 } else if (strchr(s, '.')) {
373 t = strchr(s, ':');
374 if (t) {
375 *t++ = 0;
376 int u = atoi(t);
377 if (u > -1)
378 port = u;
379 }
380 }
381 if (su_pton(su, s))
382 return -1;
383 su_set_port(su, port);
384 return 0;
385 }
386
su_pton(sockaddr_union * su,char * src)387 int su_pton(sockaddr_union * su, char *src)
388 {
389 struct hints {
390 int family;
391 size_t len;
392 char *prefix;
393 };
394
395 struct hints hints[] = {
396 #ifdef AF_UNIX
397 {AF_UNIX, 5, "unix:",},
398 #endif /* AF_UNIX */
399 #ifdef AF_INET
400 {AF_INET, 5, "inet:",},
401 #endif /* AF_INET */
402 #ifdef AF_INET6
403 {AF_INET6, 6, "inet6:",},
404 #endif /* AF_INET6 */
405 {AF_UNSPEC, 0, NULL,}
406 };
407
408 struct hints *h = hints;
409
410 while (h->prefix && strncasecmp(src, h->prefix, h->len))
411 h++;
412
413 src += h->len;
414
415 memset(su, 0, sizeof(sockaddr_union));
416
417 if (!src) {
418 #ifdef AF_INET6
419 su->sa.sa_family = AF_INET6;
420 #else /* AF_INET6 */
421 su->sa.sa_family = AF_INET;
422 #endif /* AF_INET6 */
423 return 0;
424 }
425 #ifdef AF_UNIX
426 if (h->family == AF_UNIX || (h->family == AF_UNSPEC && *src == '/')) {
427 if (strlen(src) >= sizeof(su->sun.sun_path))
428 return -1;
429 su->sa.sa_family = AF_UNIX;
430 strcpy(su->sun.sun_path, src);
431 #ifdef WITH_SUN_LEN
432 su->sun.sun_len = strlen(su->sun.sun_path) + 1;
433 #endif /* WITH_SUN_LEN */
434 return 0;
435 }
436 #endif /* AF_UNIX */
437
438 #ifdef AF_INET6
439 if (h->family == AF_INET6 || (h->family == AF_UNSPEC && strchr(src, ':'))) {
440 su->sa.sa_family = AF_INET6;
441 if (1 == inet_pton(AF_INET6, src, &su->sin6.sin6_addr))
442 return 0;
443 }
444 #endif /* AF_INET6 */
445
446 #ifdef AF_INET
447 su->sa.sa_family = AF_INET;
448 if (INADDR_NONE != (su->sin.sin_addr.s_addr = inet_addr(src)))
449 return 0;
450 #endif /* AF_INET */
451
452 return -1;
453 }
454
su_addrinfo(char * address,char * port,int protocol,int family,int count,void * data,int (* func)(sockaddr_union *,void *))455 int su_addrinfo(char *address, char *port, int protocol, int family, int count, void *data, int (*func) (sockaddr_union *, void *))
456 {
457 sockaddr_union su;
458 uint16_t p = 0;
459 #ifdef AF_INET6
460 struct addrinfo *res, hints;
461 #else /* AF_INET6 */
462 #ifdef AF_INET
463 struct hostent *he;
464 #endif /* AF_INET */
465 #endif /* AF_INET6 */
466 memset(&su, 0, sizeof(su));
467
468 if (port && (service_to_port(&p, port, protocol) < 0))
469 return -1;
470
471 if (!address)
472 address = inet_wildcard();
473
474 if (!su_pton(&su, address)) {
475 su_set_port(&su, p);
476 func(&su, data);
477 return 0;
478 }
479 #ifdef AF_INET6
480 memset(&hints, 0, sizeof(hints));
481 hints.ai_flags = AI_PASSIVE;
482 hints.ai_protocol = protocol;
483 hints.ai_family = family;
484
485 if (!getaddrinfo(address, NULL, &hints, &res)) {
486 int i;
487 struct addrinfo *r = res;
488 for (i = 0; r && (!count || count > i); r = r->ai_next, i++) {
489 su_set_port((sockaddr_union *) r->ai_addr, p);
490 if (!func((sockaddr_union *) r->ai_addr, data))
491 break;
492 }
493 freeaddrinfo(res);
494 return 0;
495 }
496 #else /* AF_INET6 */
497 #ifdef AF_INET
498 if (family == AF_INET && (he = gethostbyname(address))) {
499 su.sa.sa_family = AF_INET;
500 su_set_port(&su, p);
501 if (he->h_addrtype == AF_INET) {
502 int i;
503 u_int **a = (u_int **) he->h_addr_list;
504 for (i = 0; *a && (!count || count > i); a++, i++) {
505 su.sin.sin_addr.s_addr = **a;
506 if (!(func(&su, data)))
507 break;
508 }
509 return 0;
510 }
511 }
512 #endif /* AF_INET */
513 #endif /* AF_INET6 */
514 return -1;
515 }
516
su_nameinfo(sockaddr_union * su,char * host,size_t hostlen,char * serv,size_t servlen,int flags)517 int su_nameinfo(sockaddr_union * su, char *host, size_t hostlen, char *serv, size_t servlen, int flags)
518 {
519 switch (su->sa.sa_family) {
520 #ifdef AF_UNIX
521 case AF_UNIX:
522 if (serv)
523 *serv = 0;
524 if (host)
525 return (hostlen <= (size_t) snprintf(host, (size_t) hostlen, "%s", su->sun.sun_path));
526 return !serv;
527 #endif /* AF_UNIX */
528 #ifdef AF_INET
529 case AF_INET:
530 #endif /* AF_INET */
531 #ifdef AF_INET6
532 case AF_INET6:
533 return getnameinfo(&su->sa, su_len(su), host, (socklen_t) hostlen, serv, (socklen_t) servlen, flags);
534 #else /* AF_INET6 */
535 #ifdef AF_INET
536 if (serv) {
537 *serv = 0;
538 if (!(flags & NI_NUMERICSERV)) {
539 struct servent *se;
540 se = getservbyport(su_get_port(su), (flags & NI_DGRAM) ? "udp" : "tcp");
541 if (se && (size_t) servlen <= (size_t) snprintf(serv, servlen, "%s", se->s_name))
542 return -1;
543 }
544 if (!*serv && (size_t) servlen <= (size_t) snprintf(serv, servlen, "%d", su_get_port(su)))
545 return -1;
546 }
547 if (host) {
548 char *a = NULL;
549 if (!(flags & NI_NUMERICHOST)) {
550 struct hostent *he;
551 he = gethostbyaddr((char *) &(su->sin.sin_addr), sizeof(su->sin.sin_addr), AF_INET);
552 if (he)
553 a = (char *) he->h_name;
554 }
555 if (!a && !(flags & NI_NAMEREQD))
556 a = inet_ntoa(su->sin.sin_addr);
557 if (a)
558 return ((size_t) hostlen <= (size_t) snprintf(host, hostlen, "%s", a));
559 } else if (serv)
560 return 0;
561 #endif /* AF_INET */
562 #endif /* AF_INET6 */
563 }
564 return -1;
565 }
566
su_ptoh(sockaddr_union * su,struct in6_addr * a)567 int su_ptoh(sockaddr_union * su, struct in6_addr *a)
568 {
569 switch (su->sa.sa_family) {
570 #ifdef AF_INET
571 case AF_INET:
572 a->s6_addr32[0] = a->s6_addr32[1] = 0;
573 a->s6_addr32[2] = 0x0000FFFF;
574 a->s6_addr32[3] = ntohl(su->sin.sin_addr.s_addr);
575 return 0;
576 #endif /* AF_INET */
577 #ifdef AF_INET6
578 case AF_INET6:
579 v6_ntoh(a, &su->sin6.sin6_addr);
580 return 0;
581 #endif /* AF_INET6 */
582 }
583 return -1;
584 }
585
586 static uint32_t cidr2mask[] = {
587 0x00000000,
588 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
589 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
590 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
591 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
592 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
593 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
594 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
595 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff
596 };
597
v6_common_cidr(struct in6_addr * a,struct in6_addr * b,int min)598 int v6_common_cidr(struct in6_addr *a, struct in6_addr *b, int min)
599 {
600 int m;
601 for (m = 0; m < min && (v6_bitset(*a, m + 1) == v6_bitset(*b, m + 1)); m++);
602 return m;
603 }
604
v6_network(struct in6_addr * n,struct in6_addr * a,int m)605 void v6_network(struct in6_addr *n, struct in6_addr *a, int m)
606 {
607 int i;
608 for (i = 0; i < 4; i++, m -= 32)
609 n->s6_addr32[i] = a->s6_addr32[i] & cidr2mask[(m < 1) ? 0 : ((m > 32) ? 32 : m)];
610 }
611
v6_broadcast(struct in6_addr * b,struct in6_addr * a,int m)612 void v6_broadcast(struct in6_addr *b, struct in6_addr *a, int m)
613 {
614 int i;
615 for (i = 0; i < 4; i++, m -= 32)
616 b->s6_addr32[i] = a->s6_addr32[i] | ~cidr2mask[(m < 1) ? 0 : ((m > 32) ? 32 : m)];
617 }
618
v6_cmp(struct in6_addr * a,struct in6_addr * b)619 int v6_cmp(struct in6_addr *a, struct in6_addr *b)
620 {
621 int i;
622 for (i = 0; i < 4; i++) {
623 if (a->s6_addr32[i] < b->s6_addr32[i])
624 return -1;
625 if (a->s6_addr32[i] > b->s6_addr32[i])
626 return +1;
627 }
628 return 0;
629 }
630
v6_contains(struct in6_addr * n,int m,struct in6_addr * a)631 int v6_contains(struct in6_addr *n, int m, struct in6_addr *a)
632 {
633 int i;
634
635 for (i = 0; i < 4; i++, m -= 32)
636 if (n->s6_addr32[i] != (a->s6_addr32[i] & cidr2mask[(m < 1) ? 0 : ((m > 32) ? 32 : m)]))
637 return 0;
638 return -1;
639 }
640
v6_ntoh(struct in6_addr * a,struct in6_addr * b)641 void v6_ntoh(struct in6_addr *a, struct in6_addr *b)
642 {
643 int i;
644 for (i = 0; i < 4; i++)
645 a->s6_addr32[i] = ntohl(b->s6_addr32[i]);
646 }
647
v6_ptoh(struct in6_addr * a,int * cm,char * s)648 int v6_ptoh(struct in6_addr *a, int *cm, char *s)
649 {
650 char *mask, *c = alloca(strlen(s) + 1);
651 struct in6_addr m;
652 int i, cmdummy;
653
654 if (!cm)
655 cm = &cmdummy;
656
657 strcpy(c, s);
658
659 mask = strchr(c, '/');
660 if (mask)
661 *mask++ = 0;
662
663 #ifdef AF_INET6
664 if (strchr(c, ':')) {
665 if (mask) {
666 if (strchr(mask, ':')) {
667 if (1 != inet_pton(AF_INET6, c, &m))
668 return -1;
669 v6_ntoh(&m, &m);
670 for (*cm = 0; *cm < 128 && v6_bitset(m, *cm + 1); (*cm)++);
671 } else
672 *cm = atoi(mask);
673 } else
674 *cm = 128;
675
676 if (1 != inet_pton(AF_INET6, c, a))
677 return -1;
678
679 v6_ntoh(a, a);
680 return 0;
681 } else
682 #endif
683 {
684 if (mask) {
685 if (strchr(mask, '.')) {
686 in_addr_t ia = inet_addr(mask);
687 if (ia == INADDR_NONE)
688 return -1;
689 for (i = 0; i < 3; i++)
690 m.s6_addr32[i] = 0;
691 m.s6_addr32[3] = ntohl(ia);
692 for (*cm = 96; *cm < 128 && v6_bitset(m, *cm + 1); (*cm)++);
693 } else
694 *cm = atoi(mask) + 96;
695 } else
696 *cm = 128;
697
698 a->s6_addr32[0] = a->s6_addr32[1] = 0;
699 a->s6_addr32[2] = 0x0000FFFF;
700 a->s6_addr32[3] = ntohl(inet_addr(c));
701 return a->s6_addr32[3] == INADDR_NONE;
702 }
703 }
704