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