ncpaddr.c revision 96732
181634Sbrian/*-
281634Sbrian * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
381634Sbrian * All rights reserved.
481634Sbrian *
581634Sbrian * Redistribution and use in source and binary forms, with or without
681634Sbrian * modification, are permitted provided that the following conditions
781634Sbrian * are met:
881634Sbrian * 1. Redistributions of source code must retain the above copyright
981634Sbrian *    notice, this list of conditions and the following disclaimer.
1081634Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1181634Sbrian *    notice, this list of conditions and the following disclaimer in the
1281634Sbrian *    documentation and/or other materials provided with the distribution.
1381634Sbrian *
1481634Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1581634Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1681634Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1781634Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1881634Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1981634Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2081634Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2181634Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2281634Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2381634Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2481634Sbrian * SUCH DAMAGE.
2581634Sbrian *
2681634Sbrian * $FreeBSD: head/usr.sbin/ppp/ncpaddr.c 96732 2002-05-16 14:47:19Z brian $
2781634Sbrian */
2881634Sbrian
2981634Sbrian#include <sys/types.h>
3081634Sbrian#include <sys/socket.h>
3196732Sbrian#ifdef __OpenBSD__
3296732Sbrian#include <net/if_types.h>
3396732Sbrian#include <net/route.h>
3496732Sbrian#endif
3581634Sbrian#include <netinet/in.h>
3681634Sbrian#include <netinet/in_systm.h>
3781634Sbrian#include <netinet/ip.h>
3881634Sbrian#include <arpa/inet.h>
3981634Sbrian#include <sys/un.h>
4081634Sbrian
4181634Sbrian#include <netdb.h>
4281634Sbrian#include <stdio.h>
4381634Sbrian#include <stdlib.h>
4481634Sbrian#include <string.h>
4581634Sbrian#include <termios.h>
4681634Sbrian
4781634Sbrian#include "log.h"
4881634Sbrian#include "ncpaddr.h"
4981634Sbrian#include "timer.h"
5081634Sbrian#include "fsm.h"
5181634Sbrian#include "defs.h"
5281634Sbrian#include "slcompress.h"
5381634Sbrian#include "iplist.h"
5481634Sbrian#include "throughput.h"
5581634Sbrian#include "mbuf.h"
5681634Sbrian#include "ipcp.h"
5781634Sbrian#include "descriptor.h"
5881634Sbrian#include "layer.h"
5981634Sbrian#include "lqr.h"
6081634Sbrian#include "hdlc.h"
6181634Sbrian#include "lcp.h"
6281634Sbrian#include "ccp.h"
6381634Sbrian#include "link.h"
6481634Sbrian#include "mp.h"
6581634Sbrian#include "ipv6cp.h"
6681634Sbrian#include "ncp.h"
6781634Sbrian
6881634Sbrian
6981634Sbrian#define ncprange_ip4addr	u.ip4.ipaddr
7081634Sbrian#define ncprange_ip4mask	u.ip4.mask
7181634Sbrian#define ncprange_ip4width	u.ip4.width
7281634Sbrian#define ncpaddr_ip4addr		u.ip4addr
7381634Sbrian#ifndef NOINET6
7481634Sbrian#define ncprange_ip6addr	u.ip6.ipaddr
7581634Sbrian#define ncprange_ip6width	u.ip6.width
7681634Sbrian#define ncpaddr_ip6addr		u.ip6addr
7781634Sbrian#endif
7881634Sbrian
7981634Sbrian#define	NCP_ASCIIBUFFERSIZE	52
8081634Sbrian
8181634Sbrianstatic struct in_addr
8281634Sbrianbits2mask4(int bits)
8381634Sbrian{
8481634Sbrian  struct in_addr result;
8581634Sbrian  u_int32_t bit = 0x80000000;
8681634Sbrian
8781634Sbrian  result.s_addr = 0;
8881634Sbrian
8981634Sbrian  while (bits) {
9081634Sbrian    result.s_addr |= bit;
9181634Sbrian    bit >>= 1;
9281634Sbrian    bits--;
9381634Sbrian  }
9481634Sbrian
9581634Sbrian  result.s_addr = htonl(result.s_addr);
9681634Sbrian  return result;
9781634Sbrian}
9881634Sbrian
9981634Sbrianstatic int
10081634Sbrianmask42bits(struct in_addr mask)
10181634Sbrian{
10281634Sbrian  u_int32_t msk = ntohl(mask.s_addr);
10381634Sbrian  u_int32_t tst;
10481634Sbrian  int ret;
10581634Sbrian
10681634Sbrian  for (ret = 32, tst = 1; tst; ret--, tst <<= 1)
10781634Sbrian    if (msk & tst)
10881634Sbrian      break;
10981634Sbrian
11081634Sbrian  for (tst <<= 1; tst; tst <<= 1)
11181634Sbrian    if (!(msk & tst))
11281634Sbrian      break;
11381634Sbrian
11481634Sbrian  return tst ? -1 : ret;
11581634Sbrian}
11681634Sbrian
11781634Sbrian#ifndef NOINET6
11881634Sbrianstatic struct in6_addr
11981634Sbrianbits2mask6(int bits)
12081634Sbrian{
12181634Sbrian  struct in6_addr result;
12281634Sbrian  u_int32_t bit = 0x80;
12381634Sbrian  u_char *c = result.s6_addr;
12481634Sbrian
12581634Sbrian  memset(&result, '\0', sizeof result);
12681634Sbrian
12781634Sbrian  while (bits) {
12881634Sbrian    if (bit == 0) {
12981634Sbrian      bit = 0x80;
13081634Sbrian      c++;
13181634Sbrian    }
13281634Sbrian    *c |= bit;
13381634Sbrian    bit >>= 1;
13481634Sbrian    bits--;
13581634Sbrian  }
13681634Sbrian
13781634Sbrian  return result;
13881634Sbrian}
13981634Sbrian
14081634Sbrianstatic int
14181634Sbrianmask62bits(const struct in6_addr *mask)
14281634Sbrian{
14381634Sbrian  const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
14481634Sbrian  const u_char *c, *p, *end;
14581634Sbrian  int masklen;
14681634Sbrian
14781634Sbrian  p = (const u_char *)mask;
14881634Sbrian  for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++)
14981634Sbrian    masklen += 8;
15081634Sbrian
15181634Sbrian  if (p < end) {
15281634Sbrian    for (c = masks; c < masks + sizeof masks; c++)
15381634Sbrian      if (*c == *p) {
15481634Sbrian        masklen += c - masks;
15581634Sbrian        break;
15681634Sbrian      }
15781634Sbrian  }
15881634Sbrian
15981634Sbrian  return masklen;
16081634Sbrian}
16181634Sbrian
16281634Sbrianstatic void
16381634Sbrianadjust_linklocal(struct sockaddr_in6 *sin6)
16481634Sbrian{
16581634Sbrian    /* XXX: ?????!?!?!!!!!  This is horrible ! */
16681634Sbrian    if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
16781634Sbrian        IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) {
16881634Sbrian      sin6->sin6_scope_id =
16981634Sbrian        ntohs(*(u_short *)&sin6->sin6_addr.s6_addr[2]);
17081634Sbrian      *(u_short *)&sin6->sin6_addr.s6_addr[2] = 0;
17181634Sbrian    }
17281634Sbrian}
17381634Sbrian#endif
17481634Sbrian
17581634Sbrianvoid
17681634Sbrianncpaddr_init(struct ncpaddr *addr)
17781634Sbrian{
17881634Sbrian  addr->ncpaddr_family = AF_UNSPEC;
17981634Sbrian}
18081634Sbrian
18181634Sbrianint
18281739Sbrianncpaddr_isset(const struct ncpaddr *addr)
18381739Sbrian{
18481739Sbrian  return addr->ncpaddr_family != AF_UNSPEC;
18581739Sbrian}
18681739Sbrian
18781739Sbrianint
18881634Sbrianncpaddr_isdefault(const struct ncpaddr *addr)
18981634Sbrian{
19081634Sbrian  switch (addr->ncpaddr_family) {
19181634Sbrian  case AF_INET:
19281634Sbrian    if (addr->ncpaddr_ip4addr.s_addr == INADDR_ANY)
19381634Sbrian      return 1;
19481634Sbrian    break;
19581634Sbrian
19681634Sbrian#ifndef NOINET6
19781634Sbrian  case AF_INET6:
19881634Sbrian    if (IN6_IS_ADDR_UNSPECIFIED(&addr->ncpaddr_ip6addr))
19981634Sbrian      return 1;
20081634Sbrian    break;
20181634Sbrian#endif
20281634Sbrian  }
20381634Sbrian
20481634Sbrian  return 0;
20581634Sbrian}
20681634Sbrian
20781634Sbrianint
20881634Sbrianncpaddr_equal(const struct ncpaddr *addr, const struct ncpaddr *cmp)
20981634Sbrian{
21081634Sbrian  if (addr->ncpaddr_family != cmp->ncpaddr_family)
21181634Sbrian    return 0;
21281634Sbrian
21381634Sbrian  switch (addr->ncpaddr_family) {
21481634Sbrian  case AF_INET:
21581634Sbrian    return addr->ncpaddr_ip4addr.s_addr == cmp->ncpaddr_ip4addr.s_addr;
21681634Sbrian
21781634Sbrian#ifndef NOINET6
21881634Sbrian  case AF_INET6:
21981634Sbrian    return !memcmp(&addr->ncpaddr_ip6addr, &cmp->ncpaddr_ip6addr,
22081634Sbrian                   sizeof addr->ncpaddr_ip6addr);
22181634Sbrian#endif
22281634Sbrian
22381634Sbrian  case AF_UNSPEC:
22481634Sbrian    return 1;
22581634Sbrian  }
22681634Sbrian
22781634Sbrian  return 0;
22881634Sbrian}
22981634Sbrian
23081634Sbrianvoid
23181634Sbrianncpaddr_copy(struct ncpaddr *addr, const struct ncpaddr *from)
23281634Sbrian{
23381634Sbrian  switch (from->ncpaddr_family) {
23481634Sbrian  case AF_INET:
23581634Sbrian    addr->ncpaddr_family = AF_INET;
23681634Sbrian    addr->ncpaddr_ip4addr = from->ncpaddr_ip4addr;
23781634Sbrian    break;
23881634Sbrian#ifndef NOINET6
23981634Sbrian  case AF_INET6:
24081634Sbrian    addr->ncpaddr_family = AF_INET6;
24181634Sbrian    addr->ncpaddr_ip6addr = from->ncpaddr_ip6addr;
24281634Sbrian    break;
24381634Sbrian#endif
24481634Sbrian  default:
24581634Sbrian    addr->ncpaddr_family = AF_UNSPEC;
24681634Sbrian  }
24781634Sbrian}
24881634Sbrian
24981634Sbrianvoid
25081634Sbrianncpaddr_setip4addr(struct ncpaddr *addr, u_int32_t ip)
25181634Sbrian{
25281634Sbrian  addr->ncpaddr_family = AF_INET;
25381634Sbrian  addr->ncpaddr_ip4addr.s_addr = ip;
25481634Sbrian}
25581634Sbrian
25681634Sbrianint
25781634Sbrianncpaddr_getip4addr(const struct ncpaddr *addr, u_int32_t *ip)
25881634Sbrian{
25981634Sbrian  if (addr->ncpaddr_family != AF_INET)
26081634Sbrian    return 0;
26181634Sbrian  *ip = addr->ncpaddr_ip4addr.s_addr;
26281634Sbrian  return 1;
26381634Sbrian}
26481634Sbrian
26581634Sbrianvoid
26681634Sbrianncpaddr_setip4(struct ncpaddr *addr, struct in_addr ip)
26781634Sbrian{
26881634Sbrian  addr->ncpaddr_family = AF_INET;
26981634Sbrian  addr->ncpaddr_ip4addr = ip;
27081634Sbrian}
27181634Sbrian
27281634Sbrianint
27381634Sbrianncpaddr_getip4(const struct ncpaddr *addr, struct in_addr *ip)
27481634Sbrian{
27581634Sbrian  if (addr->ncpaddr_family != AF_INET)
27681634Sbrian    return 0;
27781634Sbrian  *ip = addr->ncpaddr_ip4addr;
27881634Sbrian  return 1;
27981634Sbrian}
28081634Sbrian
28181634Sbrian#ifndef NOINET6
28281634Sbrianvoid
28381634Sbrianncpaddr_setip6(struct ncpaddr *addr, const struct in6_addr *ip6)
28481634Sbrian{
28581634Sbrian  addr->ncpaddr_family = AF_INET6;
28681634Sbrian  addr->ncpaddr_ip6addr = *ip6;
28781634Sbrian}
28881634Sbrian
28981634Sbrianint
29081634Sbrianncpaddr_getip6(const struct ncpaddr *addr, struct in6_addr *ip6)
29181634Sbrian{
29281634Sbrian  if (addr->ncpaddr_family != AF_INET6)
29381634Sbrian    return 0;
29481634Sbrian  *ip6 = addr->ncpaddr_ip6addr;
29581634Sbrian  return 1;
29681634Sbrian}
29781634Sbrian#endif
29881634Sbrian
29981634Sbrianvoid
30081634Sbrianncpaddr_getsa(const struct ncpaddr *addr, struct sockaddr_storage *host)
30181634Sbrian{
30281634Sbrian  struct sockaddr_in *host4 = (struct sockaddr_in *)host;
30381634Sbrian#ifndef NOINET6
30481634Sbrian  struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
30581634Sbrian#endif
30681634Sbrian
30781634Sbrian  memset(host, '\0', sizeof(*host));
30881634Sbrian
30981634Sbrian  switch (addr->ncpaddr_family) {
31081634Sbrian  case AF_INET:
31181634Sbrian    host4->sin_family = AF_INET;
31281634Sbrian    host4->sin_len = sizeof(*host4);
31381634Sbrian    host4->sin_addr = addr->ncpaddr_ip4addr;
31481634Sbrian    break;
31581634Sbrian
31681634Sbrian#ifndef NOINET6
31781634Sbrian  case AF_INET6:
31881634Sbrian    host6->sin6_family = AF_INET6;
31981634Sbrian    host6->sin6_len = sizeof(*host6);
32081634Sbrian    host6->sin6_addr = addr->ncpaddr_ip6addr;
32181634Sbrian    break;
32281634Sbrian#endif
32381634Sbrian
32481634Sbrian  default:
32581634Sbrian    host->ss_family = AF_UNSPEC;
32681634Sbrian    break;
32781634Sbrian  }
32881634Sbrian}
32981634Sbrian
33081634Sbrianvoid
33181634Sbrianncpaddr_setsa(struct ncpaddr *addr, const struct sockaddr *host)
33281634Sbrian{
33381634Sbrian  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
33481634Sbrian#ifndef NOINET6
33581634Sbrian  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
33681634Sbrian#endif
33781634Sbrian
33881634Sbrian  switch (host->sa_family) {
33981634Sbrian  case AF_INET:
34081634Sbrian    addr->ncpaddr_family = AF_INET;
34181634Sbrian    addr->ncpaddr_ip4addr = host4->sin_addr;
34281634Sbrian    break;
34381634Sbrian
34481634Sbrian#ifndef NOINET6
34581634Sbrian  case AF_INET6:
34681634Sbrian    if (IN6_IS_ADDR_V4MAPPED(&host6->sin6_addr)) {
34781634Sbrian      addr->ncpaddr_family = AF_INET;
34881634Sbrian      addr->ncpaddr_ip4addr.s_addr =
34981634Sbrian        *(const u_int32_t *)(host6->sin6_addr.s6_addr + 12);
35081634Sbrian    } else {
35181634Sbrian      addr->ncpaddr_family = AF_INET6;
35281634Sbrian      addr->ncpaddr_ip6addr = host6->sin6_addr;
35381634Sbrian    }
35481634Sbrian    break;
35581634Sbrian#endif
35681634Sbrian
35781634Sbrian  default:
35881634Sbrian    addr->ncpaddr_family = AF_UNSPEC;
35981634Sbrian  }
36081634Sbrian}
36181634Sbrian
36281634Sbrianstatic char *
36381634Sbrianncpaddr_ntowa(const struct ncpaddr *addr)
36481634Sbrian{
36581634Sbrian  static char res[NCP_ASCIIBUFFERSIZE];
36681634Sbrian#ifndef NOINET6
36781634Sbrian  struct sockaddr_in6 sin6;
36881634Sbrian#endif
36981634Sbrian
37081634Sbrian  switch (addr->ncpaddr_family) {
37181634Sbrian  case AF_INET:
37281634Sbrian    snprintf(res, sizeof res, "%s", inet_ntoa(addr->ncpaddr_ip4addr));
37381634Sbrian    return res;
37481634Sbrian
37581634Sbrian#ifndef NOINET6
37681634Sbrian  case AF_INET6:
37781634Sbrian    memset(&sin6, '\0', sizeof(sin6));
37881634Sbrian    sin6.sin6_len = sizeof(sin6);
37981634Sbrian    sin6.sin6_family = AF_INET6;
38081634Sbrian    sin6.sin6_addr = addr->ncpaddr_ip6addr;
38181634Sbrian    adjust_linklocal(&sin6);
38281634Sbrian    if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res),
38381634Sbrian                    NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST) != 0)
38481634Sbrian      break;
38581634Sbrian
38681634Sbrian    return res;
38781634Sbrian#endif
38881634Sbrian  }
38981634Sbrian
39081634Sbrian  snprintf(res, sizeof res, "<AF_UNSPEC>");
39181634Sbrian  return res;
39281634Sbrian}
39381634Sbrian
39481634Sbrianconst char *
39581634Sbrianncpaddr_ntoa(const struct ncpaddr *addr)
39681634Sbrian{
39781634Sbrian  return ncpaddr_ntowa(addr);
39881634Sbrian}
39981634Sbrian
40081634Sbrian
40181634Sbrianint
40281634Sbrianncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data)
40381634Sbrian{
40481634Sbrian  struct ncprange range;
40581634Sbrian
40681634Sbrian  if (!ncprange_aton(&range, ncp, data))
40781634Sbrian    return 0;
40881634Sbrian
40981634Sbrian  if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32) {
41081634Sbrian    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data);
41181634Sbrian    return 0;
41281634Sbrian  }
41381634Sbrian
41481634Sbrian#ifndef NOINET6
41581634Sbrian  if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128) {
41681634Sbrian    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data);
41781634Sbrian    return 0;
41881634Sbrian  }
41981634Sbrian#endif
42081634Sbrian
42181634Sbrian  switch (range.ncprange_family) {
42281634Sbrian  case AF_INET:
42381634Sbrian    addr->ncpaddr_family = range.ncprange_family;
42481634Sbrian    addr->ncpaddr_ip4addr = range.ncprange_ip4addr;
42581634Sbrian    return 1;
42681634Sbrian
42781634Sbrian#ifndef NOINET6
42881634Sbrian  case AF_INET6:
42981634Sbrian    addr->ncpaddr_family = range.ncprange_family;
43081634Sbrian    addr->ncpaddr_ip6addr = range.ncprange_ip6addr;
43181634Sbrian    return 1;
43281634Sbrian#endif
43381634Sbrian  }
43481634Sbrian
43581634Sbrian  return 0;
43681634Sbrian}
43781634Sbrian
43881634Sbrianvoid
43981634Sbrianncprange_init(struct ncprange *range)
44081634Sbrian{
44181634Sbrian  range->ncprange_family = AF_UNSPEC;
44281634Sbrian}
44381634Sbrian
44481634Sbrianint
44581634Sbrianncprange_isset(const struct ncprange *range)
44681634Sbrian{
44781634Sbrian  return range->ncprange_family != AF_UNSPEC;
44881634Sbrian}
44981634Sbrian
45081634Sbrianint
45181634Sbrianncprange_equal(const struct ncprange *range, const struct ncprange *cmp)
45281634Sbrian{
45381634Sbrian  if (range->ncprange_family != cmp->ncprange_family)
45481634Sbrian    return 0;
45581634Sbrian
45681634Sbrian  switch (range->ncprange_family) {
45781634Sbrian  case AF_INET:
45881634Sbrian    if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr)
45981634Sbrian      return 0;
46081634Sbrian    return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr;
46181634Sbrian
46281634Sbrian#ifndef NOINET6
46381634Sbrian  case AF_INET6:
46481634Sbrian    if (range->ncprange_ip6width != cmp->ncprange_ip6width)
46581634Sbrian      return 0;
46681634Sbrian    return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr,
46781634Sbrian                   sizeof range->ncprange_ip6addr);
46881634Sbrian#endif
46981634Sbrian
47081634Sbrian  case AF_UNSPEC:
47181634Sbrian    return 1;
47281634Sbrian  }
47381634Sbrian
47481634Sbrian  return 0;
47581634Sbrian}
47681634Sbrian
47781634Sbrianint
47881634Sbrianncprange_isdefault(const struct ncprange *range)
47981634Sbrian{
48081634Sbrian  switch (range->ncprange_family) {
48181634Sbrian  case AF_INET:
48281634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_ANY)
48381634Sbrian      return 1;
48481634Sbrian    break;
48581634Sbrian
48681634Sbrian#ifndef NOINET6
48781634Sbrian  case AF_INET6:
48881634Sbrian    if (range->ncprange_ip6width == 0 &&
48981634Sbrian        IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
49081634Sbrian      return 1;
49181634Sbrian    break;
49281634Sbrian#endif
49381634Sbrian  }
49481634Sbrian
49581634Sbrian  return 0;
49681634Sbrian}
49781634Sbrian
49881634Sbrianvoid
49981634Sbrianncprange_setdefault(struct ncprange *range, int af)
50081634Sbrian{
50181634Sbrian  memset(range, '\0', sizeof *range);
50281634Sbrian  range->ncprange_family = af;
50381634Sbrian}
50481634Sbrian
50581634Sbrianint
50681634Sbrianncprange_contains(const struct ncprange *range, const struct ncpaddr *addr)
50781634Sbrian{
50881634Sbrian#ifndef NOINET6
50981634Sbrian  const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
51081634Sbrian  const u_char *addrp, *rangep;
51181634Sbrian  int bits;
51281634Sbrian#endif
51381634Sbrian
51481634Sbrian  if (range->ncprange_family != addr->ncpaddr_family)
51581634Sbrian    return 0;
51681634Sbrian
51781634Sbrian  switch (range->ncprange_family) {
51881634Sbrian  case AF_INET:
51981634Sbrian    return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
52081634Sbrian             range->ncprange_ip4mask.s_addr);
52181634Sbrian
52281634Sbrian#ifndef NOINET6
52381634Sbrian  case AF_INET6:
52481634Sbrian    rangep = (const u_char *)range->ncprange_ip6addr.s6_addr;
52581634Sbrian    addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr;
52681634Sbrian
52781634Sbrian    for (bits = range->ncprange_ip6width; bits > 0; bits -= 8)
52881634Sbrian      if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1])
52981634Sbrian        return 0;
53081634Sbrian
53181634Sbrian    return 1;
53281634Sbrian#endif
53381634Sbrian  }
53481634Sbrian
53581634Sbrian  return 0;
53681634Sbrian}
53781634Sbrian
53881634Sbrianint
53981634Sbrianncprange_containsip4(const struct ncprange *range, struct in_addr addr)
54081634Sbrian{
54181634Sbrian  switch (range->ncprange_family) {
54281634Sbrian  case AF_INET:
54381634Sbrian    return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
54481634Sbrian             range->ncprange_ip4mask.s_addr);
54581634Sbrian  }
54681634Sbrian
54781634Sbrian  return 0;
54881634Sbrian}
54981634Sbrian
55081634Sbrianvoid
55181634Sbrianncprange_copy(struct ncprange *range, const struct ncprange *from)
55281634Sbrian{
55381634Sbrian  switch (from->ncprange_family) {
55481634Sbrian  case AF_INET:
55581634Sbrian    range->ncprange_family = AF_INET;
55681634Sbrian    range->ncprange_ip4addr = from->ncprange_ip4addr;
55781634Sbrian    range->ncprange_ip4mask = from->ncprange_ip4mask;
55881634Sbrian    range->ncprange_ip4width = from->ncprange_ip4width;
55981634Sbrian    break;
56081634Sbrian
56181634Sbrian#ifndef NOINET6
56281634Sbrian  case AF_INET6:
56381634Sbrian    range->ncprange_family = AF_INET6;
56481634Sbrian    range->ncprange_ip6addr = from->ncprange_ip6addr;
56581634Sbrian    range->ncprange_ip6width = from->ncprange_ip6width;
56681634Sbrian    break;
56781634Sbrian#endif
56881634Sbrian
56981634Sbrian  default:
57081634Sbrian    range->ncprange_family = AF_UNSPEC;
57181634Sbrian  }
57281634Sbrian}
57381634Sbrian
57481634Sbrianvoid
57581634Sbrianncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width)
57681634Sbrian{
57781634Sbrian  ncprange_sethost(range, addr);
57881634Sbrian  ncprange_setwidth(range, width);
57981634Sbrian}
58081634Sbrian
58181634Sbrianvoid
58281634Sbrianncprange_sethost(struct ncprange *range, const struct ncpaddr *from)
58381634Sbrian{
58481634Sbrian  switch (from->ncpaddr_family) {
58581634Sbrian  case AF_INET:
58681634Sbrian    range->ncprange_family = AF_INET;
58781634Sbrian    range->ncprange_ip4addr = from->ncpaddr_ip4addr;
58886832Sbrian    if (from->ncpaddr_ip4addr.s_addr == INADDR_ANY) {
58986832Sbrian      range->ncprange_ip4mask.s_addr = INADDR_ANY;
59086832Sbrian      range->ncprange_ip4width = 0;
59186832Sbrian    } else {
59286832Sbrian      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
59386832Sbrian      range->ncprange_ip4width = 32;
59486832Sbrian    }
59581634Sbrian    break;
59681634Sbrian
59781634Sbrian#ifndef NOINET6
59881634Sbrian  case AF_INET6:
59981634Sbrian    range->ncprange_family = AF_INET6;
60081634Sbrian    range->ncprange_ip6addr = from->ncpaddr_ip6addr;
60181634Sbrian    range->ncprange_ip6width = 128;
60281634Sbrian    break;
60381634Sbrian#endif
60481634Sbrian
60581634Sbrian  default:
60681634Sbrian    range->ncprange_family = AF_UNSPEC;
60781634Sbrian  }
60881634Sbrian}
60981634Sbrian
61081634Sbrianint
61186815Sbrianncprange_ishost(const struct ncprange *range)
61286815Sbrian{
61386815Sbrian  switch (range->ncprange_family) {
61486815Sbrian  case AF_INET:
61586815Sbrian    return range->ncprange_ip4width == 32;
61686815Sbrian#ifndef NOINET6
61786815Sbrian  case AF_INET6:
61886815Sbrian    return range->ncprange_ip6width == 128;
61986815Sbrian#endif
62086815Sbrian  }
62186815Sbrian
62286815Sbrian  return (0);
62386815Sbrian}
62486815Sbrian
62586815Sbrianint
62681634Sbrianncprange_setwidth(struct ncprange *range, int width)
62781634Sbrian{
62881634Sbrian  switch (range->ncprange_family) {
62981634Sbrian  case AF_INET:
63081634Sbrian    if (width < 0 || width > 32)
63181634Sbrian      break;
63281634Sbrian    range->ncprange_ip4width = width;
63381634Sbrian    range->ncprange_ip4mask = bits2mask4(width);
63481634Sbrian    break;
63581634Sbrian
63681634Sbrian#ifndef NOINET6
63781634Sbrian  case AF_INET6:
63881634Sbrian    if (width < 0 || width > 128)
63981634Sbrian      break;
64081634Sbrian    range->ncprange_ip6width = width;
64181634Sbrian    break;
64281634Sbrian#endif
64381634Sbrian
64481634Sbrian  case AF_UNSPEC:
64581634Sbrian    return 1;
64681634Sbrian  }
64781634Sbrian
64881634Sbrian  return 0;
64981634Sbrian}
65081634Sbrian
65181634Sbrianvoid
65281634Sbrianncprange_setip4host(struct ncprange *range, struct in_addr from)
65381634Sbrian{
65481634Sbrian  range->ncprange_family = AF_INET;
65581634Sbrian  range->ncprange_ip4addr = from;
65686832Sbrian  if (from.s_addr == INADDR_ANY) {
65786832Sbrian    range->ncprange_ip4mask.s_addr = INADDR_ANY;
65886832Sbrian    range->ncprange_ip4width = 0;
65986832Sbrian  } else {
66086832Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
66186832Sbrian    range->ncprange_ip4width = 32;
66286832Sbrian  }
66381634Sbrian}
66481634Sbrian
66581634Sbrianvoid
66681634Sbrianncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk)
66781634Sbrian{
66881634Sbrian  range->ncprange_family = AF_INET;
66981634Sbrian  range->ncprange_ip4addr = from;
67081634Sbrian  range->ncprange_ip4mask = msk;
67181634Sbrian  range->ncprange_ip4width = mask42bits(msk);
67281634Sbrian}
67381634Sbrian
67481634Sbrian
67581634Sbrianint
67681634Sbrianncprange_setip4mask(struct ncprange *range, struct in_addr mask)
67781634Sbrian{
67881634Sbrian  if (range->ncprange_family != AF_INET)
67981634Sbrian    return 0;
68081634Sbrian  range->ncprange_ip4mask = mask;
68181634Sbrian  range->ncprange_ip4width = mask42bits(mask);
68281634Sbrian  return 1;
68381634Sbrian}
68481634Sbrian
68581634Sbrianvoid
68681634Sbrianncprange_setsa(struct ncprange *range, const struct sockaddr *host,
68781634Sbrian               const struct sockaddr *mask)
68881634Sbrian{
68981634Sbrian  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
69081634Sbrian  const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask;
69181634Sbrian#ifndef NOINET6
69281634Sbrian  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
69381634Sbrian  const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask;
69481634Sbrian#endif
69581634Sbrian
69681634Sbrian  switch (host->sa_family) {
69781634Sbrian  case AF_INET:
69881634Sbrian    range->ncprange_family = AF_INET;
69981634Sbrian    range->ncprange_ip4addr = host4->sin_addr;
70086832Sbrian    if (host4->sin_addr.s_addr == INADDR_ANY) {
70186832Sbrian      range->ncprange_ip4mask.s_addr = INADDR_ANY;
70286832Sbrian      range->ncprange_ip4width = 0;
70386832Sbrian    } else if (mask4 && mask4->sin_family == AF_INET) {
70481634Sbrian      range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr;
70581634Sbrian      range->ncprange_ip4width = mask42bits(mask4->sin_addr);
70681634Sbrian    } else {
70781634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
70881634Sbrian      range->ncprange_ip4width = 32;
70981634Sbrian    }
71081634Sbrian    break;
71181634Sbrian
71281634Sbrian#ifndef NOINET6
71381634Sbrian  case AF_INET6:
71481634Sbrian    range->ncprange_family = AF_INET6;
71581634Sbrian    range->ncprange_ip6addr = host6->sin6_addr;
71681634Sbrian    range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128;
71781634Sbrian    break;
71881634Sbrian#endif
71981634Sbrian
72081634Sbrian  default:
72181634Sbrian    range->ncprange_family = AF_UNSPEC;
72281634Sbrian  }
72381634Sbrian}
72481634Sbrian
72581634Sbrianvoid
72681634Sbrianncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host,
72781634Sbrian               struct sockaddr_storage *mask)
72881634Sbrian{
72981634Sbrian  struct sockaddr_in *host4 = (struct sockaddr_in *)host;
73081634Sbrian  struct sockaddr_in *mask4 = (struct sockaddr_in *)mask;
73181634Sbrian#ifndef NOINET6
73281634Sbrian  struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
73381634Sbrian  struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask;
73481634Sbrian#endif
73581634Sbrian
73681634Sbrian  memset(host, '\0', sizeof(*host));
73781634Sbrian  if (mask)
73881634Sbrian    memset(mask, '\0', sizeof(*mask));
73981634Sbrian
74081634Sbrian  switch (range->ncprange_family) {
74181634Sbrian  case AF_INET:
74281634Sbrian    host4->sin_family = AF_INET;
74381634Sbrian    host4->sin_len = sizeof(*host4);
74481634Sbrian    host4->sin_addr = range->ncprange_ip4addr;
74581634Sbrian    if (mask4) {
74681634Sbrian      mask4->sin_family = AF_INET;
74781634Sbrian      mask4->sin_len = sizeof(*host4);
74881690Sbrian      mask4->sin_addr = range->ncprange_ip4mask;
74981634Sbrian    }
75081634Sbrian    break;
75181634Sbrian
75281634Sbrian#ifndef NOINET6
75381634Sbrian  case AF_INET6:
75481634Sbrian    host6->sin6_family = AF_INET6;
75581634Sbrian    host6->sin6_len = sizeof(*host6);
75681634Sbrian    host6->sin6_addr = range->ncprange_ip6addr;
75781634Sbrian    if (mask6) {
75881634Sbrian      mask6->sin6_family = AF_INET6;
75981634Sbrian      mask6->sin6_len = sizeof(*host6);
76081634Sbrian      mask6->sin6_addr = bits2mask6(range->ncprange_ip6width);
76181634Sbrian    }
76281634Sbrian    break;
76381634Sbrian#endif
76481634Sbrian
76581634Sbrian  default:
76681634Sbrian    host->ss_family = AF_UNSPEC;
76781634Sbrian    if (mask)
76881634Sbrian      mask->ss_family = AF_UNSPEC;
76981634Sbrian    break;
77081634Sbrian  }
77181634Sbrian}
77281634Sbrian
77381634Sbrianint
77481634Sbrianncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr)
77581634Sbrian{
77681634Sbrian  switch (range->ncprange_family) {
77781634Sbrian  case AF_INET:
77881634Sbrian    addr->ncpaddr_family = AF_INET;
77981634Sbrian    addr->ncpaddr_ip4addr = range->ncprange_ip4addr;
78081634Sbrian    return 1;
78181634Sbrian#ifndef NOINET6
78281634Sbrian  case AF_INET6:
78381634Sbrian    addr->ncpaddr_family = AF_INET6;
78481634Sbrian    addr->ncpaddr_ip6addr =  range->ncprange_ip6addr;
78581634Sbrian    return 1;
78681634Sbrian#endif
78781634Sbrian  }
78881634Sbrian
78981634Sbrian  return 0;
79081634Sbrian}
79181634Sbrian
79281634Sbrianint
79381634Sbrianncprange_getip4addr(const struct ncprange *range, struct in_addr *addr)
79481634Sbrian{
79581634Sbrian  if (range->ncprange_family != AF_INET)
79681634Sbrian    return 0;
79781634Sbrian
79881634Sbrian  *addr = range->ncprange_ip4addr;
79981634Sbrian  return 1;
80081634Sbrian}
80181634Sbrian
80281634Sbrianint
80381634Sbrianncprange_getip4mask(const struct ncprange *range, struct in_addr *mask)
80481634Sbrian{
80581634Sbrian  switch (range->ncprange_family) {
80681634Sbrian  case AF_INET:
80781634Sbrian    *mask = range->ncprange_ip4mask;
80881634Sbrian    return 1;
80981634Sbrian  }
81081634Sbrian
81181634Sbrian  return 0;
81281634Sbrian}
81381634Sbrian
81481634Sbrianint
81581634Sbrianncprange_getwidth(const struct ncprange *range, int *width)
81681634Sbrian{
81781634Sbrian  switch (range->ncprange_family) {
81881634Sbrian  case AF_INET:
81981634Sbrian    *width = range->ncprange_ip4width;
82081634Sbrian    return 1;
82181634Sbrian#ifndef NOINET6
82281634Sbrian  case AF_INET6:
82381634Sbrian    *width = range->ncprange_ip6width;
82481634Sbrian    return 1;
82581634Sbrian#endif
82681634Sbrian  }
82781634Sbrian
82881634Sbrian  return 0;
82981634Sbrian}
83081634Sbrian
83181634Sbrianconst char *
83281634Sbrianncprange_ntoa(const struct ncprange *range)
83381634Sbrian{
83481634Sbrian  char *res;
83581634Sbrian  struct ncpaddr addr;
83681634Sbrian  int len;
83781634Sbrian
83881634Sbrian  if (!ncprange_getaddr(range, &addr))
83981634Sbrian    return "<AF_UNSPEC>";
84081634Sbrian
84181634Sbrian  res = ncpaddr_ntowa(&addr);
84281634Sbrian  len = strlen(res);
84381634Sbrian  if (len >= NCP_ASCIIBUFFERSIZE - 1)
84481634Sbrian    return res;
84581634Sbrian
84681634Sbrian  switch (range->ncprange_family) {
84781634Sbrian  case AF_INET:
84881634Sbrian    if (range->ncprange_ip4width == -1) {
84981634Sbrian      /* A non-contiguous mask */
85081634Sbrian      for (; len >= 3; res[len -= 2] = '\0')
85181634Sbrian        if (strcmp(res + len - 2, ".0"))
85281634Sbrian          break;
85381634Sbrian      snprintf(res + len, sizeof res - len, "&0x%08lx",
85481924Sbrian               (unsigned long)ntohl(range->ncprange_ip4mask.s_addr));
85581634Sbrian    } else if (range->ncprange_ip4width < 32)
85681634Sbrian      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width);
85781634Sbrian
85881634Sbrian    return res;
85981634Sbrian
86081634Sbrian#ifndef NOINET6
86181634Sbrian  case AF_INET6:
86281634Sbrian    if (range->ncprange_ip6width != 128)
86381634Sbrian      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width);
86481634Sbrian
86581634Sbrian    return res;
86681634Sbrian#endif
86781634Sbrian  }
86881634Sbrian
86981634Sbrian  return "<AF_UNSPEC>";
87081634Sbrian}
87181634Sbrian
87281634Sbrian#ifndef NOINET6
87381634Sbrianint
87481634Sbrianncprange_scopeid(const struct ncprange *range)
87581634Sbrian{
87681634Sbrian  const struct in6_addr *sin6;
87781634Sbrian  int scopeid = -1;
87881634Sbrian
87981634Sbrian  if (range->ncprange_family == AF_INET6) {
88081634Sbrian    sin6 = &range->ncprange_ip6addr;
88181634Sbrian    if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6))
88281634Sbrian      if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0)
88381634Sbrian        scopeid = -1;
88481634Sbrian  }
88581634Sbrian
88681634Sbrian  return scopeid;
88781634Sbrian}
88881634Sbrian#endif
88981634Sbrian
89081634Sbrianint
89181634Sbrianncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data)
89281634Sbrian{
89381634Sbrian  int bits, len;
89481634Sbrian  char *wp;
89581634Sbrian  const char *cp;
89681634Sbrian  char *s;
89781634Sbrian
89881634Sbrian  len = strcspn(data, "/");
89981634Sbrian
90081634Sbrian  if (ncp && strncasecmp(data, "HISADDR", len) == 0) {
90181634Sbrian    range->ncprange_family = AF_INET;
90281634Sbrian    range->ncprange_ip4addr = ncp->ipcp.peer_ip;
90381634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
90481634Sbrian    range->ncprange_ip4width = 32;
90581634Sbrian    return 1;
90681634Sbrian#ifndef NOINET6
90781634Sbrian  } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) {
90881634Sbrian    ncprange_sethost(range, &ncp->ipv6cp.hisaddr);
90981634Sbrian    return 1;
91081634Sbrian#endif
91181634Sbrian  } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) {
91281634Sbrian    range->ncprange_family = AF_INET;
91381634Sbrian    range->ncprange_ip4addr = ncp->ipcp.my_ip;
91481634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
91581634Sbrian    range->ncprange_ip4width = 32;
91681634Sbrian    return 1;
91781634Sbrian#ifndef NOINET6
91881634Sbrian  } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) {
91981634Sbrian    ncprange_sethost(range, &ncp->ipv6cp.myaddr);
92081634Sbrian    return 1;
92181634Sbrian#endif
92281634Sbrian  } else if (ncp && strncasecmp(data, "DNS0", len) == 0) {
92381634Sbrian    range->ncprange_family = AF_INET;
92481634Sbrian    range->ncprange_ip4addr = ncp->ipcp.ns.dns[0];
92581634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
92681634Sbrian    range->ncprange_ip4width = 32;
92781634Sbrian    return 1;
92881634Sbrian  } else if (ncp && strncasecmp(data, "DNS1", len) == 0) {
92981634Sbrian    range->ncprange_family = AF_INET;
93081634Sbrian    range->ncprange_ip4addr = ncp->ipcp.ns.dns[1];
93181634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
93281634Sbrian    range->ncprange_ip4width = 32;
93381634Sbrian    return 1;
93481634Sbrian  }
93581634Sbrian
93681634Sbrian  s = (char *)alloca(len + 1);
93781634Sbrian  strncpy(s, data, len);
93881634Sbrian  s[len] = '\0';
93981634Sbrian  bits = -1;
94081634Sbrian
94181634Sbrian  if (data[len] != '\0') {
94281634Sbrian    bits = strtol(data + len + 1, &wp, 0);
94381634Sbrian    if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) {
94481634Sbrian      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
94581634Sbrian      return 0;
94681634Sbrian    }
94781634Sbrian  }
94881634Sbrian
94981634Sbrian  if ((cp = strchr(data, ':')) == NULL) {
95081634Sbrian    range->ncprange_family = AF_INET;
95181634Sbrian
95281634Sbrian    range->ncprange_ip4addr = GetIpAddr(s);
95381634Sbrian
95481634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_NONE) {
95581634Sbrian      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
95681634Sbrian      return 0;
95781634Sbrian    }
95881634Sbrian
95981634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_ANY) {
96081634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_ANY;
96181634Sbrian      range->ncprange_ip4width = 0;
96281690Sbrian    } else if (bits == -1) {
96381634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
96481634Sbrian      range->ncprange_ip4width = 32;
96581690Sbrian    } else if (bits > 32) {
96681690Sbrian      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
96781690Sbrian      return 0;
96881634Sbrian    } else {
96981634Sbrian      range->ncprange_ip4mask = bits2mask4(bits);
97081634Sbrian      range->ncprange_ip4width = bits;
97181634Sbrian    }
97281634Sbrian
97381634Sbrian    return 1;
97481634Sbrian#ifndef NOINET6
97581634Sbrian  } else if (strchr(cp + 1, ':') != NULL) {
97681634Sbrian    range->ncprange_family = AF_INET6;
97781634Sbrian
97881634Sbrian    if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) {
97981634Sbrian      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
98081634Sbrian      return 0;
98181634Sbrian    }
98281634Sbrian
98381634Sbrian    if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
98481634Sbrian      range->ncprange_ip6width = 0;
98581634Sbrian    else
98681634Sbrian      range->ncprange_ip6width = (bits == -1) ? 128 : bits;
98781634Sbrian    return 1;
98881634Sbrian#endif
98981634Sbrian  }
99081634Sbrian
99181634Sbrian  return 0;
99281634Sbrian}
993