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