xref: /freebsd/usr.sbin/ppp/ncpaddr.c (revision d8a0fe102c0cfdfcd5b818f850eff09d8536c9bc)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #ifdef __OpenBSD__
34 #include <net/if_types.h>
35 #include <net/route.h>
36 #endif
37 #include <netinet/in.h>
38 #include <netinet/in_systm.h>
39 #include <netinet/ip.h>
40 #include <arpa/inet.h>
41 #include <sys/un.h>
42 
43 #include <netdb.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <termios.h>
48 
49 #include "log.h"
50 #include "ncpaddr.h"
51 #include "timer.h"
52 #include "fsm.h"
53 #include "defs.h"
54 #include "slcompress.h"
55 #include "iplist.h"
56 #include "throughput.h"
57 #include "mbuf.h"
58 #include "ipcp.h"
59 #include "descriptor.h"
60 #include "layer.h"
61 #include "lqr.h"
62 #include "hdlc.h"
63 #include "lcp.h"
64 #include "ccp.h"
65 #include "link.h"
66 #include "mp.h"
67 #include "ipv6cp.h"
68 #include "ncp.h"
69 
70 
71 #define ncprange_ip4addr	u.ip4.ipaddr
72 #define ncprange_ip4mask	u.ip4.mask
73 #define ncprange_ip4width	u.ip4.width
74 #define ncpaddr_ip4addr		u.ip4addr
75 #ifndef NOINET6
76 #define ncprange_ip6addr	u.ip6.ipaddr
77 #define ncprange_ip6width	u.ip6.width
78 #define ncpaddr_ip6addr		u.ip6addr
79 #endif
80 
81 #define	NCP_ASCIIBUFFERSIZE	52
82 
83 static struct in_addr
84 bits2mask4(int bits)
85 {
86   struct in_addr result;
87   u_int32_t bit = 0x80000000;
88 
89   result.s_addr = 0;
90 
91   while (bits) {
92     result.s_addr |= bit;
93     bit >>= 1;
94     bits--;
95   }
96 
97   result.s_addr = htonl(result.s_addr);
98   return result;
99 }
100 
101 static int
102 mask42bits(struct in_addr mask)
103 {
104   u_int32_t msk = ntohl(mask.s_addr);
105   u_int32_t tst;
106   int ret;
107 
108   for (ret = 32, tst = 1; tst; ret--, tst <<= 1)
109     if (msk & tst)
110       break;
111 
112   for (tst <<= 1; tst; tst <<= 1)
113     if (!(msk & tst))
114       break;
115 
116   return tst ? -1 : ret;
117 }
118 
119 #ifndef NOINET6
120 static struct in6_addr
121 bits2mask6(int bits)
122 {
123   struct in6_addr result;
124   u_int32_t bit = 0x80;
125   u_char *c = result.s6_addr;
126 
127   memset(&result, '\0', sizeof result);
128 
129   while (bits) {
130     if (bit == 0) {
131       bit = 0x80;
132       c++;
133     }
134     *c |= bit;
135     bit >>= 1;
136     bits--;
137   }
138 
139   return result;
140 }
141 
142 static int
143 mask62bits(const struct in6_addr *mask)
144 {
145   const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
146   const u_char *c, *p, *end;
147   int masklen, m;
148 
149   p = (const u_char *)mask;
150   for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++)
151     masklen += 8;
152 
153   if (p < end) {
154     for (c = masks, m = 0; c < masks + sizeof masks; c++, m++)
155       if (*c == *p) {
156         masklen += m;
157         break;
158       }
159   }
160 
161   return masklen;
162 }
163 
164 #if 0
165 static void
166 adjust_linklocal(struct sockaddr_in6 *sin6)
167 {
168     /* XXX: ?????!?!?!!!!!  This is horrible ! */
169     /*
170      * The kernel does not understand sin6_scope_id for routing at this moment.
171      * We should rather keep the embedded ID.
172      * jinmei@kame.net, 20011026
173      */
174     if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
175         IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) {
176       sin6->sin6_scope_id =
177         ntohs(*(u_short *)&sin6->sin6_addr.s6_addr[2]);
178       *(u_short *)&sin6->sin6_addr.s6_addr[2] = 0;
179     }
180 }
181 #endif
182 #endif
183 
184 void
185 ncpaddr_init(struct ncpaddr *addr)
186 {
187   addr->ncpaddr_family = AF_UNSPEC;
188 }
189 
190 int
191 ncpaddr_isset(const struct ncpaddr *addr)
192 {
193   return addr->ncpaddr_family != AF_UNSPEC;
194 }
195 
196 int
197 ncpaddr_isdefault(const struct ncpaddr *addr)
198 {
199   switch (addr->ncpaddr_family) {
200   case AF_INET:
201     if (addr->ncpaddr_ip4addr.s_addr == INADDR_ANY)
202       return 1;
203     break;
204 
205 #ifndef NOINET6
206   case AF_INET6:
207     if (IN6_IS_ADDR_UNSPECIFIED(&addr->ncpaddr_ip6addr))
208       return 1;
209     break;
210 #endif
211   }
212 
213   return 0;
214 }
215 
216 int
217 ncpaddr_equal(const struct ncpaddr *addr, const struct ncpaddr *cmp)
218 {
219   if (addr->ncpaddr_family != cmp->ncpaddr_family)
220     return 0;
221 
222   switch (addr->ncpaddr_family) {
223   case AF_INET:
224     return addr->ncpaddr_ip4addr.s_addr == cmp->ncpaddr_ip4addr.s_addr;
225 
226 #ifndef NOINET6
227   case AF_INET6:
228     return !memcmp(&addr->ncpaddr_ip6addr, &cmp->ncpaddr_ip6addr,
229                    sizeof addr->ncpaddr_ip6addr);
230 #endif
231 
232   case AF_UNSPEC:
233     return 1;
234   }
235 
236   return 0;
237 }
238 
239 void
240 ncpaddr_copy(struct ncpaddr *addr, const struct ncpaddr *from)
241 {
242   switch (from->ncpaddr_family) {
243   case AF_INET:
244     addr->ncpaddr_family = AF_INET;
245     addr->ncpaddr_ip4addr = from->ncpaddr_ip4addr;
246     break;
247 #ifndef NOINET6
248   case AF_INET6:
249     addr->ncpaddr_family = AF_INET6;
250     addr->ncpaddr_ip6addr = from->ncpaddr_ip6addr;
251     break;
252 #endif
253   default:
254     addr->ncpaddr_family = AF_UNSPEC;
255   }
256 }
257 
258 void
259 ncpaddr_setip4addr(struct ncpaddr *addr, u_int32_t ip)
260 {
261   addr->ncpaddr_family = AF_INET;
262   addr->ncpaddr_ip4addr.s_addr = ip;
263 }
264 
265 int
266 ncpaddr_getip4addr(const struct ncpaddr *addr, u_int32_t *ip)
267 {
268   if (addr->ncpaddr_family != AF_INET)
269     return 0;
270   *ip = addr->ncpaddr_ip4addr.s_addr;
271   return 1;
272 }
273 
274 void
275 ncpaddr_setip4(struct ncpaddr *addr, struct in_addr ip)
276 {
277   addr->ncpaddr_family = AF_INET;
278   addr->ncpaddr_ip4addr = ip;
279 }
280 
281 int
282 ncpaddr_getip4(const struct ncpaddr *addr, struct in_addr *ip)
283 {
284   if (addr->ncpaddr_family != AF_INET)
285     return 0;
286   *ip = addr->ncpaddr_ip4addr;
287   return 1;
288 }
289 
290 #ifndef NOINET6
291 void
292 ncpaddr_setip6(struct ncpaddr *addr, const struct in6_addr *ip6)
293 {
294   addr->ncpaddr_family = AF_INET6;
295   addr->ncpaddr_ip6addr = *ip6;
296 }
297 
298 int
299 ncpaddr_getip6(const struct ncpaddr *addr, struct in6_addr *ip6)
300 {
301   if (addr->ncpaddr_family != AF_INET6)
302     return 0;
303   *ip6 = addr->ncpaddr_ip6addr;
304   return 1;
305 }
306 #endif
307 
308 void
309 ncpaddr_getsa(const struct ncpaddr *addr, struct sockaddr_storage *host)
310 {
311   struct sockaddr_in *host4 = (struct sockaddr_in *)host;
312 #ifndef NOINET6
313   struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
314 #endif
315 
316   memset(host, '\0', sizeof(*host));
317 
318   switch (addr->ncpaddr_family) {
319   case AF_INET:
320     host4->sin_family = AF_INET;
321     host4->sin_len = sizeof(*host4);
322     host4->sin_addr = addr->ncpaddr_ip4addr;
323     break;
324 
325 #ifndef NOINET6
326   case AF_INET6:
327     host6->sin6_family = AF_INET6;
328     host6->sin6_len = sizeof(*host6);
329     host6->sin6_addr = addr->ncpaddr_ip6addr;
330     break;
331 #endif
332 
333   default:
334     host->ss_family = AF_UNSPEC;
335     break;
336   }
337 }
338 
339 void
340 ncpaddr_setsa(struct ncpaddr *addr, const struct sockaddr *host)
341 {
342   const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
343 #ifndef NOINET6
344   const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
345 #endif
346 
347   switch (host->sa_family) {
348   case AF_INET:
349     addr->ncpaddr_family = AF_INET;
350     addr->ncpaddr_ip4addr = host4->sin_addr;
351     break;
352 
353 #ifndef NOINET6
354   case AF_INET6:
355     if (IN6_IS_ADDR_V4MAPPED(&host6->sin6_addr)) {
356       addr->ncpaddr_family = AF_INET;
357       addr->ncpaddr_ip4addr.s_addr =
358         *(const u_int32_t *)(host6->sin6_addr.s6_addr + 12);
359     } else {
360       addr->ncpaddr_family = AF_INET6;
361       addr->ncpaddr_ip6addr = host6->sin6_addr;
362     }
363     break;
364 #endif
365 
366   default:
367     addr->ncpaddr_family = AF_UNSPEC;
368   }
369 }
370 
371 static char *
372 ncpaddr_ntowa(const struct ncpaddr *addr)
373 {
374   static char res[NCP_ASCIIBUFFERSIZE];
375 #ifndef NOINET6
376   struct sockaddr_in6 sin6;
377 #endif
378 
379   switch (addr->ncpaddr_family) {
380   case AF_INET:
381     snprintf(res, sizeof res, "%s", inet_ntoa(addr->ncpaddr_ip4addr));
382     return res;
383 
384 #ifndef NOINET6
385   case AF_INET6:
386     memset(&sin6, '\0', sizeof(sin6));
387     sin6.sin6_len = sizeof(sin6);
388     sin6.sin6_family = AF_INET6;
389     sin6.sin6_addr = addr->ncpaddr_ip6addr;
390 #if 0
391     adjust_linklocal(&sin6);
392 #endif
393     if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res),
394                     NULL, 0, NI_NUMERICHOST) != 0)
395       break;
396 
397     return res;
398 #endif
399   }
400 
401   snprintf(res, sizeof res, "<AF_UNSPEC>");
402   return res;
403 }
404 
405 const char *
406 ncpaddr_ntoa(const struct ncpaddr *addr)
407 {
408   return ncpaddr_ntowa(addr);
409 }
410 
411 
412 int
413 ncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data)
414 {
415   struct ncprange range;
416 
417   if (!ncprange_aton(&range, ncp, data))
418     return 0;
419 
420   if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32 &&
421       range.ncprange_ip4addr.s_addr != INADDR_ANY) {
422     log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data);
423     return 0;
424   }
425 
426 #ifndef NOINET6
427   if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128 &&
428       !IN6_IS_ADDR_UNSPECIFIED(&range.ncprange_ip6addr)) {
429     log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data);
430     return 0;
431   }
432 #endif
433 
434   switch (range.ncprange_family) {
435   case AF_INET:
436     addr->ncpaddr_family = range.ncprange_family;
437     addr->ncpaddr_ip4addr = range.ncprange_ip4addr;
438     return 1;
439 
440 #ifndef NOINET6
441   case AF_INET6:
442     addr->ncpaddr_family = range.ncprange_family;
443     addr->ncpaddr_ip6addr = range.ncprange_ip6addr;
444     return 1;
445 #endif
446   }
447 
448   return 0;
449 }
450 
451 void
452 ncprange_init(struct ncprange *range)
453 {
454   range->ncprange_family = AF_UNSPEC;
455 }
456 
457 int
458 ncprange_isset(const struct ncprange *range)
459 {
460   return range->ncprange_family != AF_UNSPEC;
461 }
462 
463 int
464 ncprange_equal(const struct ncprange *range, const struct ncprange *cmp)
465 {
466   if (range->ncprange_family != cmp->ncprange_family)
467     return 0;
468 
469   switch (range->ncprange_family) {
470   case AF_INET:
471     if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr)
472       return 0;
473     return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr;
474 
475 #ifndef NOINET6
476   case AF_INET6:
477     if (range->ncprange_ip6width != cmp->ncprange_ip6width)
478       return 0;
479     return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr,
480                    sizeof range->ncprange_ip6addr);
481 #endif
482 
483   case AF_UNSPEC:
484     return 1;
485   }
486 
487   return 0;
488 }
489 
490 int
491 ncprange_isdefault(const struct ncprange *range)
492 {
493   switch (range->ncprange_family) {
494   case AF_INET:
495     if (range->ncprange_ip4addr.s_addr == INADDR_ANY)
496       return 1;
497     break;
498 
499 #ifndef NOINET6
500   case AF_INET6:
501     if (range->ncprange_ip6width == 0 &&
502         IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
503       return 1;
504     break;
505 #endif
506   }
507 
508   return 0;
509 }
510 
511 void
512 ncprange_setdefault(struct ncprange *range, int af)
513 {
514   memset(range, '\0', sizeof *range);
515   range->ncprange_family = af;
516 }
517 
518 int
519 ncprange_contains(const struct ncprange *range, const struct ncpaddr *addr)
520 {
521 #ifndef NOINET6
522   const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
523   const u_char *addrp, *rangep;
524   int bits;
525 #endif
526 
527   if (range->ncprange_family != addr->ncpaddr_family)
528     return 0;
529 
530   switch (range->ncprange_family) {
531   case AF_INET:
532     return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
533              range->ncprange_ip4mask.s_addr);
534 
535 #ifndef NOINET6
536   case AF_INET6:
537     rangep = (const u_char *)range->ncprange_ip6addr.s6_addr;
538     addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr;
539 
540     for (bits = range->ncprange_ip6width; bits > 0; bits -= 8)
541       if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1])
542         return 0;
543 
544     return 1;
545 #endif
546   }
547 
548   return 0;
549 }
550 
551 int
552 ncprange_containsip4(const struct ncprange *range, struct in_addr addr)
553 {
554   switch (range->ncprange_family) {
555   case AF_INET:
556     return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
557              range->ncprange_ip4mask.s_addr);
558   }
559 
560   return 0;
561 }
562 
563 void
564 ncprange_copy(struct ncprange *range, const struct ncprange *from)
565 {
566   switch (from->ncprange_family) {
567   case AF_INET:
568     range->ncprange_family = AF_INET;
569     range->ncprange_ip4addr = from->ncprange_ip4addr;
570     range->ncprange_ip4mask = from->ncprange_ip4mask;
571     range->ncprange_ip4width = from->ncprange_ip4width;
572     break;
573 
574 #ifndef NOINET6
575   case AF_INET6:
576     range->ncprange_family = AF_INET6;
577     range->ncprange_ip6addr = from->ncprange_ip6addr;
578     range->ncprange_ip6width = from->ncprange_ip6width;
579     break;
580 #endif
581 
582   default:
583     range->ncprange_family = AF_UNSPEC;
584   }
585 }
586 
587 void
588 ncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width)
589 {
590   ncprange_sethost(range, addr);
591   ncprange_setwidth(range, width);
592 }
593 
594 void
595 ncprange_sethost(struct ncprange *range, const struct ncpaddr *from)
596 {
597   switch (from->ncpaddr_family) {
598   case AF_INET:
599     range->ncprange_family = AF_INET;
600     range->ncprange_ip4addr = from->ncpaddr_ip4addr;
601     if (from->ncpaddr_ip4addr.s_addr == INADDR_ANY) {
602       range->ncprange_ip4mask.s_addr = INADDR_ANY;
603       range->ncprange_ip4width = 0;
604     } else {
605       range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
606       range->ncprange_ip4width = 32;
607     }
608     break;
609 
610 #ifndef NOINET6
611   case AF_INET6:
612     range->ncprange_family = AF_INET6;
613     range->ncprange_ip6addr = from->ncpaddr_ip6addr;
614     range->ncprange_ip6width = 128;
615     break;
616 #endif
617 
618   default:
619     range->ncprange_family = AF_UNSPEC;
620   }
621 }
622 
623 int
624 ncprange_ishost(const struct ncprange *range)
625 {
626   switch (range->ncprange_family) {
627   case AF_INET:
628     return range->ncprange_ip4width == 32;
629 #ifndef NOINET6
630   case AF_INET6:
631     return range->ncprange_ip6width == 128;
632 #endif
633   }
634 
635   return (0);
636 }
637 
638 int
639 ncprange_setwidth(struct ncprange *range, int width)
640 {
641   switch (range->ncprange_family) {
642   case AF_INET:
643     if (width < 0 || width > 32)
644       break;
645     range->ncprange_ip4width = width;
646     range->ncprange_ip4mask = bits2mask4(width);
647     break;
648 
649 #ifndef NOINET6
650   case AF_INET6:
651     if (width < 0 || width > 128)
652       break;
653     range->ncprange_ip6width = width;
654     break;
655 #endif
656 
657   case AF_UNSPEC:
658     return 1;
659   }
660 
661   return 0;
662 }
663 
664 void
665 ncprange_setip4host(struct ncprange *range, struct in_addr from)
666 {
667   range->ncprange_family = AF_INET;
668   range->ncprange_ip4addr = from;
669   if (from.s_addr == INADDR_ANY) {
670     range->ncprange_ip4mask.s_addr = INADDR_ANY;
671     range->ncprange_ip4width = 0;
672   } else {
673     range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
674     range->ncprange_ip4width = 32;
675   }
676 }
677 
678 void
679 ncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk)
680 {
681   range->ncprange_family = AF_INET;
682   range->ncprange_ip4addr = from;
683   range->ncprange_ip4mask = msk;
684   range->ncprange_ip4width = mask42bits(msk);
685 }
686 
687 
688 int
689 ncprange_setip4mask(struct ncprange *range, struct in_addr mask)
690 {
691   if (range->ncprange_family != AF_INET)
692     return 0;
693   range->ncprange_ip4mask = mask;
694   range->ncprange_ip4width = mask42bits(mask);
695   return 1;
696 }
697 
698 void
699 ncprange_setsa(struct ncprange *range, const struct sockaddr *host,
700                const struct sockaddr *mask)
701 {
702   const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
703   const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask;
704 #ifndef NOINET6
705   const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
706   const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask;
707 #endif
708 
709   switch (host->sa_family) {
710   case AF_INET:
711     range->ncprange_family = AF_INET;
712     range->ncprange_ip4addr = host4->sin_addr;
713     if (host4->sin_addr.s_addr == INADDR_ANY) {
714       range->ncprange_ip4mask.s_addr = INADDR_ANY;
715       range->ncprange_ip4width = 0;
716     } else if (mask4 && mask4->sin_family == AF_INET) {
717       range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr;
718       range->ncprange_ip4width = mask42bits(mask4->sin_addr);
719     } else {
720       range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
721       range->ncprange_ip4width = 32;
722     }
723     break;
724 
725 #ifndef NOINET6
726   case AF_INET6:
727     range->ncprange_family = AF_INET6;
728     range->ncprange_ip6addr = host6->sin6_addr;
729     if (IN6_IS_ADDR_UNSPECIFIED(&host6->sin6_addr))
730       range->ncprange_ip6width = 0;
731     else
732       range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128;
733     break;
734 #endif
735 
736   default:
737     range->ncprange_family = AF_UNSPEC;
738   }
739 }
740 
741 void
742 ncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host,
743                struct sockaddr_storage *mask)
744 {
745   struct sockaddr_in *host4 = (struct sockaddr_in *)host;
746   struct sockaddr_in *mask4 = (struct sockaddr_in *)mask;
747 #ifndef NOINET6
748   struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
749   struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask;
750 #endif
751 
752   memset(host, '\0', sizeof(*host));
753   if (mask)
754     memset(mask, '\0', sizeof(*mask));
755 
756   switch (range->ncprange_family) {
757   case AF_INET:
758     host4->sin_family = AF_INET;
759     host4->sin_len = sizeof(*host4);
760     host4->sin_addr = range->ncprange_ip4addr;
761     if (mask4) {
762       mask4->sin_family = AF_INET;
763       mask4->sin_len = sizeof(*host4);
764       mask4->sin_addr = range->ncprange_ip4mask;
765     }
766     break;
767 
768 #ifndef NOINET6
769   case AF_INET6:
770     host6->sin6_family = AF_INET6;
771     host6->sin6_len = sizeof(*host6);
772     host6->sin6_addr = range->ncprange_ip6addr;
773     if (mask6) {
774       mask6->sin6_family = AF_INET6;
775       mask6->sin6_len = sizeof(*host6);
776       mask6->sin6_addr = bits2mask6(range->ncprange_ip6width);
777     }
778     break;
779 #endif
780 
781   default:
782     host->ss_family = AF_UNSPEC;
783     if (mask)
784       mask->ss_family = AF_UNSPEC;
785     break;
786   }
787 }
788 
789 int
790 ncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr)
791 {
792   switch (range->ncprange_family) {
793   case AF_INET:
794     addr->ncpaddr_family = AF_INET;
795     addr->ncpaddr_ip4addr = range->ncprange_ip4addr;
796     return 1;
797 #ifndef NOINET6
798   case AF_INET6:
799     addr->ncpaddr_family = AF_INET6;
800     addr->ncpaddr_ip6addr =  range->ncprange_ip6addr;
801     return 1;
802 #endif
803   }
804 
805   return 0;
806 }
807 
808 int
809 ncprange_getip4addr(const struct ncprange *range, struct in_addr *addr)
810 {
811   if (range->ncprange_family != AF_INET)
812     return 0;
813 
814   *addr = range->ncprange_ip4addr;
815   return 1;
816 }
817 
818 int
819 ncprange_getip4mask(const struct ncprange *range, struct in_addr *mask)
820 {
821   switch (range->ncprange_family) {
822   case AF_INET:
823     *mask = range->ncprange_ip4mask;
824     return 1;
825   }
826 
827   return 0;
828 }
829 
830 int
831 ncprange_getwidth(const struct ncprange *range, int *width)
832 {
833   switch (range->ncprange_family) {
834   case AF_INET:
835     *width = range->ncprange_ip4width;
836     return 1;
837 #ifndef NOINET6
838   case AF_INET6:
839     *width = range->ncprange_ip6width;
840     return 1;
841 #endif
842   }
843 
844   return 0;
845 }
846 
847 const char *
848 ncprange_ntoa(const struct ncprange *range)
849 {
850   char *res;
851   struct ncpaddr addr;
852   int len;
853 
854   if (!ncprange_getaddr(range, &addr))
855     return "<AF_UNSPEC>";
856 
857   res = ncpaddr_ntowa(&addr);
858   len = strlen(res);
859   if (len >= NCP_ASCIIBUFFERSIZE - 1)
860     return res;
861 
862   switch (range->ncprange_family) {
863   case AF_INET:
864     if (range->ncprange_ip4width == -1) {
865       /* A non-contiguous mask */
866       for (; len >= 3; res[len -= 2] = '\0')
867         if (strcmp(res + len - 2, ".0"))
868           break;
869       snprintf(res + len, sizeof res - len, "&0x%08lx",
870                (unsigned long)ntohl(range->ncprange_ip4mask.s_addr));
871     } else if (range->ncprange_ip4width < 32)
872       snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width);
873 
874     return res;
875 
876 #ifndef NOINET6
877   case AF_INET6:
878     if (range->ncprange_ip6width != 128)
879       snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width);
880 
881     return res;
882 #endif
883   }
884 
885   return "<AF_UNSPEC>";
886 }
887 
888 #ifndef NOINET6
889 int
890 ncprange_scopeid(const struct ncprange *range)
891 {
892   const struct in6_addr *sin6;
893   int scopeid = -1;
894 
895   if (range->ncprange_family == AF_INET6) {
896     sin6 = &range->ncprange_ip6addr;
897     if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6))
898       if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0)
899         scopeid = -1;
900   }
901 
902   return scopeid;
903 }
904 #endif
905 
906 int
907 ncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data)
908 {
909   int bits, len;
910   char *wp;
911   const char *cp;
912   char *s;
913 
914   len = strcspn(data, "/");
915 
916   if (ncp && strncasecmp(data, "HISADDR", len) == 0) {
917     range->ncprange_family = AF_INET;
918     range->ncprange_ip4addr = ncp->ipcp.peer_ip;
919     range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
920     range->ncprange_ip4width = 32;
921     return 1;
922 #ifndef NOINET6
923   } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) {
924     range->ncprange_family = AF_INET6;
925     range->ncprange_ip6addr = ncp->ipv6cp.hisaddr.ncpaddr_ip6addr;
926     range->ncprange_ip6width = 128;
927     return 1;
928 #endif
929   } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) {
930     range->ncprange_family = AF_INET;
931     range->ncprange_ip4addr = ncp->ipcp.my_ip;
932     range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
933     range->ncprange_ip4width = 32;
934     return 1;
935 #ifndef NOINET6
936   } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) {
937     range->ncprange_family = AF_INET6;
938     range->ncprange_ip6addr = ncp->ipv6cp.myaddr.ncpaddr_ip6addr;
939     range->ncprange_ip6width = 128;
940     return 1;
941 #endif
942   } else if (ncp && strncasecmp(data, "DNS0", len) == 0) {
943     range->ncprange_family = AF_INET;
944     range->ncprange_ip4addr = ncp->ipcp.ns.dns[0];
945     range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
946     range->ncprange_ip4width = 32;
947     return 1;
948   } else if (ncp && strncasecmp(data, "DNS1", len) == 0) {
949     range->ncprange_family = AF_INET;
950     range->ncprange_ip4addr = ncp->ipcp.ns.dns[1];
951     range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
952     range->ncprange_ip4width = 32;
953     return 1;
954   }
955 
956   s = (char *)alloca(len + 1);
957   strncpy(s, data, len);
958   s[len] = '\0';
959   bits = -1;
960 
961   if (data[len] != '\0') {
962     bits = strtol(data + len + 1, &wp, 0);
963     if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) {
964       log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
965       return 0;
966     }
967   }
968 
969   if ((cp = strchr(data, ':')) == NULL) {
970     range->ncprange_family = AF_INET;
971 
972     range->ncprange_ip4addr = GetIpAddr(s);
973 
974     if (range->ncprange_ip4addr.s_addr == INADDR_NONE) {
975       log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
976       return 0;
977     }
978 
979     if (range->ncprange_ip4addr.s_addr == INADDR_ANY) {
980       range->ncprange_ip4mask.s_addr = INADDR_ANY;
981       range->ncprange_ip4width = 0;
982     } else if (bits == -1) {
983       range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
984       range->ncprange_ip4width = 32;
985     } else if (bits > 32) {
986       log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
987       return 0;
988     } else {
989       range->ncprange_ip4mask = bits2mask4(bits);
990       range->ncprange_ip4width = bits;
991     }
992 
993     return 1;
994 #ifndef NOINET6
995   } else if (strchr(cp + 1, ':') != NULL) {
996     range->ncprange_family = AF_INET6;
997 
998     if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) {
999       log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
1000       return 0;
1001     }
1002 
1003     if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
1004       range->ncprange_ip6width = 0;
1005     else
1006       range->ncprange_ip6width = (bits == -1) ? 128 : bits;
1007     return 1;
1008 #endif
1009   }
1010 
1011   return 0;
1012 }
1013