ncpaddr.c revision 102558
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: head/usr.sbin/ppp/ncpaddr.c 102558 2002-08-29 02:44:58Z brian $
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;
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; c < masks + sizeof masks; c++)
153      if (*c == *p) {
154        masklen += c - masks;
155        break;
156      }
157  }
158
159  return masklen;
160}
161
162static void
163adjust_linklocal(struct sockaddr_in6 *sin6)
164{
165    /* XXX: ?????!?!?!!!!!  This is horrible ! */
166#if 0
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#endif
179}
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    adjust_linklocal(&sin6);
389#ifdef NI_WITHSCOPEID
390    if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res),
391                    NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST) != 0)
392#else
393    if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res),
394                    NULL, 0, NI_NUMERICHOST) != 0)
395#endif
396      break;
397
398    return res;
399#endif
400  }
401
402  snprintf(res, sizeof res, "<AF_UNSPEC>");
403  return res;
404}
405
406const char *
407ncpaddr_ntoa(const struct ncpaddr *addr)
408{
409  return ncpaddr_ntowa(addr);
410}
411
412
413int
414ncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data)
415{
416  struct ncprange range;
417
418  if (!ncprange_aton(&range, ncp, data))
419    return 0;
420
421  if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32) {
422    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data);
423    return 0;
424  }
425
426#ifndef NOINET6
427  if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128) {
428    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data);
429    return 0;
430  }
431#endif
432
433  switch (range.ncprange_family) {
434  case AF_INET:
435    addr->ncpaddr_family = range.ncprange_family;
436    addr->ncpaddr_ip4addr = range.ncprange_ip4addr;
437    return 1;
438
439#ifndef NOINET6
440  case AF_INET6:
441    addr->ncpaddr_family = range.ncprange_family;
442    addr->ncpaddr_ip6addr = range.ncprange_ip6addr;
443    return 1;
444#endif
445  }
446
447  return 0;
448}
449
450void
451ncprange_init(struct ncprange *range)
452{
453  range->ncprange_family = AF_UNSPEC;
454}
455
456int
457ncprange_isset(const struct ncprange *range)
458{
459  return range->ncprange_family != AF_UNSPEC;
460}
461
462int
463ncprange_equal(const struct ncprange *range, const struct ncprange *cmp)
464{
465  if (range->ncprange_family != cmp->ncprange_family)
466    return 0;
467
468  switch (range->ncprange_family) {
469  case AF_INET:
470    if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr)
471      return 0;
472    return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr;
473
474#ifndef NOINET6
475  case AF_INET6:
476    if (range->ncprange_ip6width != cmp->ncprange_ip6width)
477      return 0;
478    return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr,
479                   sizeof range->ncprange_ip6addr);
480#endif
481
482  case AF_UNSPEC:
483    return 1;
484  }
485
486  return 0;
487}
488
489int
490ncprange_isdefault(const struct ncprange *range)
491{
492  switch (range->ncprange_family) {
493  case AF_INET:
494    if (range->ncprange_ip4addr.s_addr == INADDR_ANY)
495      return 1;
496    break;
497
498#ifndef NOINET6
499  case AF_INET6:
500    if (range->ncprange_ip6width == 0 &&
501        IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
502      return 1;
503    break;
504#endif
505  }
506
507  return 0;
508}
509
510void
511ncprange_setdefault(struct ncprange *range, int af)
512{
513  memset(range, '\0', sizeof *range);
514  range->ncprange_family = af;
515}
516
517int
518ncprange_contains(const struct ncprange *range, const struct ncpaddr *addr)
519{
520#ifndef NOINET6
521  const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
522  const u_char *addrp, *rangep;
523  int bits;
524#endif
525
526  if (range->ncprange_family != addr->ncpaddr_family)
527    return 0;
528
529  switch (range->ncprange_family) {
530  case AF_INET:
531    return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
532             range->ncprange_ip4mask.s_addr);
533
534#ifndef NOINET6
535  case AF_INET6:
536    rangep = (const u_char *)range->ncprange_ip6addr.s6_addr;
537    addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr;
538
539    for (bits = range->ncprange_ip6width; bits > 0; bits -= 8)
540      if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1])
541        return 0;
542
543    return 1;
544#endif
545  }
546
547  return 0;
548}
549
550int
551ncprange_containsip4(const struct ncprange *range, struct in_addr addr)
552{
553  switch (range->ncprange_family) {
554  case AF_INET:
555    return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
556             range->ncprange_ip4mask.s_addr);
557  }
558
559  return 0;
560}
561
562void
563ncprange_copy(struct ncprange *range, const struct ncprange *from)
564{
565  switch (from->ncprange_family) {
566  case AF_INET:
567    range->ncprange_family = AF_INET;
568    range->ncprange_ip4addr = from->ncprange_ip4addr;
569    range->ncprange_ip4mask = from->ncprange_ip4mask;
570    range->ncprange_ip4width = from->ncprange_ip4width;
571    break;
572
573#ifndef NOINET6
574  case AF_INET6:
575    range->ncprange_family = AF_INET6;
576    range->ncprange_ip6addr = from->ncprange_ip6addr;
577    range->ncprange_ip6width = from->ncprange_ip6width;
578    break;
579#endif
580
581  default:
582    range->ncprange_family = AF_UNSPEC;
583  }
584}
585
586void
587ncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width)
588{
589  ncprange_sethost(range, addr);
590  ncprange_setwidth(range, width);
591}
592
593void
594ncprange_sethost(struct ncprange *range, const struct ncpaddr *from)
595{
596  switch (from->ncpaddr_family) {
597  case AF_INET:
598    range->ncprange_family = AF_INET;
599    range->ncprange_ip4addr = from->ncpaddr_ip4addr;
600    if (from->ncpaddr_ip4addr.s_addr == INADDR_ANY) {
601      range->ncprange_ip4mask.s_addr = INADDR_ANY;
602      range->ncprange_ip4width = 0;
603    } else {
604      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
605      range->ncprange_ip4width = 32;
606    }
607    break;
608
609#ifndef NOINET6
610  case AF_INET6:
611    range->ncprange_family = AF_INET6;
612    range->ncprange_ip6addr = from->ncpaddr_ip6addr;
613    range->ncprange_ip6width = 128;
614    break;
615#endif
616
617  default:
618    range->ncprange_family = AF_UNSPEC;
619  }
620}
621
622int
623ncprange_ishost(const struct ncprange *range)
624{
625  switch (range->ncprange_family) {
626  case AF_INET:
627    return range->ncprange_ip4width == 32;
628#ifndef NOINET6
629  case AF_INET6:
630    return range->ncprange_ip6width == 128;
631#endif
632  }
633
634  return (0);
635}
636
637int
638ncprange_setwidth(struct ncprange *range, int width)
639{
640  switch (range->ncprange_family) {
641  case AF_INET:
642    if (width < 0 || width > 32)
643      break;
644    range->ncprange_ip4width = width;
645    range->ncprange_ip4mask = bits2mask4(width);
646    break;
647
648#ifndef NOINET6
649  case AF_INET6:
650    if (width < 0 || width > 128)
651      break;
652    range->ncprange_ip6width = width;
653    break;
654#endif
655
656  case AF_UNSPEC:
657    return 1;
658  }
659
660  return 0;
661}
662
663void
664ncprange_setip4host(struct ncprange *range, struct in_addr from)
665{
666  range->ncprange_family = AF_INET;
667  range->ncprange_ip4addr = from;
668  if (from.s_addr == INADDR_ANY) {
669    range->ncprange_ip4mask.s_addr = INADDR_ANY;
670    range->ncprange_ip4width = 0;
671  } else {
672    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
673    range->ncprange_ip4width = 32;
674  }
675}
676
677void
678ncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk)
679{
680  range->ncprange_family = AF_INET;
681  range->ncprange_ip4addr = from;
682  range->ncprange_ip4mask = msk;
683  range->ncprange_ip4width = mask42bits(msk);
684}
685
686
687int
688ncprange_setip4mask(struct ncprange *range, struct in_addr mask)
689{
690  if (range->ncprange_family != AF_INET)
691    return 0;
692  range->ncprange_ip4mask = mask;
693  range->ncprange_ip4width = mask42bits(mask);
694  return 1;
695}
696
697void
698ncprange_setsa(struct ncprange *range, const struct sockaddr *host,
699               const struct sockaddr *mask)
700{
701  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
702  const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask;
703#ifndef NOINET6
704  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
705  const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask;
706#endif
707
708  switch (host->sa_family) {
709  case AF_INET:
710    range->ncprange_family = AF_INET;
711    range->ncprange_ip4addr = host4->sin_addr;
712    if (host4->sin_addr.s_addr == INADDR_ANY) {
713      range->ncprange_ip4mask.s_addr = INADDR_ANY;
714      range->ncprange_ip4width = 0;
715    } else if (mask4 && mask4->sin_family == AF_INET) {
716      range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr;
717      range->ncprange_ip4width = mask42bits(mask4->sin_addr);
718    } else {
719      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
720      range->ncprange_ip4width = 32;
721    }
722    break;
723
724#ifndef NOINET6
725  case AF_INET6:
726    range->ncprange_family = AF_INET6;
727    range->ncprange_ip6addr = host6->sin6_addr;
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    ncprange_sethost(range, &ncp->ipv6cp.hisaddr);
921    return 1;
922#endif
923  } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) {
924    range->ncprange_family = AF_INET;
925    range->ncprange_ip4addr = ncp->ipcp.my_ip;
926    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
927    range->ncprange_ip4width = 32;
928    return 1;
929#ifndef NOINET6
930  } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) {
931    ncprange_sethost(range, &ncp->ipv6cp.myaddr);
932    return 1;
933#endif
934  } else if (ncp && strncasecmp(data, "DNS0", len) == 0) {
935    range->ncprange_family = AF_INET;
936    range->ncprange_ip4addr = ncp->ipcp.ns.dns[0];
937    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
938    range->ncprange_ip4width = 32;
939    return 1;
940  } else if (ncp && strncasecmp(data, "DNS1", len) == 0) {
941    range->ncprange_family = AF_INET;
942    range->ncprange_ip4addr = ncp->ipcp.ns.dns[1];
943    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
944    range->ncprange_ip4width = 32;
945    return 1;
946  }
947
948  s = (char *)alloca(len + 1);
949  strncpy(s, data, len);
950  s[len] = '\0';
951  bits = -1;
952
953  if (data[len] != '\0') {
954    bits = strtol(data + len + 1, &wp, 0);
955    if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) {
956      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
957      return 0;
958    }
959  }
960
961  if ((cp = strchr(data, ':')) == NULL) {
962    range->ncprange_family = AF_INET;
963
964    range->ncprange_ip4addr = GetIpAddr(s);
965
966    if (range->ncprange_ip4addr.s_addr == INADDR_NONE) {
967      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
968      return 0;
969    }
970
971    if (range->ncprange_ip4addr.s_addr == INADDR_ANY) {
972      range->ncprange_ip4mask.s_addr = INADDR_ANY;
973      range->ncprange_ip4width = 0;
974    } else if (bits == -1) {
975      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
976      range->ncprange_ip4width = 32;
977    } else if (bits > 32) {
978      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
979      return 0;
980    } else {
981      range->ncprange_ip4mask = bits2mask4(bits);
982      range->ncprange_ip4width = bits;
983    }
984
985    return 1;
986#ifndef NOINET6
987  } else if (strchr(cp + 1, ':') != NULL) {
988    range->ncprange_family = AF_INET6;
989
990    if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) {
991      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
992      return 0;
993    }
994
995    if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
996      range->ncprange_ip6width = 0;
997    else
998      range->ncprange_ip6width = (bits == -1) ? 128 : bits;
999    return 1;
1000#endif
1001  }
1002
1003  return 0;
1004}
1005