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