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