ncpaddr.c revision 81739
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 81739 2001-08-16 02:01:05Z brian $
2781634Sbrian */
2881634Sbrian
2981634Sbrian#include <sys/types.h>
3081634Sbrian#include <sys/socket.h>
3181634Sbrian#include <net/if_types.h>
3281634Sbrian#include <net/route.h>
3381634Sbrian#include <netinet/in.h>
3481634Sbrian#include <netinet/in_systm.h>
3581634Sbrian#include <netinet/ip.h>
3681634Sbrian#include <arpa/inet.h>
3781634Sbrian#include <sys/un.h>
3881634Sbrian
3981634Sbrian#include <limits.h>
4081634Sbrian#include <netdb.h>
4181634Sbrian#include <stdio.h>
4281634Sbrian#include <stdlib.h>
4381634Sbrian#include <string.h>
4481634Sbrian#include <termios.h>
4581634Sbrian
4681634Sbrian#include "log.h"
4781634Sbrian#include "ncpaddr.h"
4881634Sbrian#include "timer.h"
4981634Sbrian#include "fsm.h"
5081634Sbrian#include "defs.h"
5181634Sbrian#include "slcompress.h"
5281634Sbrian#include "iplist.h"
5381634Sbrian#include "throughput.h"
5481634Sbrian#include "mbuf.h"
5581634Sbrian#include "ip.h"
5681634Sbrian#include "ipcp.h"
5781634Sbrian#include "filter.h"
5881634Sbrian#include "descriptor.h"
5981634Sbrian#include "route.h"
6081634Sbrian#include "layer.h"
6181634Sbrian#include "lqr.h"
6281634Sbrian#include "hdlc.h"
6381634Sbrian#include "lcp.h"
6481634Sbrian#include "ccp.h"
6581634Sbrian#include "link.h"
6681634Sbrian#include "mp.h"
6781634Sbrian#ifndef NORADIUS
6881634Sbrian#include "radius.h"
6981634Sbrian#endif
7081634Sbrian#include "ipv6cp.h"
7181634Sbrian#include "ncp.h"
7281634Sbrian#include "bundle.h"
7381634Sbrian
7481634Sbrian
7581634Sbrian#define ncprange_ip4addr	u.ip4.ipaddr
7681634Sbrian#define ncprange_ip4mask	u.ip4.mask
7781634Sbrian#define ncprange_ip4width	u.ip4.width
7881634Sbrian#define ncpaddr_ip4addr		u.ip4addr
7981634Sbrian#ifndef NOINET6
8081634Sbrian#define ncprange_ip6addr	u.ip6.ipaddr
8181634Sbrian#define ncprange_ip6width	u.ip6.width
8281634Sbrian#define ncpaddr_ip6addr		u.ip6addr
8381634Sbrian#endif
8481634Sbrian
8581634Sbrian#define	NCP_ASCIIBUFFERSIZE	52
8681634Sbrian
8781634Sbrianstatic struct in_addr
8881634Sbrianbits2mask4(int bits)
8981634Sbrian{
9081634Sbrian  struct in_addr result;
9181634Sbrian  u_int32_t bit = 0x80000000;
9281634Sbrian
9381634Sbrian  result.s_addr = 0;
9481634Sbrian
9581634Sbrian  while (bits) {
9681634Sbrian    result.s_addr |= bit;
9781634Sbrian    bit >>= 1;
9881634Sbrian    bits--;
9981634Sbrian  }
10081634Sbrian
10181634Sbrian  result.s_addr = htonl(result.s_addr);
10281634Sbrian  return result;
10381634Sbrian}
10481634Sbrian
10581634Sbrianstatic int
10681634Sbrianmask42bits(struct in_addr mask)
10781634Sbrian{
10881634Sbrian  u_int32_t msk = ntohl(mask.s_addr);
10981634Sbrian  u_int32_t tst;
11081634Sbrian  int ret;
11181634Sbrian
11281634Sbrian  for (ret = 32, tst = 1; tst; ret--, tst <<= 1)
11381634Sbrian    if (msk & tst)
11481634Sbrian      break;
11581634Sbrian
11681634Sbrian  for (tst <<= 1; tst; tst <<= 1)
11781634Sbrian    if (!(msk & tst))
11881634Sbrian      break;
11981634Sbrian
12081634Sbrian  return tst ? -1 : ret;
12181634Sbrian}
12281634Sbrian
12381634Sbrian#ifndef NOINET6
12481634Sbrianstatic struct in6_addr
12581634Sbrianbits2mask6(int bits)
12681634Sbrian{
12781634Sbrian  struct in6_addr result;
12881634Sbrian  u_int32_t bit = 0x80;
12981634Sbrian  u_char *c = result.s6_addr;
13081634Sbrian
13181634Sbrian  memset(&result, '\0', sizeof result);
13281634Sbrian
13381634Sbrian  while (bits) {
13481634Sbrian    if (bit == 0) {
13581634Sbrian      bit = 0x80;
13681634Sbrian      c++;
13781634Sbrian    }
13881634Sbrian    *c |= bit;
13981634Sbrian    bit >>= 1;
14081634Sbrian    bits--;
14181634Sbrian  }
14281634Sbrian
14381634Sbrian  return result;
14481634Sbrian}
14581634Sbrian
14681634Sbrianstatic int
14781634Sbrianmask62bits(const struct in6_addr *mask)
14881634Sbrian{
14981634Sbrian  const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
15081634Sbrian  const u_char *c, *p, *end;
15181634Sbrian  int masklen;
15281634Sbrian
15381634Sbrian  p = (const u_char *)mask;
15481634Sbrian  for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++)
15581634Sbrian    masklen += 8;
15681634Sbrian
15781634Sbrian  if (p < end) {
15881634Sbrian    for (c = masks; c < masks + sizeof masks; c++)
15981634Sbrian      if (*c == *p) {
16081634Sbrian        masklen += c - masks;
16181634Sbrian        break;
16281634Sbrian      }
16381634Sbrian  }
16481634Sbrian
16581634Sbrian  return masklen;
16681634Sbrian}
16781634Sbrian
16881634Sbrianstatic void
16981634Sbrianadjust_linklocal(struct sockaddr_in6 *sin6)
17081634Sbrian{
17181634Sbrian    /* XXX: ?????!?!?!!!!!  This is horrible ! */
17281634Sbrian    if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
17381634Sbrian        IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) {
17481634Sbrian      sin6->sin6_scope_id =
17581634Sbrian        ntohs(*(u_short *)&sin6->sin6_addr.s6_addr[2]);
17681634Sbrian      *(u_short *)&sin6->sin6_addr.s6_addr[2] = 0;
17781634Sbrian    }
17881634Sbrian}
17981634Sbrian#endif
18081634Sbrian
18181634Sbrianvoid
18281634Sbrianncpaddr_init(struct ncpaddr *addr)
18381634Sbrian{
18481634Sbrian  addr->ncpaddr_family = AF_UNSPEC;
18581634Sbrian}
18681634Sbrian
18781634Sbrianint
18881739Sbrianncpaddr_isset(const struct ncpaddr *addr)
18981739Sbrian{
19081739Sbrian  return addr->ncpaddr_family != AF_UNSPEC;
19181739Sbrian}
19281739Sbrian
19381739Sbrianint
19481634Sbrianncpaddr_isdefault(const struct ncpaddr *addr)
19581634Sbrian{
19681634Sbrian  switch (addr->ncpaddr_family) {
19781634Sbrian  case AF_INET:
19881634Sbrian    if (addr->ncpaddr_ip4addr.s_addr == INADDR_ANY)
19981634Sbrian      return 1;
20081634Sbrian    break;
20181634Sbrian
20281634Sbrian#ifndef NOINET6
20381634Sbrian  case AF_INET6:
20481634Sbrian    if (IN6_IS_ADDR_UNSPECIFIED(&addr->ncpaddr_ip6addr))
20581634Sbrian      return 1;
20681634Sbrian    break;
20781634Sbrian#endif
20881634Sbrian  }
20981634Sbrian
21081634Sbrian  return 0;
21181634Sbrian}
21281634Sbrian
21381634Sbrianint
21481634Sbrianncpaddr_equal(const struct ncpaddr *addr, const struct ncpaddr *cmp)
21581634Sbrian{
21681634Sbrian  if (addr->ncpaddr_family != cmp->ncpaddr_family)
21781634Sbrian    return 0;
21881634Sbrian
21981634Sbrian  switch (addr->ncpaddr_family) {
22081634Sbrian  case AF_INET:
22181634Sbrian    return addr->ncpaddr_ip4addr.s_addr == cmp->ncpaddr_ip4addr.s_addr;
22281634Sbrian
22381634Sbrian#ifndef NOINET6
22481634Sbrian  case AF_INET6:
22581634Sbrian    return !memcmp(&addr->ncpaddr_ip6addr, &cmp->ncpaddr_ip6addr,
22681634Sbrian                   sizeof addr->ncpaddr_ip6addr);
22781634Sbrian#endif
22881634Sbrian
22981634Sbrian  case AF_UNSPEC:
23081634Sbrian    return 1;
23181634Sbrian  }
23281634Sbrian
23381634Sbrian  return 0;
23481634Sbrian}
23581634Sbrian
23681634Sbrianvoid
23781634Sbrianncpaddr_copy(struct ncpaddr *addr, const struct ncpaddr *from)
23881634Sbrian{
23981634Sbrian  switch (from->ncpaddr_family) {
24081634Sbrian  case AF_INET:
24181634Sbrian    addr->ncpaddr_family = AF_INET;
24281634Sbrian    addr->ncpaddr_ip4addr = from->ncpaddr_ip4addr;
24381634Sbrian    break;
24481634Sbrian#ifndef NOINET6
24581634Sbrian  case AF_INET6:
24681634Sbrian    addr->ncpaddr_family = AF_INET6;
24781634Sbrian    addr->ncpaddr_ip6addr = from->ncpaddr_ip6addr;
24881634Sbrian    break;
24981634Sbrian#endif
25081634Sbrian  default:
25181634Sbrian    addr->ncpaddr_family = AF_UNSPEC;
25281634Sbrian  }
25381634Sbrian}
25481634Sbrian
25581634Sbrianvoid
25681634Sbrianncpaddr_setip4addr(struct ncpaddr *addr, u_int32_t ip)
25781634Sbrian{
25881634Sbrian  addr->ncpaddr_family = AF_INET;
25981634Sbrian  addr->ncpaddr_ip4addr.s_addr = ip;
26081634Sbrian}
26181634Sbrian
26281634Sbrianint
26381634Sbrianncpaddr_getip4addr(const struct ncpaddr *addr, u_int32_t *ip)
26481634Sbrian{
26581634Sbrian  if (addr->ncpaddr_family != AF_INET)
26681634Sbrian    return 0;
26781634Sbrian  *ip = addr->ncpaddr_ip4addr.s_addr;
26881634Sbrian  return 1;
26981634Sbrian}
27081634Sbrian
27181634Sbrianvoid
27281634Sbrianncpaddr_setip4(struct ncpaddr *addr, struct in_addr ip)
27381634Sbrian{
27481634Sbrian  addr->ncpaddr_family = AF_INET;
27581634Sbrian  addr->ncpaddr_ip4addr = ip;
27681634Sbrian}
27781634Sbrian
27881634Sbrianint
27981634Sbrianncpaddr_getip4(const struct ncpaddr *addr, struct in_addr *ip)
28081634Sbrian{
28181634Sbrian  if (addr->ncpaddr_family != AF_INET)
28281634Sbrian    return 0;
28381634Sbrian  *ip = addr->ncpaddr_ip4addr;
28481634Sbrian  return 1;
28581634Sbrian}
28681634Sbrian
28781634Sbrian#ifndef NOINET6
28881634Sbrianvoid
28981634Sbrianncpaddr_setip6(struct ncpaddr *addr, const struct in6_addr *ip6)
29081634Sbrian{
29181634Sbrian  addr->ncpaddr_family = AF_INET6;
29281634Sbrian  addr->ncpaddr_ip6addr = *ip6;
29381634Sbrian}
29481634Sbrian
29581634Sbrianint
29681634Sbrianncpaddr_getip6(const struct ncpaddr *addr, struct in6_addr *ip6)
29781634Sbrian{
29881634Sbrian  if (addr->ncpaddr_family != AF_INET6)
29981634Sbrian    return 0;
30081634Sbrian  *ip6 = addr->ncpaddr_ip6addr;
30181634Sbrian  return 1;
30281634Sbrian}
30381634Sbrian#endif
30481634Sbrian
30581634Sbrianvoid
30681634Sbrianncpaddr_getsa(const struct ncpaddr *addr, struct sockaddr_storage *host)
30781634Sbrian{
30881634Sbrian  struct sockaddr_in *host4 = (struct sockaddr_in *)host;
30981634Sbrian#ifndef NOINET6
31081634Sbrian  struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
31181634Sbrian#endif
31281634Sbrian
31381634Sbrian  memset(host, '\0', sizeof(*host));
31481634Sbrian
31581634Sbrian  switch (addr->ncpaddr_family) {
31681634Sbrian  case AF_INET:
31781634Sbrian    host4->sin_family = AF_INET;
31881634Sbrian    host4->sin_len = sizeof(*host4);
31981634Sbrian    host4->sin_addr = addr->ncpaddr_ip4addr;
32081634Sbrian    break;
32181634Sbrian
32281634Sbrian#ifndef NOINET6
32381634Sbrian  case AF_INET6:
32481634Sbrian    host6->sin6_family = AF_INET6;
32581634Sbrian    host6->sin6_len = sizeof(*host6);
32681634Sbrian    host6->sin6_addr = addr->ncpaddr_ip6addr;
32781634Sbrian    adjust_linklocal(host6);
32881634Sbrian    break;
32981634Sbrian#endif
33081634Sbrian
33181634Sbrian  default:
33281634Sbrian    host->ss_family = AF_UNSPEC;
33381634Sbrian    break;
33481634Sbrian  }
33581634Sbrian}
33681634Sbrian
33781634Sbrianvoid
33881634Sbrianncpaddr_setsa(struct ncpaddr *addr, const struct sockaddr *host)
33981634Sbrian{
34081634Sbrian  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
34181634Sbrian#ifndef NOINET6
34281634Sbrian  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
34381634Sbrian#endif
34481634Sbrian
34581634Sbrian  switch (host->sa_family) {
34681634Sbrian  case AF_INET:
34781634Sbrian    addr->ncpaddr_family = AF_INET;
34881634Sbrian    addr->ncpaddr_ip4addr = host4->sin_addr;
34981634Sbrian    break;
35081634Sbrian
35181634Sbrian#ifndef NOINET6
35281634Sbrian  case AF_INET6:
35381634Sbrian    if (IN6_IS_ADDR_V4MAPPED(&host6->sin6_addr)) {
35481634Sbrian      addr->ncpaddr_family = AF_INET;
35581634Sbrian      addr->ncpaddr_ip4addr.s_addr =
35681634Sbrian        *(const u_int32_t *)(host6->sin6_addr.s6_addr + 12);
35781634Sbrian    } else {
35881634Sbrian      addr->ncpaddr_family = AF_INET6;
35981634Sbrian      addr->ncpaddr_ip6addr = host6->sin6_addr;
36081634Sbrian    }
36181634Sbrian    break;
36281634Sbrian#endif
36381634Sbrian
36481634Sbrian  default:
36581634Sbrian    addr->ncpaddr_family = AF_UNSPEC;
36681634Sbrian  }
36781634Sbrian}
36881634Sbrian
36981634Sbrianstatic char *
37081634Sbrianncpaddr_ntowa(const struct ncpaddr *addr)
37181634Sbrian{
37281634Sbrian  static char res[NCP_ASCIIBUFFERSIZE];
37381634Sbrian#ifndef NOINET6
37481634Sbrian  struct sockaddr_in6 sin6;
37581634Sbrian#endif
37681634Sbrian
37781634Sbrian  switch (addr->ncpaddr_family) {
37881634Sbrian  case AF_INET:
37981634Sbrian    snprintf(res, sizeof res, "%s", inet_ntoa(addr->ncpaddr_ip4addr));
38081634Sbrian    return res;
38181634Sbrian
38281634Sbrian#ifndef NOINET6
38381634Sbrian  case AF_INET6:
38481634Sbrian    memset(&sin6, '\0', sizeof(sin6));
38581634Sbrian    sin6.sin6_len = sizeof(sin6);
38681634Sbrian    sin6.sin6_family = AF_INET6;
38781634Sbrian    sin6.sin6_addr = addr->ncpaddr_ip6addr;
38881634Sbrian    adjust_linklocal(&sin6);
38981634Sbrian    if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res),
39081634Sbrian                    NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST) != 0)
39181634Sbrian      break;
39281634Sbrian
39381634Sbrian    return res;
39481634Sbrian#endif
39581634Sbrian  }
39681634Sbrian
39781634Sbrian  snprintf(res, sizeof res, "<AF_UNSPEC>");
39881634Sbrian  return res;
39981634Sbrian}
40081634Sbrian
40181634Sbrianconst char *
40281634Sbrianncpaddr_ntoa(const struct ncpaddr *addr)
40381634Sbrian{
40481634Sbrian  return ncpaddr_ntowa(addr);
40581634Sbrian}
40681634Sbrian
40781634Sbrian
40881634Sbrianint
40981634Sbrianncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data)
41081634Sbrian{
41181634Sbrian  struct ncprange range;
41281634Sbrian
41381634Sbrian  if (!ncprange_aton(&range, ncp, data))
41481634Sbrian    return 0;
41581634Sbrian
41681634Sbrian  if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32) {
41781634Sbrian    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data);
41881634Sbrian    return 0;
41981634Sbrian  }
42081634Sbrian
42181634Sbrian#ifndef NOINET6
42281634Sbrian  if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128) {
42381634Sbrian    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data);
42481634Sbrian    return 0;
42581634Sbrian  }
42681634Sbrian#endif
42781634Sbrian
42881634Sbrian  switch (range.ncprange_family) {
42981634Sbrian  case AF_INET:
43081634Sbrian    addr->ncpaddr_family = range.ncprange_family;
43181634Sbrian    addr->ncpaddr_ip4addr = range.ncprange_ip4addr;
43281634Sbrian    return 1;
43381634Sbrian
43481634Sbrian#ifndef NOINET6
43581634Sbrian  case AF_INET6:
43681634Sbrian    addr->ncpaddr_family = range.ncprange_family;
43781634Sbrian    addr->ncpaddr_ip6addr = range.ncprange_ip6addr;
43881634Sbrian    return 1;
43981634Sbrian#endif
44081634Sbrian  }
44181634Sbrian
44281634Sbrian  return 0;
44381634Sbrian}
44481634Sbrian
44581634Sbrianvoid
44681634Sbrianncprange_init(struct ncprange *range)
44781634Sbrian{
44881634Sbrian  range->ncprange_family = AF_UNSPEC;
44981634Sbrian}
45081634Sbrian
45181634Sbrianint
45281634Sbrianncprange_isset(const struct ncprange *range)
45381634Sbrian{
45481634Sbrian  return range->ncprange_family != AF_UNSPEC;
45581634Sbrian}
45681634Sbrian
45781634Sbrianint
45881634Sbrianncprange_equal(const struct ncprange *range, const struct ncprange *cmp)
45981634Sbrian{
46081634Sbrian  if (range->ncprange_family != cmp->ncprange_family)
46181634Sbrian    return 0;
46281634Sbrian
46381634Sbrian  switch (range->ncprange_family) {
46481634Sbrian  case AF_INET:
46581634Sbrian    if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr)
46681634Sbrian      return 0;
46781634Sbrian    return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr;
46881634Sbrian
46981634Sbrian#ifndef NOINET6
47081634Sbrian  case AF_INET6:
47181634Sbrian    if (range->ncprange_ip6width != cmp->ncprange_ip6width)
47281634Sbrian      return 0;
47381634Sbrian    return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr,
47481634Sbrian                   sizeof range->ncprange_ip6addr);
47581634Sbrian#endif
47681634Sbrian
47781634Sbrian  case AF_UNSPEC:
47881634Sbrian    return 1;
47981634Sbrian  }
48081634Sbrian
48181634Sbrian  return 0;
48281634Sbrian}
48381634Sbrian
48481634Sbrianint
48581634Sbrianncprange_isdefault(const struct ncprange *range)
48681634Sbrian{
48781634Sbrian  switch (range->ncprange_family) {
48881634Sbrian  case AF_INET:
48981634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_ANY)
49081634Sbrian      return 1;
49181634Sbrian    break;
49281634Sbrian
49381634Sbrian#ifndef NOINET6
49481634Sbrian  case AF_INET6:
49581634Sbrian    if (range->ncprange_ip6width == 0 &&
49681634Sbrian        IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
49781634Sbrian      return 1;
49881634Sbrian    break;
49981634Sbrian#endif
50081634Sbrian  }
50181634Sbrian
50281634Sbrian  return 0;
50381634Sbrian}
50481634Sbrian
50581634Sbrianvoid
50681634Sbrianncprange_setdefault(struct ncprange *range, int af)
50781634Sbrian{
50881634Sbrian  memset(range, '\0', sizeof *range);
50981634Sbrian  range->ncprange_family = af;
51081634Sbrian}
51181634Sbrian
51281634Sbrianint
51381634Sbrianncprange_contains(const struct ncprange *range, const struct ncpaddr *addr)
51481634Sbrian{
51581634Sbrian#ifndef NOINET6
51681634Sbrian  const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
51781634Sbrian  const u_char *addrp, *rangep;
51881634Sbrian  int bits;
51981634Sbrian#endif
52081634Sbrian
52181634Sbrian  if (range->ncprange_family != addr->ncpaddr_family)
52281634Sbrian    return 0;
52381634Sbrian
52481634Sbrian  switch (range->ncprange_family) {
52581634Sbrian  case AF_INET:
52681634Sbrian    return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
52781634Sbrian             range->ncprange_ip4mask.s_addr);
52881634Sbrian
52981634Sbrian#ifndef NOINET6
53081634Sbrian  case AF_INET6:
53181634Sbrian    rangep = (const u_char *)range->ncprange_ip6addr.s6_addr;
53281634Sbrian    addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr;
53381634Sbrian
53481634Sbrian    for (bits = range->ncprange_ip6width; bits > 0; bits -= 8)
53581634Sbrian      if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1])
53681634Sbrian        return 0;
53781634Sbrian
53881634Sbrian    return 1;
53981634Sbrian#endif
54081634Sbrian  }
54181634Sbrian
54281634Sbrian  return 0;
54381634Sbrian}
54481634Sbrian
54581634Sbrianint
54681634Sbrianncprange_containsip4(const struct ncprange *range, struct in_addr addr)
54781634Sbrian{
54881634Sbrian  switch (range->ncprange_family) {
54981634Sbrian  case AF_INET:
55081634Sbrian    return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
55181634Sbrian             range->ncprange_ip4mask.s_addr);
55281634Sbrian  }
55381634Sbrian
55481634Sbrian  return 0;
55581634Sbrian}
55681634Sbrian
55781634Sbrianvoid
55881634Sbrianncprange_copy(struct ncprange *range, const struct ncprange *from)
55981634Sbrian{
56081634Sbrian  switch (from->ncprange_family) {
56181634Sbrian  case AF_INET:
56281634Sbrian    range->ncprange_family = AF_INET;
56381634Sbrian    range->ncprange_ip4addr = from->ncprange_ip4addr;
56481634Sbrian    range->ncprange_ip4mask = from->ncprange_ip4mask;
56581634Sbrian    range->ncprange_ip4width = from->ncprange_ip4width;
56681634Sbrian    break;
56781634Sbrian
56881634Sbrian#ifndef NOINET6
56981634Sbrian  case AF_INET6:
57081634Sbrian    range->ncprange_family = AF_INET6;
57181634Sbrian    range->ncprange_ip6addr = from->ncprange_ip6addr;
57281634Sbrian    range->ncprange_ip6width = from->ncprange_ip6width;
57381634Sbrian    break;
57481634Sbrian#endif
57581634Sbrian
57681634Sbrian  default:
57781634Sbrian    range->ncprange_family = AF_UNSPEC;
57881634Sbrian  }
57981634Sbrian}
58081634Sbrian
58181634Sbrianvoid
58281634Sbrianncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width)
58381634Sbrian{
58481634Sbrian  ncprange_sethost(range, addr);
58581634Sbrian  ncprange_setwidth(range, width);
58681634Sbrian}
58781634Sbrian
58881634Sbrianvoid
58981634Sbrianncprange_sethost(struct ncprange *range, const struct ncpaddr *from)
59081634Sbrian{
59181634Sbrian  switch (from->ncpaddr_family) {
59281634Sbrian  case AF_INET:
59381634Sbrian    range->ncprange_family = AF_INET;
59481634Sbrian    range->ncprange_ip4addr = from->ncpaddr_ip4addr;
59581634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
59681634Sbrian    range->ncprange_ip4width = 32;
59781634Sbrian    break;
59881634Sbrian
59981634Sbrian#ifndef NOINET6
60081634Sbrian  case AF_INET6:
60181634Sbrian    range->ncprange_family = AF_INET6;
60281634Sbrian    range->ncprange_ip6addr = from->ncpaddr_ip6addr;
60381634Sbrian    range->ncprange_ip6width = 128;
60481634Sbrian    break;
60581634Sbrian#endif
60681634Sbrian
60781634Sbrian  default:
60881634Sbrian    range->ncprange_family = AF_UNSPEC;
60981634Sbrian  }
61081634Sbrian}
61181634Sbrian
61281634Sbrianint
61381634Sbrianncprange_setwidth(struct ncprange *range, int width)
61481634Sbrian{
61581634Sbrian  switch (range->ncprange_family) {
61681634Sbrian  case AF_INET:
61781634Sbrian    if (width < 0 || width > 32)
61881634Sbrian      break;
61981634Sbrian    range->ncprange_ip4width = width;
62081634Sbrian    range->ncprange_ip4mask = bits2mask4(width);
62181634Sbrian    break;
62281634Sbrian
62381634Sbrian#ifndef NOINET6
62481634Sbrian  case AF_INET6:
62581634Sbrian    if (width < 0 || width > 128)
62681634Sbrian      break;
62781634Sbrian    range->ncprange_ip6width = width;
62881634Sbrian    break;
62981634Sbrian#endif
63081634Sbrian
63181634Sbrian  case AF_UNSPEC:
63281634Sbrian    return 1;
63381634Sbrian  }
63481634Sbrian
63581634Sbrian  return 0;
63681634Sbrian}
63781634Sbrian
63881634Sbrianvoid
63981634Sbrianncprange_setip4host(struct ncprange *range, struct in_addr from)
64081634Sbrian{
64181634Sbrian  range->ncprange_family = AF_INET;
64281634Sbrian  range->ncprange_ip4addr = from;
64381634Sbrian  range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
64481634Sbrian  range->ncprange_ip4width = 32;
64581634Sbrian}
64681634Sbrian
64781634Sbrianvoid
64881634Sbrianncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk)
64981634Sbrian{
65081634Sbrian  range->ncprange_family = AF_INET;
65181634Sbrian  range->ncprange_ip4addr = from;
65281634Sbrian  range->ncprange_ip4mask = msk;
65381634Sbrian  range->ncprange_ip4width = mask42bits(msk);
65481634Sbrian}
65581634Sbrian
65681634Sbrian
65781634Sbrianint
65881634Sbrianncprange_setip4mask(struct ncprange *range, struct in_addr mask)
65981634Sbrian{
66081634Sbrian  if (range->ncprange_family != AF_INET)
66181634Sbrian    return 0;
66281634Sbrian  range->ncprange_ip4mask = mask;
66381634Sbrian  range->ncprange_ip4width = mask42bits(mask);
66481634Sbrian  return 1;
66581634Sbrian}
66681634Sbrian
66781634Sbrianvoid
66881634Sbrianncprange_setsa(struct ncprange *range, const struct sockaddr *host,
66981634Sbrian               const struct sockaddr *mask)
67081634Sbrian{
67181634Sbrian  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
67281634Sbrian  const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask;
67381634Sbrian#ifndef NOINET6
67481634Sbrian  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
67581634Sbrian  const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask;
67681634Sbrian#endif
67781634Sbrian
67881634Sbrian  switch (host->sa_family) {
67981634Sbrian  case AF_INET:
68081634Sbrian    range->ncprange_family = AF_INET;
68181634Sbrian    range->ncprange_ip4addr = host4->sin_addr;
68281634Sbrian    if (mask4) {
68381634Sbrian      range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr;
68481634Sbrian      range->ncprange_ip4width = mask42bits(mask4->sin_addr);
68581634Sbrian    } else {
68681634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
68781634Sbrian      range->ncprange_ip4width = 32;
68881634Sbrian    }
68981634Sbrian    break;
69081634Sbrian
69181634Sbrian#ifndef NOINET6
69281634Sbrian  case AF_INET6:
69381634Sbrian    range->ncprange_family = AF_INET6;
69481634Sbrian    range->ncprange_ip6addr = host6->sin6_addr;
69581634Sbrian    range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128;
69681634Sbrian    break;
69781634Sbrian#endif
69881634Sbrian
69981634Sbrian  default:
70081634Sbrian    range->ncprange_family = AF_UNSPEC;
70181634Sbrian  }
70281634Sbrian}
70381634Sbrian
70481634Sbrianvoid
70581634Sbrianncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host,
70681634Sbrian               struct sockaddr_storage *mask)
70781634Sbrian{
70881634Sbrian  struct sockaddr_in *host4 = (struct sockaddr_in *)host;
70981634Sbrian  struct sockaddr_in *mask4 = (struct sockaddr_in *)mask;
71081634Sbrian#ifndef NOINET6
71181634Sbrian  struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
71281634Sbrian  struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask;
71381634Sbrian#endif
71481634Sbrian
71581634Sbrian  memset(host, '\0', sizeof(*host));
71681634Sbrian  if (mask)
71781634Sbrian    memset(mask, '\0', sizeof(*mask));
71881634Sbrian
71981634Sbrian  switch (range->ncprange_family) {
72081634Sbrian  case AF_INET:
72181634Sbrian    host4->sin_family = AF_INET;
72281634Sbrian    host4->sin_len = sizeof(*host4);
72381634Sbrian    host4->sin_addr = range->ncprange_ip4addr;
72481634Sbrian    if (mask4) {
72581634Sbrian      mask4->sin_family = AF_INET;
72681634Sbrian      mask4->sin_len = sizeof(*host4);
72781690Sbrian      mask4->sin_addr = range->ncprange_ip4mask;
72881634Sbrian    }
72981634Sbrian    break;
73081634Sbrian
73181634Sbrian#ifndef NOINET6
73281634Sbrian  case AF_INET6:
73381634Sbrian    host6->sin6_family = AF_INET6;
73481634Sbrian    host6->sin6_len = sizeof(*host6);
73581634Sbrian    host6->sin6_addr = range->ncprange_ip6addr;
73681634Sbrian    adjust_linklocal(host6);
73781634Sbrian    if (mask6) {
73881634Sbrian      mask6->sin6_family = AF_INET6;
73981634Sbrian      mask6->sin6_len = sizeof(*host6);
74081634Sbrian      mask6->sin6_addr = bits2mask6(range->ncprange_ip6width);
74181634Sbrian    }
74281634Sbrian    break;
74381634Sbrian#endif
74481634Sbrian
74581634Sbrian  default:
74681634Sbrian    host->ss_family = AF_UNSPEC;
74781634Sbrian    if (mask)
74881634Sbrian      mask->ss_family = AF_UNSPEC;
74981634Sbrian    break;
75081634Sbrian  }
75181634Sbrian}
75281634Sbrian
75381634Sbrianint
75481634Sbrianncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr)
75581634Sbrian{
75681634Sbrian  switch (range->ncprange_family) {
75781634Sbrian  case AF_INET:
75881634Sbrian    addr->ncpaddr_family = AF_INET;
75981634Sbrian    addr->ncpaddr_ip4addr = range->ncprange_ip4addr;
76081634Sbrian    return 1;
76181634Sbrian#ifndef NOINET6
76281634Sbrian  case AF_INET6:
76381634Sbrian    addr->ncpaddr_family = AF_INET6;
76481634Sbrian    addr->ncpaddr_ip6addr =  range->ncprange_ip6addr;
76581634Sbrian    return 1;
76681634Sbrian#endif
76781634Sbrian  }
76881634Sbrian
76981634Sbrian  return 0;
77081634Sbrian}
77181634Sbrian
77281634Sbrianint
77381634Sbrianncprange_getip4addr(const struct ncprange *range, struct in_addr *addr)
77481634Sbrian{
77581634Sbrian  if (range->ncprange_family != AF_INET)
77681634Sbrian    return 0;
77781634Sbrian
77881634Sbrian  *addr = range->ncprange_ip4addr;
77981634Sbrian  return 1;
78081634Sbrian}
78181634Sbrian
78281634Sbrianint
78381634Sbrianncprange_getip4mask(const struct ncprange *range, struct in_addr *mask)
78481634Sbrian{
78581634Sbrian  switch (range->ncprange_family) {
78681634Sbrian  case AF_INET:
78781634Sbrian    *mask = range->ncprange_ip4mask;
78881634Sbrian    return 1;
78981634Sbrian  }
79081634Sbrian
79181634Sbrian  return 0;
79281634Sbrian}
79381634Sbrian
79481634Sbrianint
79581634Sbrianncprange_getwidth(const struct ncprange *range, int *width)
79681634Sbrian{
79781634Sbrian  switch (range->ncprange_family) {
79881634Sbrian  case AF_INET:
79981634Sbrian    *width = range->ncprange_ip4width;
80081634Sbrian    return 1;
80181634Sbrian#ifndef NOINET6
80281634Sbrian  case AF_INET6:
80381634Sbrian    *width = range->ncprange_ip6width;
80481634Sbrian    return 1;
80581634Sbrian#endif
80681634Sbrian  }
80781634Sbrian
80881634Sbrian  return 0;
80981634Sbrian}
81081634Sbrian
81181634Sbrianconst char *
81281634Sbrianncprange_ntoa(const struct ncprange *range)
81381634Sbrian{
81481634Sbrian  char *res;
81581634Sbrian  struct ncpaddr addr;
81681634Sbrian  int len;
81781634Sbrian
81881634Sbrian  if (!ncprange_getaddr(range, &addr))
81981634Sbrian    return "<AF_UNSPEC>";
82081634Sbrian
82181634Sbrian  res = ncpaddr_ntowa(&addr);
82281634Sbrian  len = strlen(res);
82381634Sbrian  if (len >= NCP_ASCIIBUFFERSIZE - 1)
82481634Sbrian    return res;
82581634Sbrian
82681634Sbrian  switch (range->ncprange_family) {
82781634Sbrian  case AF_INET:
82881634Sbrian    if (range->ncprange_ip4width == -1) {
82981634Sbrian      /* A non-contiguous mask */
83081634Sbrian      for (; len >= 3; res[len -= 2] = '\0')
83181634Sbrian        if (strcmp(res + len - 2, ".0"))
83281634Sbrian          break;
83381634Sbrian      snprintf(res + len, sizeof res - len, "&0x%08lx",
83481634Sbrian               ntohl(range->ncprange_ip4mask.s_addr));
83581634Sbrian    } else if (range->ncprange_ip4width < 32)
83681634Sbrian      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width);
83781634Sbrian
83881634Sbrian    return res;
83981634Sbrian
84081634Sbrian#ifndef NOINET6
84181634Sbrian  case AF_INET6:
84281634Sbrian    if (range->ncprange_ip6width != 128)
84381634Sbrian      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width);
84481634Sbrian
84581634Sbrian    return res;
84681634Sbrian#endif
84781634Sbrian  }
84881634Sbrian
84981634Sbrian  return "<AF_UNSPEC>";
85081634Sbrian}
85181634Sbrian
85281634Sbrian#ifndef NOINET6
85381634Sbrianint
85481634Sbrianncprange_scopeid(const struct ncprange *range)
85581634Sbrian{
85681634Sbrian  const struct in6_addr *sin6;
85781634Sbrian  int scopeid = -1;
85881634Sbrian
85981634Sbrian  if (range->ncprange_family == AF_INET6) {
86081634Sbrian    sin6 = &range->ncprange_ip6addr;
86181634Sbrian    if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6))
86281634Sbrian      if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0)
86381634Sbrian        scopeid = -1;
86481634Sbrian  }
86581634Sbrian
86681634Sbrian  return scopeid;
86781634Sbrian}
86881634Sbrian#endif
86981634Sbrian
87081634Sbrianint
87181634Sbrianncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data)
87281634Sbrian{
87381634Sbrian  int bits, len;
87481634Sbrian  char *wp;
87581634Sbrian  const char *cp;
87681634Sbrian  char *s;
87781634Sbrian
87881634Sbrian  len = strcspn(data, "/");
87981634Sbrian
88081634Sbrian  if (ncp && strncasecmp(data, "HISADDR", len) == 0) {
88181634Sbrian    range->ncprange_family = AF_INET;
88281634Sbrian    range->ncprange_ip4addr = ncp->ipcp.peer_ip;
88381634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
88481634Sbrian    range->ncprange_ip4width = 32;
88581634Sbrian    return 1;
88681634Sbrian#ifndef NOINET6
88781634Sbrian  } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) {
88881634Sbrian    ncprange_sethost(range, &ncp->ipv6cp.hisaddr);
88981634Sbrian    return 1;
89081634Sbrian#endif
89181634Sbrian  } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) {
89281634Sbrian    range->ncprange_family = AF_INET;
89381634Sbrian    range->ncprange_ip4addr = ncp->ipcp.my_ip;
89481634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
89581634Sbrian    range->ncprange_ip4width = 32;
89681634Sbrian    return 1;
89781634Sbrian#ifndef NOINET6
89881634Sbrian  } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) {
89981634Sbrian    ncprange_sethost(range, &ncp->ipv6cp.myaddr);
90081634Sbrian    return 1;
90181634Sbrian#endif
90281634Sbrian  } else if (ncp && strncasecmp(data, "DNS0", len) == 0) {
90381634Sbrian    range->ncprange_family = AF_INET;
90481634Sbrian    range->ncprange_ip4addr = ncp->ipcp.ns.dns[0];
90581634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
90681634Sbrian    range->ncprange_ip4width = 32;
90781634Sbrian    return 1;
90881634Sbrian  } else if (ncp && strncasecmp(data, "DNS1", len) == 0) {
90981634Sbrian    range->ncprange_family = AF_INET;
91081634Sbrian    range->ncprange_ip4addr = ncp->ipcp.ns.dns[1];
91181634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
91281634Sbrian    range->ncprange_ip4width = 32;
91381634Sbrian    return 1;
91481634Sbrian  }
91581634Sbrian
91681634Sbrian  s = (char *)alloca(len + 1);
91781634Sbrian  strncpy(s, data, len);
91881634Sbrian  s[len] = '\0';
91981634Sbrian  bits = -1;
92081634Sbrian
92181634Sbrian  if (data[len] != '\0') {
92281634Sbrian    bits = strtol(data + len + 1, &wp, 0);
92381634Sbrian    if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) {
92481634Sbrian      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
92581634Sbrian      return 0;
92681634Sbrian    }
92781634Sbrian  }
92881634Sbrian
92981634Sbrian  if ((cp = strchr(data, ':')) == NULL) {
93081634Sbrian    range->ncprange_family = AF_INET;
93181634Sbrian
93281634Sbrian    range->ncprange_ip4addr = GetIpAddr(s);
93381634Sbrian
93481634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_NONE) {
93581634Sbrian      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
93681634Sbrian      return 0;
93781634Sbrian    }
93881634Sbrian
93981634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_ANY) {
94081634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_ANY;
94181634Sbrian      range->ncprange_ip4width = 0;
94281690Sbrian    } else if (bits == -1) {
94381634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
94481634Sbrian      range->ncprange_ip4width = 32;
94581690Sbrian    } else if (bits > 32) {
94681690Sbrian      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
94781690Sbrian      return 0;
94881634Sbrian    } else {
94981634Sbrian      range->ncprange_ip4mask = bits2mask4(bits);
95081634Sbrian      range->ncprange_ip4width = bits;
95181634Sbrian    }
95281634Sbrian
95381634Sbrian    return 1;
95481634Sbrian#ifndef NOINET6
95581634Sbrian  } else if (strchr(cp + 1, ':') != NULL) {
95681634Sbrian    range->ncprange_family = AF_INET6;
95781634Sbrian
95881634Sbrian    if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) {
95981634Sbrian      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
96081634Sbrian      return 0;
96181634Sbrian    }
96281634Sbrian
96381634Sbrian    if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
96481634Sbrian      range->ncprange_ip6width = 0;
96581634Sbrian    else
96681634Sbrian      range->ncprange_ip6width = (bits == -1) ? 128 : bits;
96781634Sbrian    return 1;
96881634Sbrian#endif
96981634Sbrian  }
97081634Sbrian
97181634Sbrian  return 0;
97281634Sbrian}
973