ncpaddr.c revision 81739
1330569Sgordon/*-
2267843Sdelphij * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
3330569Sgordon * All rights reserved.
4330569Sgordon *
5330569Sgordon * Redistribution and use in source and binary forms, with or without
6330569Sgordon * modification, are permitted provided that the following conditions
7330569Sgordon * are met:
8330569Sgordon * 1. Redistributions of source code must retain the above copyright
9330569Sgordon *    notice, this list of conditions and the following disclaimer.
10330569Sgordon * 2. Redistributions in binary form must reproduce the above copyright
11330569Sgordon *    notice, this list of conditions and the following disclaimer in the
12330569Sgordon *    documentation and/or other materials provided with the distribution.
13330569Sgordon *
14330569Sgordon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15330569Sgordon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16330569Sgordon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17330569Sgordon * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18330569Sgordon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19330569Sgordon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20330569Sgordon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21330569Sgordon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22330569Sgordon * 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 81739 2001-08-16 02:01:05Z 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    adjust_linklocal(host6);
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    if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res),
390                    NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST) != 0)
391      break;
392
393    return res;
394#endif
395  }
396
397  snprintf(res, sizeof res, "<AF_UNSPEC>");
398  return res;
399}
400
401const char *
402ncpaddr_ntoa(const struct ncpaddr *addr)
403{
404  return ncpaddr_ntowa(addr);
405}
406
407
408int
409ncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data)
410{
411  struct ncprange range;
412
413  if (!ncprange_aton(&range, ncp, data))
414    return 0;
415
416  if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32) {
417    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data);
418    return 0;
419  }
420
421#ifndef NOINET6
422  if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128) {
423    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data);
424    return 0;
425  }
426#endif
427
428  switch (range.ncprange_family) {
429  case AF_INET:
430    addr->ncpaddr_family = range.ncprange_family;
431    addr->ncpaddr_ip4addr = range.ncprange_ip4addr;
432    return 1;
433
434#ifndef NOINET6
435  case AF_INET6:
436    addr->ncpaddr_family = range.ncprange_family;
437    addr->ncpaddr_ip6addr = range.ncprange_ip6addr;
438    return 1;
439#endif
440  }
441
442  return 0;
443}
444
445void
446ncprange_init(struct ncprange *range)
447{
448  range->ncprange_family = AF_UNSPEC;
449}
450
451int
452ncprange_isset(const struct ncprange *range)
453{
454  return range->ncprange_family != AF_UNSPEC;
455}
456
457int
458ncprange_equal(const struct ncprange *range, const struct ncprange *cmp)
459{
460  if (range->ncprange_family != cmp->ncprange_family)
461    return 0;
462
463  switch (range->ncprange_family) {
464  case AF_INET:
465    if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr)
466      return 0;
467    return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr;
468
469#ifndef NOINET6
470  case AF_INET6:
471    if (range->ncprange_ip6width != cmp->ncprange_ip6width)
472      return 0;
473    return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr,
474                   sizeof range->ncprange_ip6addr);
475#endif
476
477  case AF_UNSPEC:
478    return 1;
479  }
480
481  return 0;
482}
483
484int
485ncprange_isdefault(const struct ncprange *range)
486{
487  switch (range->ncprange_family) {
488  case AF_INET:
489    if (range->ncprange_ip4addr.s_addr == INADDR_ANY)
490      return 1;
491    break;
492
493#ifndef NOINET6
494  case AF_INET6:
495    if (range->ncprange_ip6width == 0 &&
496        IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
497      return 1;
498    break;
499#endif
500  }
501
502  return 0;
503}
504
505void
506ncprange_setdefault(struct ncprange *range, int af)
507{
508  memset(range, '\0', sizeof *range);
509  range->ncprange_family = af;
510}
511
512int
513ncprange_contains(const struct ncprange *range, const struct ncpaddr *addr)
514{
515#ifndef NOINET6
516  const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
517  const u_char *addrp, *rangep;
518  int bits;
519#endif
520
521  if (range->ncprange_family != addr->ncpaddr_family)
522    return 0;
523
524  switch (range->ncprange_family) {
525  case AF_INET:
526    return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
527             range->ncprange_ip4mask.s_addr);
528
529#ifndef NOINET6
530  case AF_INET6:
531    rangep = (const u_char *)range->ncprange_ip6addr.s6_addr;
532    addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr;
533
534    for (bits = range->ncprange_ip6width; bits > 0; bits -= 8)
535      if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1])
536        return 0;
537
538    return 1;
539#endif
540  }
541
542  return 0;
543}
544
545int
546ncprange_containsip4(const struct ncprange *range, struct in_addr addr)
547{
548  switch (range->ncprange_family) {
549  case AF_INET:
550    return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
551             range->ncprange_ip4mask.s_addr);
552  }
553
554  return 0;
555}
556
557void
558ncprange_copy(struct ncprange *range, const struct ncprange *from)
559{
560  switch (from->ncprange_family) {
561  case AF_INET:
562    range->ncprange_family = AF_INET;
563    range->ncprange_ip4addr = from->ncprange_ip4addr;
564    range->ncprange_ip4mask = from->ncprange_ip4mask;
565    range->ncprange_ip4width = from->ncprange_ip4width;
566    break;
567
568#ifndef NOINET6
569  case AF_INET6:
570    range->ncprange_family = AF_INET6;
571    range->ncprange_ip6addr = from->ncprange_ip6addr;
572    range->ncprange_ip6width = from->ncprange_ip6width;
573    break;
574#endif
575
576  default:
577    range->ncprange_family = AF_UNSPEC;
578  }
579}
580
581void
582ncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width)
583{
584  ncprange_sethost(range, addr);
585  ncprange_setwidth(range, width);
586}
587
588void
589ncprange_sethost(struct ncprange *range, const struct ncpaddr *from)
590{
591  switch (from->ncpaddr_family) {
592  case AF_INET:
593    range->ncprange_family = AF_INET;
594    range->ncprange_ip4addr = from->ncpaddr_ip4addr;
595    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
596    range->ncprange_ip4width = 32;
597    break;
598
599#ifndef NOINET6
600  case AF_INET6:
601    range->ncprange_family = AF_INET6;
602    range->ncprange_ip6addr = from->ncpaddr_ip6addr;
603    range->ncprange_ip6width = 128;
604    break;
605#endif
606
607  default:
608    range->ncprange_family = AF_UNSPEC;
609  }
610}
611
612int
613ncprange_setwidth(struct ncprange *range, int width)
614{
615  switch (range->ncprange_family) {
616  case AF_INET:
617    if (width < 0 || width > 32)
618      break;
619    range->ncprange_ip4width = width;
620    range->ncprange_ip4mask = bits2mask4(width);
621    break;
622
623#ifndef NOINET6
624  case AF_INET6:
625    if (width < 0 || width > 128)
626      break;
627    range->ncprange_ip6width = width;
628    break;
629#endif
630
631  case AF_UNSPEC:
632    return 1;
633  }
634
635  return 0;
636}
637
638void
639ncprange_setip4host(struct ncprange *range, struct in_addr from)
640{
641  range->ncprange_family = AF_INET;
642  range->ncprange_ip4addr = from;
643  range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
644  range->ncprange_ip4width = 32;
645}
646
647void
648ncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk)
649{
650  range->ncprange_family = AF_INET;
651  range->ncprange_ip4addr = from;
652  range->ncprange_ip4mask = msk;
653  range->ncprange_ip4width = mask42bits(msk);
654}
655
656
657int
658ncprange_setip4mask(struct ncprange *range, struct in_addr mask)
659{
660  if (range->ncprange_family != AF_INET)
661    return 0;
662  range->ncprange_ip4mask = mask;
663  range->ncprange_ip4width = mask42bits(mask);
664  return 1;
665}
666
667void
668ncprange_setsa(struct ncprange *range, const struct sockaddr *host,
669               const struct sockaddr *mask)
670{
671  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
672  const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask;
673#ifndef NOINET6
674  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
675  const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask;
676#endif
677
678  switch (host->sa_family) {
679  case AF_INET:
680    range->ncprange_family = AF_INET;
681    range->ncprange_ip4addr = host4->sin_addr;
682    if (mask4) {
683      range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr;
684      range->ncprange_ip4width = mask42bits(mask4->sin_addr);
685    } else {
686      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
687      range->ncprange_ip4width = 32;
688    }
689    break;
690
691#ifndef NOINET6
692  case AF_INET6:
693    range->ncprange_family = AF_INET6;
694    range->ncprange_ip6addr = host6->sin6_addr;
695    range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128;
696    break;
697#endif
698
699  default:
700    range->ncprange_family = AF_UNSPEC;
701  }
702}
703
704void
705ncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host,
706               struct sockaddr_storage *mask)
707{
708  struct sockaddr_in *host4 = (struct sockaddr_in *)host;
709  struct sockaddr_in *mask4 = (struct sockaddr_in *)mask;
710#ifndef NOINET6
711  struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
712  struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask;
713#endif
714
715  memset(host, '\0', sizeof(*host));
716  if (mask)
717    memset(mask, '\0', sizeof(*mask));
718
719  switch (range->ncprange_family) {
720  case AF_INET:
721    host4->sin_family = AF_INET;
722    host4->sin_len = sizeof(*host4);
723    host4->sin_addr = range->ncprange_ip4addr;
724    if (mask4) {
725      mask4->sin_family = AF_INET;
726      mask4->sin_len = sizeof(*host4);
727      mask4->sin_addr = range->ncprange_ip4mask;
728    }
729    break;
730
731#ifndef NOINET6
732  case AF_INET6:
733    host6->sin6_family = AF_INET6;
734    host6->sin6_len = sizeof(*host6);
735    host6->sin6_addr = range->ncprange_ip6addr;
736    adjust_linklocal(host6);
737    if (mask6) {
738      mask6->sin6_family = AF_INET6;
739      mask6->sin6_len = sizeof(*host6);
740      mask6->sin6_addr = bits2mask6(range->ncprange_ip6width);
741    }
742    break;
743#endif
744
745  default:
746    host->ss_family = AF_UNSPEC;
747    if (mask)
748      mask->ss_family = AF_UNSPEC;
749    break;
750  }
751}
752
753int
754ncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr)
755{
756  switch (range->ncprange_family) {
757  case AF_INET:
758    addr->ncpaddr_family = AF_INET;
759    addr->ncpaddr_ip4addr = range->ncprange_ip4addr;
760    return 1;
761#ifndef NOINET6
762  case AF_INET6:
763    addr->ncpaddr_family = AF_INET6;
764    addr->ncpaddr_ip6addr =  range->ncprange_ip6addr;
765    return 1;
766#endif
767  }
768
769  return 0;
770}
771
772int
773ncprange_getip4addr(const struct ncprange *range, struct in_addr *addr)
774{
775  if (range->ncprange_family != AF_INET)
776    return 0;
777
778  *addr = range->ncprange_ip4addr;
779  return 1;
780}
781
782int
783ncprange_getip4mask(const struct ncprange *range, struct in_addr *mask)
784{
785  switch (range->ncprange_family) {
786  case AF_INET:
787    *mask = range->ncprange_ip4mask;
788    return 1;
789  }
790
791  return 0;
792}
793
794int
795ncprange_getwidth(const struct ncprange *range, int *width)
796{
797  switch (range->ncprange_family) {
798  case AF_INET:
799    *width = range->ncprange_ip4width;
800    return 1;
801#ifndef NOINET6
802  case AF_INET6:
803    *width = range->ncprange_ip6width;
804    return 1;
805#endif
806  }
807
808  return 0;
809}
810
811const char *
812ncprange_ntoa(const struct ncprange *range)
813{
814  char *res;
815  struct ncpaddr addr;
816  int len;
817
818  if (!ncprange_getaddr(range, &addr))
819    return "<AF_UNSPEC>";
820
821  res = ncpaddr_ntowa(&addr);
822  len = strlen(res);
823  if (len >= NCP_ASCIIBUFFERSIZE - 1)
824    return res;
825
826  switch (range->ncprange_family) {
827  case AF_INET:
828    if (range->ncprange_ip4width == -1) {
829      /* A non-contiguous mask */
830      for (; len >= 3; res[len -= 2] = '\0')
831        if (strcmp(res + len - 2, ".0"))
832          break;
833      snprintf(res + len, sizeof res - len, "&0x%08lx",
834               ntohl(range->ncprange_ip4mask.s_addr));
835    } else if (range->ncprange_ip4width < 32)
836      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width);
837
838    return res;
839
840#ifndef NOINET6
841  case AF_INET6:
842    if (range->ncprange_ip6width != 128)
843      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width);
844
845    return res;
846#endif
847  }
848
849  return "<AF_UNSPEC>";
850}
851
852#ifndef NOINET6
853int
854ncprange_scopeid(const struct ncprange *range)
855{
856  const struct in6_addr *sin6;
857  int scopeid = -1;
858
859  if (range->ncprange_family == AF_INET6) {
860    sin6 = &range->ncprange_ip6addr;
861    if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6))
862      if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0)
863        scopeid = -1;
864  }
865
866  return scopeid;
867}
868#endif
869
870int
871ncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data)
872{
873  int bits, len;
874  char *wp;
875  const char *cp;
876  char *s;
877
878  len = strcspn(data, "/");
879
880  if (ncp && strncasecmp(data, "HISADDR", len) == 0) {
881    range->ncprange_family = AF_INET;
882    range->ncprange_ip4addr = ncp->ipcp.peer_ip;
883    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
884    range->ncprange_ip4width = 32;
885    return 1;
886#ifndef NOINET6
887  } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) {
888    ncprange_sethost(range, &ncp->ipv6cp.hisaddr);
889    return 1;
890#endif
891  } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) {
892    range->ncprange_family = AF_INET;
893    range->ncprange_ip4addr = ncp->ipcp.my_ip;
894    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
895    range->ncprange_ip4width = 32;
896    return 1;
897#ifndef NOINET6
898  } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) {
899    ncprange_sethost(range, &ncp->ipv6cp.myaddr);
900    return 1;
901#endif
902  } else if (ncp && strncasecmp(data, "DNS0", len) == 0) {
903    range->ncprange_family = AF_INET;
904    range->ncprange_ip4addr = ncp->ipcp.ns.dns[0];
905    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
906    range->ncprange_ip4width = 32;
907    return 1;
908  } else if (ncp && strncasecmp(data, "DNS1", len) == 0) {
909    range->ncprange_family = AF_INET;
910    range->ncprange_ip4addr = ncp->ipcp.ns.dns[1];
911    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
912    range->ncprange_ip4width = 32;
913    return 1;
914  }
915
916  s = (char *)alloca(len + 1);
917  strncpy(s, data, len);
918  s[len] = '\0';
919  bits = -1;
920
921  if (data[len] != '\0') {
922    bits = strtol(data + len + 1, &wp, 0);
923    if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) {
924      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
925      return 0;
926    }
927  }
928
929  if ((cp = strchr(data, ':')) == NULL) {
930    range->ncprange_family = AF_INET;
931
932    range->ncprange_ip4addr = GetIpAddr(s);
933
934    if (range->ncprange_ip4addr.s_addr == INADDR_NONE) {
935      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
936      return 0;
937    }
938
939    if (range->ncprange_ip4addr.s_addr == INADDR_ANY) {
940      range->ncprange_ip4mask.s_addr = INADDR_ANY;
941      range->ncprange_ip4width = 0;
942    } else if (bits == -1) {
943      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
944      range->ncprange_ip4width = 32;
945    } else if (bits > 32) {
946      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
947      return 0;
948    } else {
949      range->ncprange_ip4mask = bits2mask4(bits);
950      range->ncprange_ip4width = bits;
951    }
952
953    return 1;
954#ifndef NOINET6
955  } else if (strchr(cp + 1, ':') != NULL) {
956    range->ncprange_family = AF_INET6;
957
958    if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) {
959      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
960      return 0;
961    }
962
963    if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
964      range->ncprange_ip6width = 0;
965    else
966      range->ncprange_ip6width = (bits == -1) ? 128 : bits;
967    return 1;
968#endif
969  }
970
971  return 0;
972}
973