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#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
81static struct in_addr
82bits2mask4(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
99static int
100mask42bits(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
118static struct in6_addr
119bits2mask6(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
140static int
141mask62bits(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
163static void
164adjust_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@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
182void
183ncpaddr_init(struct ncpaddr *addr)
184{
185  addr->ncpaddr_family = AF_UNSPEC;
186}
187
188int
189ncpaddr_isset(const struct ncpaddr *addr)
190{
191  return addr->ncpaddr_family != AF_UNSPEC;
192}
193
194int
195ncpaddr_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
214int
215ncpaddr_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
237void
238ncpaddr_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
256void
257ncpaddr_setip4addr(struct ncpaddr *addr, u_int32_t ip)
258{
259  addr->ncpaddr_family = AF_INET;
260  addr->ncpaddr_ip4addr.s_addr = ip;
261}
262
263int
264ncpaddr_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
272void
273ncpaddr_setip4(struct ncpaddr *addr, struct in_addr ip)
274{
275  addr->ncpaddr_family = AF_INET;
276  addr->ncpaddr_ip4addr = ip;
277}
278
279int
280ncpaddr_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
289void
290ncpaddr_setip6(struct ncpaddr *addr, const struct in6_addr *ip6)
291{
292  addr->ncpaddr_family = AF_INET6;
293  addr->ncpaddr_ip6addr = *ip6;
294}
295
296int
297ncpaddr_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
306void
307ncpaddr_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
337void
338ncpaddr_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
369static char *
370ncpaddr_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
403const char *
404ncpaddr_ntoa(const struct ncpaddr *addr)
405{
406  return ncpaddr_ntowa(addr);
407}
408
409
410int
411ncpaddr_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
449void
450ncprange_init(struct ncprange *range)
451{
452  range->ncprange_family = AF_UNSPEC;
453}
454
455int
456ncprange_isset(const struct ncprange *range)
457{
458  return range->ncprange_family != AF_UNSPEC;
459}
460
461int
462ncprange_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
488int
489ncprange_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
509void
510ncprange_setdefault(struct ncprange *range, int af)
511{
512  memset(range, '\0', sizeof *range);
513  range->ncprange_family = af;
514}
515
516int
517ncprange_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
549int
550ncprange_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
561void
562ncprange_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
585void
586ncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width)
587{
588  ncprange_sethost(range, addr);
589  ncprange_setwidth(range, width);
590}
591
592void
593ncprange_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
621int
622ncprange_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
636int
637ncprange_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
662void
663ncprange_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
676void
677ncprange_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
686int
687ncprange_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
696void
697ncprange_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
739void
740ncprange_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
787int
788ncprange_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
806int
807ncprange_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
816int
817ncprange_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
828int
829ncprange_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
845const char *
846ncprange_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
887int
888ncprange_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
904int
905ncprange_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