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