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