ncpaddr.c revision 81690
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 81690 2001-08-15 12:07:39Z 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
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    adjust_linklocal(host6);
32281634Sbrian    break;
32381634Sbrian#endif
32481634Sbrian
32581634Sbrian  default:
32681634Sbrian    host->ss_family = AF_UNSPEC;
32781634Sbrian    break;
32881634Sbrian  }
32981634Sbrian}
33081634Sbrian
33181634Sbrianvoid
33281634Sbrianncpaddr_setsa(struct ncpaddr *addr, const struct sockaddr *host)
33381634Sbrian{
33481634Sbrian  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
33581634Sbrian#ifndef NOINET6
33681634Sbrian  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
33781634Sbrian#endif
33881634Sbrian
33981634Sbrian  switch (host->sa_family) {
34081634Sbrian  case AF_INET:
34181634Sbrian    addr->ncpaddr_family = AF_INET;
34281634Sbrian    addr->ncpaddr_ip4addr = host4->sin_addr;
34381634Sbrian    break;
34481634Sbrian
34581634Sbrian#ifndef NOINET6
34681634Sbrian  case AF_INET6:
34781634Sbrian    if (IN6_IS_ADDR_V4MAPPED(&host6->sin6_addr)) {
34881634Sbrian      addr->ncpaddr_family = AF_INET;
34981634Sbrian      addr->ncpaddr_ip4addr.s_addr =
35081634Sbrian        *(const u_int32_t *)(host6->sin6_addr.s6_addr + 12);
35181634Sbrian    } else {
35281634Sbrian      addr->ncpaddr_family = AF_INET6;
35381634Sbrian      addr->ncpaddr_ip6addr = host6->sin6_addr;
35481634Sbrian    }
35581634Sbrian    break;
35681634Sbrian#endif
35781634Sbrian
35881634Sbrian  default:
35981634Sbrian    addr->ncpaddr_family = AF_UNSPEC;
36081634Sbrian  }
36181634Sbrian}
36281634Sbrian
36381634Sbrianstatic char *
36481634Sbrianncpaddr_ntowa(const struct ncpaddr *addr)
36581634Sbrian{
36681634Sbrian  static char res[NCP_ASCIIBUFFERSIZE];
36781634Sbrian#ifndef NOINET6
36881634Sbrian  struct sockaddr_in6 sin6;
36981634Sbrian#endif
37081634Sbrian
37181634Sbrian  switch (addr->ncpaddr_family) {
37281634Sbrian  case AF_INET:
37381634Sbrian    snprintf(res, sizeof res, "%s", inet_ntoa(addr->ncpaddr_ip4addr));
37481634Sbrian    return res;
37581634Sbrian
37681634Sbrian#ifndef NOINET6
37781634Sbrian  case AF_INET6:
37881634Sbrian    memset(&sin6, '\0', sizeof(sin6));
37981634Sbrian    sin6.sin6_len = sizeof(sin6);
38081634Sbrian    sin6.sin6_family = AF_INET6;
38181634Sbrian    sin6.sin6_addr = addr->ncpaddr_ip6addr;
38281634Sbrian    adjust_linklocal(&sin6);
38381634Sbrian    if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res),
38481634Sbrian                    NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST) != 0)
38581634Sbrian      break;
38681634Sbrian
38781634Sbrian    return res;
38881634Sbrian#endif
38981634Sbrian  }
39081634Sbrian
39181634Sbrian  snprintf(res, sizeof res, "<AF_UNSPEC>");
39281634Sbrian  return res;
39381634Sbrian}
39481634Sbrian
39581634Sbrianconst char *
39681634Sbrianncpaddr_ntoa(const struct ncpaddr *addr)
39781634Sbrian{
39881634Sbrian  return ncpaddr_ntowa(addr);
39981634Sbrian}
40081634Sbrian
40181634Sbrian
40281634Sbrianint
40381634Sbrianncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data)
40481634Sbrian{
40581634Sbrian  struct ncprange range;
40681634Sbrian
40781634Sbrian  if (!ncprange_aton(&range, ncp, data))
40881634Sbrian    return 0;
40981634Sbrian
41081634Sbrian  if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32) {
41181634Sbrian    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data);
41281634Sbrian    return 0;
41381634Sbrian  }
41481634Sbrian
41581634Sbrian#ifndef NOINET6
41681634Sbrian  if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128) {
41781634Sbrian    log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data);
41881634Sbrian    return 0;
41981634Sbrian  }
42081634Sbrian#endif
42181634Sbrian
42281634Sbrian  switch (range.ncprange_family) {
42381634Sbrian  case AF_INET:
42481634Sbrian    addr->ncpaddr_family = range.ncprange_family;
42581634Sbrian    addr->ncpaddr_ip4addr = range.ncprange_ip4addr;
42681634Sbrian    return 1;
42781634Sbrian
42881634Sbrian#ifndef NOINET6
42981634Sbrian  case AF_INET6:
43081634Sbrian    addr->ncpaddr_family = range.ncprange_family;
43181634Sbrian    addr->ncpaddr_ip6addr = range.ncprange_ip6addr;
43281634Sbrian    return 1;
43381634Sbrian#endif
43481634Sbrian  }
43581634Sbrian
43681634Sbrian  return 0;
43781634Sbrian}
43881634Sbrian
43981634Sbrianvoid
44081634Sbrianncprange_init(struct ncprange *range)
44181634Sbrian{
44281634Sbrian  range->ncprange_family = AF_UNSPEC;
44381634Sbrian}
44481634Sbrian
44581634Sbrianint
44681634Sbrianncprange_isset(const struct ncprange *range)
44781634Sbrian{
44881634Sbrian  return range->ncprange_family != AF_UNSPEC;
44981634Sbrian}
45081634Sbrian
45181634Sbrianint
45281634Sbrianncprange_equal(const struct ncprange *range, const struct ncprange *cmp)
45381634Sbrian{
45481634Sbrian  if (range->ncprange_family != cmp->ncprange_family)
45581634Sbrian    return 0;
45681634Sbrian
45781634Sbrian  switch (range->ncprange_family) {
45881634Sbrian  case AF_INET:
45981634Sbrian    if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr)
46081634Sbrian      return 0;
46181634Sbrian    return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr;
46281634Sbrian
46381634Sbrian#ifndef NOINET6
46481634Sbrian  case AF_INET6:
46581634Sbrian    if (range->ncprange_ip6width != cmp->ncprange_ip6width)
46681634Sbrian      return 0;
46781634Sbrian    return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr,
46881634Sbrian                   sizeof range->ncprange_ip6addr);
46981634Sbrian#endif
47081634Sbrian
47181634Sbrian  case AF_UNSPEC:
47281634Sbrian    return 1;
47381634Sbrian  }
47481634Sbrian
47581634Sbrian  return 0;
47681634Sbrian}
47781634Sbrian
47881634Sbrianint
47981634Sbrianncprange_isdefault(const struct ncprange *range)
48081634Sbrian{
48181634Sbrian  switch (range->ncprange_family) {
48281634Sbrian  case AF_INET:
48381634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_ANY)
48481634Sbrian      return 1;
48581634Sbrian    break;
48681634Sbrian
48781634Sbrian#ifndef NOINET6
48881634Sbrian  case AF_INET6:
48981634Sbrian    if (range->ncprange_ip6width == 0 &&
49081634Sbrian        IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
49181634Sbrian      return 1;
49281634Sbrian    break;
49381634Sbrian#endif
49481634Sbrian  }
49581634Sbrian
49681634Sbrian  return 0;
49781634Sbrian}
49881634Sbrian
49981634Sbrianvoid
50081634Sbrianncprange_setdefault(struct ncprange *range, int af)
50181634Sbrian{
50281634Sbrian  memset(range, '\0', sizeof *range);
50381634Sbrian  range->ncprange_family = af;
50481634Sbrian}
50581634Sbrian
50681634Sbrianint
50781634Sbrianncprange_contains(const struct ncprange *range, const struct ncpaddr *addr)
50881634Sbrian{
50981634Sbrian#ifndef NOINET6
51081634Sbrian  const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
51181634Sbrian  const u_char *addrp, *rangep;
51281634Sbrian  int bits;
51381634Sbrian#endif
51481634Sbrian
51581634Sbrian  if (range->ncprange_family != addr->ncpaddr_family)
51681634Sbrian    return 0;
51781634Sbrian
51881634Sbrian  switch (range->ncprange_family) {
51981634Sbrian  case AF_INET:
52081634Sbrian    return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
52181634Sbrian             range->ncprange_ip4mask.s_addr);
52281634Sbrian
52381634Sbrian#ifndef NOINET6
52481634Sbrian  case AF_INET6:
52581634Sbrian    rangep = (const u_char *)range->ncprange_ip6addr.s6_addr;
52681634Sbrian    addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr;
52781634Sbrian
52881634Sbrian    for (bits = range->ncprange_ip6width; bits > 0; bits -= 8)
52981634Sbrian      if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1])
53081634Sbrian        return 0;
53181634Sbrian
53281634Sbrian    return 1;
53381634Sbrian#endif
53481634Sbrian  }
53581634Sbrian
53681634Sbrian  return 0;
53781634Sbrian}
53881634Sbrian
53981634Sbrianint
54081634Sbrianncprange_containsip4(const struct ncprange *range, struct in_addr addr)
54181634Sbrian{
54281634Sbrian  switch (range->ncprange_family) {
54381634Sbrian  case AF_INET:
54481634Sbrian    return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) &
54581634Sbrian             range->ncprange_ip4mask.s_addr);
54681634Sbrian  }
54781634Sbrian
54881634Sbrian  return 0;
54981634Sbrian}
55081634Sbrian
55181634Sbrianvoid
55281634Sbrianncprange_copy(struct ncprange *range, const struct ncprange *from)
55381634Sbrian{
55481634Sbrian  switch (from->ncprange_family) {
55581634Sbrian  case AF_INET:
55681634Sbrian    range->ncprange_family = AF_INET;
55781634Sbrian    range->ncprange_ip4addr = from->ncprange_ip4addr;
55881634Sbrian    range->ncprange_ip4mask = from->ncprange_ip4mask;
55981634Sbrian    range->ncprange_ip4width = from->ncprange_ip4width;
56081634Sbrian    break;
56181634Sbrian
56281634Sbrian#ifndef NOINET6
56381634Sbrian  case AF_INET6:
56481634Sbrian    range->ncprange_family = AF_INET6;
56581634Sbrian    range->ncprange_ip6addr = from->ncprange_ip6addr;
56681634Sbrian    range->ncprange_ip6width = from->ncprange_ip6width;
56781634Sbrian    break;
56881634Sbrian#endif
56981634Sbrian
57081634Sbrian  default:
57181634Sbrian    range->ncprange_family = AF_UNSPEC;
57281634Sbrian  }
57381634Sbrian}
57481634Sbrian
57581634Sbrianvoid
57681634Sbrianncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width)
57781634Sbrian{
57881634Sbrian  ncprange_sethost(range, addr);
57981634Sbrian  ncprange_setwidth(range, width);
58081634Sbrian}
58181634Sbrian
58281634Sbrianvoid
58381634Sbrianncprange_sethost(struct ncprange *range, const struct ncpaddr *from)
58481634Sbrian{
58581634Sbrian  switch (from->ncpaddr_family) {
58681634Sbrian  case AF_INET:
58781634Sbrian    range->ncprange_family = AF_INET;
58881634Sbrian    range->ncprange_ip4addr = from->ncpaddr_ip4addr;
58981634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
59081634Sbrian    range->ncprange_ip4width = 32;
59181634Sbrian    break;
59281634Sbrian
59381634Sbrian#ifndef NOINET6
59481634Sbrian  case AF_INET6:
59581634Sbrian    range->ncprange_family = AF_INET6;
59681634Sbrian    range->ncprange_ip6addr = from->ncpaddr_ip6addr;
59781634Sbrian    range->ncprange_ip6width = 128;
59881634Sbrian    break;
59981634Sbrian#endif
60081634Sbrian
60181634Sbrian  default:
60281634Sbrian    range->ncprange_family = AF_UNSPEC;
60381634Sbrian  }
60481634Sbrian}
60581634Sbrian
60681634Sbrianint
60781634Sbrianncprange_setwidth(struct ncprange *range, int width)
60881634Sbrian{
60981634Sbrian  switch (range->ncprange_family) {
61081634Sbrian  case AF_INET:
61181634Sbrian    if (width < 0 || width > 32)
61281634Sbrian      break;
61381634Sbrian    range->ncprange_ip4width = width;
61481634Sbrian    range->ncprange_ip4mask = bits2mask4(width);
61581634Sbrian    break;
61681634Sbrian
61781634Sbrian#ifndef NOINET6
61881634Sbrian  case AF_INET6:
61981634Sbrian    if (width < 0 || width > 128)
62081634Sbrian      break;
62181634Sbrian    range->ncprange_ip6width = width;
62281634Sbrian    break;
62381634Sbrian#endif
62481634Sbrian
62581634Sbrian  case AF_UNSPEC:
62681634Sbrian    return 1;
62781634Sbrian  }
62881634Sbrian
62981634Sbrian  return 0;
63081634Sbrian}
63181634Sbrian
63281634Sbrianvoid
63381634Sbrianncprange_setip4host(struct ncprange *range, struct in_addr from)
63481634Sbrian{
63581634Sbrian  range->ncprange_family = AF_INET;
63681634Sbrian  range->ncprange_ip4addr = from;
63781634Sbrian  range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
63881634Sbrian  range->ncprange_ip4width = 32;
63981634Sbrian}
64081634Sbrian
64181634Sbrianvoid
64281634Sbrianncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk)
64381634Sbrian{
64481634Sbrian  range->ncprange_family = AF_INET;
64581634Sbrian  range->ncprange_ip4addr = from;
64681634Sbrian  range->ncprange_ip4mask = msk;
64781634Sbrian  range->ncprange_ip4width = mask42bits(msk);
64881634Sbrian}
64981634Sbrian
65081634Sbrian
65181634Sbrianint
65281634Sbrianncprange_setip4mask(struct ncprange *range, struct in_addr mask)
65381634Sbrian{
65481634Sbrian  if (range->ncprange_family != AF_INET)
65581634Sbrian    return 0;
65681634Sbrian  range->ncprange_ip4mask = mask;
65781634Sbrian  range->ncprange_ip4width = mask42bits(mask);
65881634Sbrian  return 1;
65981634Sbrian}
66081634Sbrian
66181634Sbrianvoid
66281634Sbrianncprange_setsa(struct ncprange *range, const struct sockaddr *host,
66381634Sbrian               const struct sockaddr *mask)
66481634Sbrian{
66581634Sbrian  const struct sockaddr_in *host4 = (const struct sockaddr_in *)host;
66681634Sbrian  const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask;
66781634Sbrian#ifndef NOINET6
66881634Sbrian  const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host;
66981634Sbrian  const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask;
67081634Sbrian#endif
67181634Sbrian
67281634Sbrian  switch (host->sa_family) {
67381634Sbrian  case AF_INET:
67481634Sbrian    range->ncprange_family = AF_INET;
67581634Sbrian    range->ncprange_ip4addr = host4->sin_addr;
67681634Sbrian    if (mask4) {
67781634Sbrian      range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr;
67881634Sbrian      range->ncprange_ip4width = mask42bits(mask4->sin_addr);
67981634Sbrian    } else {
68081634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
68181634Sbrian      range->ncprange_ip4width = 32;
68281634Sbrian    }
68381634Sbrian    break;
68481634Sbrian
68581634Sbrian#ifndef NOINET6
68681634Sbrian  case AF_INET6:
68781634Sbrian    range->ncprange_family = AF_INET6;
68881634Sbrian    range->ncprange_ip6addr = host6->sin6_addr;
68981634Sbrian    range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128;
69081634Sbrian    break;
69181634Sbrian#endif
69281634Sbrian
69381634Sbrian  default:
69481634Sbrian    range->ncprange_family = AF_UNSPEC;
69581634Sbrian  }
69681634Sbrian}
69781634Sbrian
69881634Sbrianvoid
69981634Sbrianncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host,
70081634Sbrian               struct sockaddr_storage *mask)
70181634Sbrian{
70281634Sbrian  struct sockaddr_in *host4 = (struct sockaddr_in *)host;
70381634Sbrian  struct sockaddr_in *mask4 = (struct sockaddr_in *)mask;
70481634Sbrian#ifndef NOINET6
70581634Sbrian  struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host;
70681634Sbrian  struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask;
70781634Sbrian#endif
70881634Sbrian
70981634Sbrian  memset(host, '\0', sizeof(*host));
71081634Sbrian  if (mask)
71181634Sbrian    memset(mask, '\0', sizeof(*mask));
71281634Sbrian
71381634Sbrian  switch (range->ncprange_family) {
71481634Sbrian  case AF_INET:
71581634Sbrian    host4->sin_family = AF_INET;
71681634Sbrian    host4->sin_len = sizeof(*host4);
71781634Sbrian    host4->sin_addr = range->ncprange_ip4addr;
71881634Sbrian    if (mask4) {
71981634Sbrian      mask4->sin_family = AF_INET;
72081634Sbrian      mask4->sin_len = sizeof(*host4);
72181690Sbrian      mask4->sin_addr = range->ncprange_ip4mask;
72281634Sbrian    }
72381634Sbrian    break;
72481634Sbrian
72581634Sbrian#ifndef NOINET6
72681634Sbrian  case AF_INET6:
72781634Sbrian    host6->sin6_family = AF_INET6;
72881634Sbrian    host6->sin6_len = sizeof(*host6);
72981634Sbrian    host6->sin6_addr = range->ncprange_ip6addr;
73081634Sbrian    adjust_linklocal(host6);
73181634Sbrian    if (mask6) {
73281634Sbrian      mask6->sin6_family = AF_INET6;
73381634Sbrian      mask6->sin6_len = sizeof(*host6);
73481634Sbrian      mask6->sin6_addr = bits2mask6(range->ncprange_ip6width);
73581634Sbrian    }
73681634Sbrian    break;
73781634Sbrian#endif
73881634Sbrian
73981634Sbrian  default:
74081634Sbrian    host->ss_family = AF_UNSPEC;
74181634Sbrian    if (mask)
74281634Sbrian      mask->ss_family = AF_UNSPEC;
74381634Sbrian    break;
74481634Sbrian  }
74581634Sbrian}
74681634Sbrian
74781634Sbrianint
74881634Sbrianncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr)
74981634Sbrian{
75081634Sbrian  switch (range->ncprange_family) {
75181634Sbrian  case AF_INET:
75281634Sbrian    addr->ncpaddr_family = AF_INET;
75381634Sbrian    addr->ncpaddr_ip4addr = range->ncprange_ip4addr;
75481634Sbrian    return 1;
75581634Sbrian#ifndef NOINET6
75681634Sbrian  case AF_INET6:
75781634Sbrian    addr->ncpaddr_family = AF_INET6;
75881634Sbrian    addr->ncpaddr_ip6addr =  range->ncprange_ip6addr;
75981634Sbrian    return 1;
76081634Sbrian#endif
76181634Sbrian  }
76281634Sbrian
76381634Sbrian  return 0;
76481634Sbrian}
76581634Sbrian
76681634Sbrianint
76781634Sbrianncprange_getip4addr(const struct ncprange *range, struct in_addr *addr)
76881634Sbrian{
76981634Sbrian  if (range->ncprange_family != AF_INET)
77081634Sbrian    return 0;
77181634Sbrian
77281634Sbrian  *addr = range->ncprange_ip4addr;
77381634Sbrian  return 1;
77481634Sbrian}
77581634Sbrian
77681634Sbrianint
77781634Sbrianncprange_getip4mask(const struct ncprange *range, struct in_addr *mask)
77881634Sbrian{
77981634Sbrian  switch (range->ncprange_family) {
78081634Sbrian  case AF_INET:
78181634Sbrian    *mask = range->ncprange_ip4mask;
78281634Sbrian    return 1;
78381634Sbrian  }
78481634Sbrian
78581634Sbrian  return 0;
78681634Sbrian}
78781634Sbrian
78881634Sbrianint
78981634Sbrianncprange_getwidth(const struct ncprange *range, int *width)
79081634Sbrian{
79181634Sbrian  switch (range->ncprange_family) {
79281634Sbrian  case AF_INET:
79381634Sbrian    *width = range->ncprange_ip4width;
79481634Sbrian    return 1;
79581634Sbrian#ifndef NOINET6
79681634Sbrian  case AF_INET6:
79781634Sbrian    *width = range->ncprange_ip6width;
79881634Sbrian    return 1;
79981634Sbrian#endif
80081634Sbrian  }
80181634Sbrian
80281634Sbrian  return 0;
80381634Sbrian}
80481634Sbrian
80581634Sbrianconst char *
80681634Sbrianncprange_ntoa(const struct ncprange *range)
80781634Sbrian{
80881634Sbrian  char *res;
80981634Sbrian  struct ncpaddr addr;
81081634Sbrian  int len;
81181634Sbrian
81281634Sbrian  if (!ncprange_getaddr(range, &addr))
81381634Sbrian    return "<AF_UNSPEC>";
81481634Sbrian
81581634Sbrian  res = ncpaddr_ntowa(&addr);
81681634Sbrian  len = strlen(res);
81781634Sbrian  if (len >= NCP_ASCIIBUFFERSIZE - 1)
81881634Sbrian    return res;
81981634Sbrian
82081634Sbrian  switch (range->ncprange_family) {
82181634Sbrian  case AF_INET:
82281634Sbrian    if (range->ncprange_ip4width == -1) {
82381634Sbrian      /* A non-contiguous mask */
82481634Sbrian      for (; len >= 3; res[len -= 2] = '\0')
82581634Sbrian        if (strcmp(res + len - 2, ".0"))
82681634Sbrian          break;
82781634Sbrian      snprintf(res + len, sizeof res - len, "&0x%08lx",
82881634Sbrian               ntohl(range->ncprange_ip4mask.s_addr));
82981634Sbrian    } else if (range->ncprange_ip4width < 32)
83081634Sbrian      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width);
83181634Sbrian
83281634Sbrian    return res;
83381634Sbrian
83481634Sbrian#ifndef NOINET6
83581634Sbrian  case AF_INET6:
83681634Sbrian    if (range->ncprange_ip6width != 128)
83781634Sbrian      snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width);
83881634Sbrian
83981634Sbrian    return res;
84081634Sbrian#endif
84181634Sbrian  }
84281634Sbrian
84381634Sbrian  return "<AF_UNSPEC>";
84481634Sbrian}
84581634Sbrian
84681634Sbrian#ifndef NOINET6
84781634Sbrianint
84881634Sbrianncprange_scopeid(const struct ncprange *range)
84981634Sbrian{
85081634Sbrian  const struct in6_addr *sin6;
85181634Sbrian  int scopeid = -1;
85281634Sbrian
85381634Sbrian  if (range->ncprange_family == AF_INET6) {
85481634Sbrian    sin6 = &range->ncprange_ip6addr;
85581634Sbrian    if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6))
85681634Sbrian      if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0)
85781634Sbrian        scopeid = -1;
85881634Sbrian  }
85981634Sbrian
86081634Sbrian  return scopeid;
86181634Sbrian}
86281634Sbrian#endif
86381634Sbrian
86481634Sbrianint
86581634Sbrianncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data)
86681634Sbrian{
86781634Sbrian  int bits, len;
86881634Sbrian  char *wp;
86981634Sbrian  const char *cp;
87081634Sbrian  char *s;
87181634Sbrian
87281634Sbrian  len = strcspn(data, "/");
87381634Sbrian
87481634Sbrian  if (ncp && strncasecmp(data, "HISADDR", len) == 0) {
87581634Sbrian    range->ncprange_family = AF_INET;
87681634Sbrian    range->ncprange_ip4addr = ncp->ipcp.peer_ip;
87781634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
87881634Sbrian    range->ncprange_ip4width = 32;
87981634Sbrian    return 1;
88081634Sbrian#ifndef NOINET6
88181634Sbrian  } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) {
88281634Sbrian    ncprange_sethost(range, &ncp->ipv6cp.hisaddr);
88381634Sbrian    return 1;
88481634Sbrian#endif
88581634Sbrian  } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) {
88681634Sbrian    range->ncprange_family = AF_INET;
88781634Sbrian    range->ncprange_ip4addr = ncp->ipcp.my_ip;
88881634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
88981634Sbrian    range->ncprange_ip4width = 32;
89081634Sbrian    return 1;
89181634Sbrian#ifndef NOINET6
89281634Sbrian  } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) {
89381634Sbrian    ncprange_sethost(range, &ncp->ipv6cp.myaddr);
89481634Sbrian    return 1;
89581634Sbrian#endif
89681634Sbrian  } else if (ncp && strncasecmp(data, "DNS0", len) == 0) {
89781634Sbrian    range->ncprange_family = AF_INET;
89881634Sbrian    range->ncprange_ip4addr = ncp->ipcp.ns.dns[0];
89981634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
90081634Sbrian    range->ncprange_ip4width = 32;
90181634Sbrian    return 1;
90281634Sbrian  } else if (ncp && strncasecmp(data, "DNS1", len) == 0) {
90381634Sbrian    range->ncprange_family = AF_INET;
90481634Sbrian    range->ncprange_ip4addr = ncp->ipcp.ns.dns[1];
90581634Sbrian    range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
90681634Sbrian    range->ncprange_ip4width = 32;
90781634Sbrian    return 1;
90881634Sbrian  }
90981634Sbrian
91081634Sbrian  s = (char *)alloca(len + 1);
91181634Sbrian  strncpy(s, data, len);
91281634Sbrian  s[len] = '\0';
91381634Sbrian  bits = -1;
91481634Sbrian
91581634Sbrian  if (data[len] != '\0') {
91681634Sbrian    bits = strtol(data + len + 1, &wp, 0);
91781634Sbrian    if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) {
91881634Sbrian      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
91981634Sbrian      return 0;
92081634Sbrian    }
92181634Sbrian  }
92281634Sbrian
92381634Sbrian  if ((cp = strchr(data, ':')) == NULL) {
92481634Sbrian    range->ncprange_family = AF_INET;
92581634Sbrian
92681634Sbrian    range->ncprange_ip4addr = GetIpAddr(s);
92781634Sbrian
92881634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_NONE) {
92981634Sbrian      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
93081634Sbrian      return 0;
93181634Sbrian    }
93281634Sbrian
93381634Sbrian    if (range->ncprange_ip4addr.s_addr == INADDR_ANY) {
93481634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_ANY;
93581634Sbrian      range->ncprange_ip4width = 0;
93681690Sbrian    } else if (bits == -1) {
93781634Sbrian      range->ncprange_ip4mask.s_addr = INADDR_BROADCAST;
93881634Sbrian      range->ncprange_ip4width = 32;
93981690Sbrian    } else if (bits > 32) {
94081690Sbrian      log_Printf(LogWARN, "ncprange_aton: bad mask width.\n");
94181690Sbrian      return 0;
94281634Sbrian    } else {
94381634Sbrian      range->ncprange_ip4mask = bits2mask4(bits);
94481634Sbrian      range->ncprange_ip4width = bits;
94581634Sbrian    }
94681634Sbrian
94781634Sbrian    return 1;
94881634Sbrian#ifndef NOINET6
94981634Sbrian  } else if (strchr(cp + 1, ':') != NULL) {
95081634Sbrian    range->ncprange_family = AF_INET6;
95181634Sbrian
95281634Sbrian    if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) {
95381634Sbrian      log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s);
95481634Sbrian      return 0;
95581634Sbrian    }
95681634Sbrian
95781634Sbrian    if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr))
95881634Sbrian      range->ncprange_ip6width = 0;
95981634Sbrian    else
96081634Sbrian      range->ncprange_ip6width = (bits == -1) ? 128 : bits;
96181634Sbrian    return 1;
96281634Sbrian#endif
96381634Sbrian  }
96481634Sbrian
96581634Sbrian  return 0;
96681634Sbrian}
967