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