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