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$ 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; 145115303Speter int masklen, m; 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) { 152115303Speter for (c = masks, m = 0; c < masks + sizeof masks; c++, m++) 15381634Sbrian if (*c == *p) { 154115303Speter masklen += m; 15581634Sbrian break; 15681634Sbrian } 15781634Sbrian } 15881634Sbrian 15981634Sbrian return masklen; 16081634Sbrian} 16181634Sbrian 162134789Sbrian#if 0 16381634Sbrianstatic void 16481634Sbrianadjust_linklocal(struct sockaddr_in6 *sin6) 16581634Sbrian{ 16681634Sbrian /* XXX: ?????!?!?!!!!! This is horrible ! */ 167102558Sbrian /* 168102558Sbrian * The kernel does not understand sin6_scope_id for routing at this moment. 169102558Sbrian * We should rather keep the embedded ID. 170102558Sbrian * jinmei@kame.net, 20011026 171102558Sbrian */ 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 180134789Sbrian#endif 18181634Sbrian 18281634Sbrianvoid 18381634Sbrianncpaddr_init(struct ncpaddr *addr) 18481634Sbrian{ 18581634Sbrian addr->ncpaddr_family = AF_UNSPEC; 18681634Sbrian} 18781634Sbrian 18881634Sbrianint 18981739Sbrianncpaddr_isset(const struct ncpaddr *addr) 19081739Sbrian{ 19181739Sbrian return addr->ncpaddr_family != AF_UNSPEC; 19281739Sbrian} 19381739Sbrian 19481739Sbrianint 19581634Sbrianncpaddr_isdefault(const struct ncpaddr *addr) 19681634Sbrian{ 19781634Sbrian switch (addr->ncpaddr_family) { 19881634Sbrian case AF_INET: 19981634Sbrian if (addr->ncpaddr_ip4addr.s_addr == INADDR_ANY) 20081634Sbrian return 1; 20181634Sbrian break; 20281634Sbrian 20381634Sbrian#ifndef NOINET6 20481634Sbrian case AF_INET6: 20581634Sbrian if (IN6_IS_ADDR_UNSPECIFIED(&addr->ncpaddr_ip6addr)) 20681634Sbrian return 1; 20781634Sbrian break; 20881634Sbrian#endif 20981634Sbrian } 21081634Sbrian 21181634Sbrian return 0; 21281634Sbrian} 21381634Sbrian 21481634Sbrianint 21581634Sbrianncpaddr_equal(const struct ncpaddr *addr, const struct ncpaddr *cmp) 21681634Sbrian{ 21781634Sbrian if (addr->ncpaddr_family != cmp->ncpaddr_family) 21881634Sbrian return 0; 21981634Sbrian 22081634Sbrian switch (addr->ncpaddr_family) { 22181634Sbrian case AF_INET: 22281634Sbrian return addr->ncpaddr_ip4addr.s_addr == cmp->ncpaddr_ip4addr.s_addr; 22381634Sbrian 22481634Sbrian#ifndef NOINET6 22581634Sbrian case AF_INET6: 22681634Sbrian return !memcmp(&addr->ncpaddr_ip6addr, &cmp->ncpaddr_ip6addr, 22781634Sbrian sizeof addr->ncpaddr_ip6addr); 22881634Sbrian#endif 22981634Sbrian 23081634Sbrian case AF_UNSPEC: 23181634Sbrian return 1; 23281634Sbrian } 23381634Sbrian 23481634Sbrian return 0; 23581634Sbrian} 23681634Sbrian 23781634Sbrianvoid 23881634Sbrianncpaddr_copy(struct ncpaddr *addr, const struct ncpaddr *from) 23981634Sbrian{ 24081634Sbrian switch (from->ncpaddr_family) { 24181634Sbrian case AF_INET: 24281634Sbrian addr->ncpaddr_family = AF_INET; 24381634Sbrian addr->ncpaddr_ip4addr = from->ncpaddr_ip4addr; 24481634Sbrian break; 24581634Sbrian#ifndef NOINET6 24681634Sbrian case AF_INET6: 24781634Sbrian addr->ncpaddr_family = AF_INET6; 24881634Sbrian addr->ncpaddr_ip6addr = from->ncpaddr_ip6addr; 24981634Sbrian break; 25081634Sbrian#endif 25181634Sbrian default: 25281634Sbrian addr->ncpaddr_family = AF_UNSPEC; 25381634Sbrian } 25481634Sbrian} 25581634Sbrian 25681634Sbrianvoid 25781634Sbrianncpaddr_setip4addr(struct ncpaddr *addr, u_int32_t ip) 25881634Sbrian{ 25981634Sbrian addr->ncpaddr_family = AF_INET; 26081634Sbrian addr->ncpaddr_ip4addr.s_addr = ip; 26181634Sbrian} 26281634Sbrian 26381634Sbrianint 26481634Sbrianncpaddr_getip4addr(const struct ncpaddr *addr, u_int32_t *ip) 26581634Sbrian{ 26681634Sbrian if (addr->ncpaddr_family != AF_INET) 26781634Sbrian return 0; 26881634Sbrian *ip = addr->ncpaddr_ip4addr.s_addr; 26981634Sbrian return 1; 27081634Sbrian} 27181634Sbrian 27281634Sbrianvoid 27381634Sbrianncpaddr_setip4(struct ncpaddr *addr, struct in_addr ip) 27481634Sbrian{ 27581634Sbrian addr->ncpaddr_family = AF_INET; 27681634Sbrian addr->ncpaddr_ip4addr = ip; 27781634Sbrian} 27881634Sbrian 27981634Sbrianint 28081634Sbrianncpaddr_getip4(const struct ncpaddr *addr, struct in_addr *ip) 28181634Sbrian{ 28281634Sbrian if (addr->ncpaddr_family != AF_INET) 28381634Sbrian return 0; 28481634Sbrian *ip = addr->ncpaddr_ip4addr; 28581634Sbrian return 1; 28681634Sbrian} 28781634Sbrian 28881634Sbrian#ifndef NOINET6 28981634Sbrianvoid 29081634Sbrianncpaddr_setip6(struct ncpaddr *addr, const struct in6_addr *ip6) 29181634Sbrian{ 29281634Sbrian addr->ncpaddr_family = AF_INET6; 29381634Sbrian addr->ncpaddr_ip6addr = *ip6; 29481634Sbrian} 29581634Sbrian 29681634Sbrianint 29781634Sbrianncpaddr_getip6(const struct ncpaddr *addr, struct in6_addr *ip6) 29881634Sbrian{ 29981634Sbrian if (addr->ncpaddr_family != AF_INET6) 30081634Sbrian return 0; 30181634Sbrian *ip6 = addr->ncpaddr_ip6addr; 30281634Sbrian return 1; 30381634Sbrian} 30481634Sbrian#endif 30581634Sbrian 30681634Sbrianvoid 30781634Sbrianncpaddr_getsa(const struct ncpaddr *addr, struct sockaddr_storage *host) 30881634Sbrian{ 30981634Sbrian struct sockaddr_in *host4 = (struct sockaddr_in *)host; 31081634Sbrian#ifndef NOINET6 31181634Sbrian struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host; 31281634Sbrian#endif 31381634Sbrian 31481634Sbrian memset(host, '\0', sizeof(*host)); 31581634Sbrian 31681634Sbrian switch (addr->ncpaddr_family) { 31781634Sbrian case AF_INET: 31881634Sbrian host4->sin_family = AF_INET; 31981634Sbrian host4->sin_len = sizeof(*host4); 32081634Sbrian host4->sin_addr = addr->ncpaddr_ip4addr; 32181634Sbrian break; 32281634Sbrian 32381634Sbrian#ifndef NOINET6 32481634Sbrian case AF_INET6: 32581634Sbrian host6->sin6_family = AF_INET6; 32681634Sbrian host6->sin6_len = sizeof(*host6); 32781634Sbrian host6->sin6_addr = addr->ncpaddr_ip6addr; 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; 388134789Sbrian#if 0 38981634Sbrian adjust_linklocal(&sin6); 390134789Sbrian#endif 39181634Sbrian if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res), 392102558Sbrian NULL, 0, NI_NUMERICHOST) != 0) 39381634Sbrian break; 39481634Sbrian 39581634Sbrian return res; 39681634Sbrian#endif 39781634Sbrian } 39881634Sbrian 39981634Sbrian snprintf(res, sizeof res, "<AF_UNSPEC>"); 40081634Sbrian return res; 40181634Sbrian} 40281634Sbrian 40381634Sbrianconst char * 40481634Sbrianncpaddr_ntoa(const struct ncpaddr *addr) 40581634Sbrian{ 40681634Sbrian return ncpaddr_ntowa(addr); 40781634Sbrian} 40881634Sbrian 40981634Sbrian 41081634Sbrianint 41181634Sbrianncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data) 41281634Sbrian{ 41381634Sbrian struct ncprange range; 41481634Sbrian 41581634Sbrian if (!ncprange_aton(&range, ncp, data)) 41681634Sbrian return 0; 41798243Sbrian 418116654Sume if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32 && 419116654Sume range.ncprange_ip4addr.s_addr != INADDR_ANY) { 42081634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data); 42181634Sbrian return 0; 42281634Sbrian } 42381634Sbrian 42481634Sbrian#ifndef NOINET6 425116654Sume if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128 && 426116654Sume !IN6_IS_ADDR_UNSPECIFIED(&range.ncprange_ip6addr)) { 42781634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data); 42881634Sbrian return 0; 42981634Sbrian } 43081634Sbrian#endif 43181634Sbrian 43281634Sbrian switch (range.ncprange_family) { 43381634Sbrian case AF_INET: 43481634Sbrian addr->ncpaddr_family = range.ncprange_family; 43581634Sbrian addr->ncpaddr_ip4addr = range.ncprange_ip4addr; 43681634Sbrian return 1; 43781634Sbrian 43881634Sbrian#ifndef NOINET6 43981634Sbrian case AF_INET6: 44081634Sbrian addr->ncpaddr_family = range.ncprange_family; 44181634Sbrian addr->ncpaddr_ip6addr = range.ncprange_ip6addr; 44281634Sbrian return 1; 44381634Sbrian#endif 44481634Sbrian } 44581634Sbrian 44681634Sbrian return 0; 44781634Sbrian} 44881634Sbrian 44981634Sbrianvoid 45081634Sbrianncprange_init(struct ncprange *range) 45181634Sbrian{ 45281634Sbrian range->ncprange_family = AF_UNSPEC; 45381634Sbrian} 45481634Sbrian 45581634Sbrianint 45681634Sbrianncprange_isset(const struct ncprange *range) 45781634Sbrian{ 45881634Sbrian return range->ncprange_family != AF_UNSPEC; 45981634Sbrian} 46081634Sbrian 46181634Sbrianint 46281634Sbrianncprange_equal(const struct ncprange *range, const struct ncprange *cmp) 46381634Sbrian{ 46481634Sbrian if (range->ncprange_family != cmp->ncprange_family) 46581634Sbrian return 0; 46681634Sbrian 46781634Sbrian switch (range->ncprange_family) { 46881634Sbrian case AF_INET: 46981634Sbrian if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr) 47081634Sbrian return 0; 47181634Sbrian return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr; 47281634Sbrian 47381634Sbrian#ifndef NOINET6 47481634Sbrian case AF_INET6: 47581634Sbrian if (range->ncprange_ip6width != cmp->ncprange_ip6width) 47681634Sbrian return 0; 47781634Sbrian return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr, 47881634Sbrian sizeof range->ncprange_ip6addr); 47981634Sbrian#endif 48081634Sbrian 48181634Sbrian case AF_UNSPEC: 48281634Sbrian return 1; 48381634Sbrian } 48481634Sbrian 48581634Sbrian return 0; 48681634Sbrian} 48781634Sbrian 48881634Sbrianint 48981634Sbrianncprange_isdefault(const struct ncprange *range) 49081634Sbrian{ 49181634Sbrian switch (range->ncprange_family) { 49281634Sbrian case AF_INET: 49381634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) 49481634Sbrian return 1; 49581634Sbrian break; 49681634Sbrian 49781634Sbrian#ifndef NOINET6 49881634Sbrian case AF_INET6: 49981634Sbrian if (range->ncprange_ip6width == 0 && 50081634Sbrian IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 50181634Sbrian return 1; 50281634Sbrian break; 50381634Sbrian#endif 50481634Sbrian } 50581634Sbrian 50681634Sbrian return 0; 50781634Sbrian} 50881634Sbrian 50981634Sbrianvoid 51081634Sbrianncprange_setdefault(struct ncprange *range, int af) 51181634Sbrian{ 51281634Sbrian memset(range, '\0', sizeof *range); 51381634Sbrian range->ncprange_family = af; 51481634Sbrian} 51581634Sbrian 51681634Sbrianint 51781634Sbrianncprange_contains(const struct ncprange *range, const struct ncpaddr *addr) 51881634Sbrian{ 51981634Sbrian#ifndef NOINET6 52081634Sbrian const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 52181634Sbrian const u_char *addrp, *rangep; 52281634Sbrian int bits; 52381634Sbrian#endif 52481634Sbrian 52581634Sbrian if (range->ncprange_family != addr->ncpaddr_family) 52681634Sbrian return 0; 52781634Sbrian 52881634Sbrian switch (range->ncprange_family) { 52981634Sbrian case AF_INET: 53081634Sbrian return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 53181634Sbrian range->ncprange_ip4mask.s_addr); 53281634Sbrian 53381634Sbrian#ifndef NOINET6 53481634Sbrian case AF_INET6: 53581634Sbrian rangep = (const u_char *)range->ncprange_ip6addr.s6_addr; 53681634Sbrian addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr; 53781634Sbrian 53881634Sbrian for (bits = range->ncprange_ip6width; bits > 0; bits -= 8) 53981634Sbrian if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1]) 54081634Sbrian return 0; 54181634Sbrian 54281634Sbrian return 1; 54381634Sbrian#endif 54481634Sbrian } 54581634Sbrian 54681634Sbrian return 0; 54781634Sbrian} 54881634Sbrian 54981634Sbrianint 55081634Sbrianncprange_containsip4(const struct ncprange *range, struct in_addr addr) 55181634Sbrian{ 55281634Sbrian switch (range->ncprange_family) { 55381634Sbrian case AF_INET: 55481634Sbrian return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 55581634Sbrian range->ncprange_ip4mask.s_addr); 55681634Sbrian } 55781634Sbrian 55881634Sbrian return 0; 55981634Sbrian} 56081634Sbrian 56181634Sbrianvoid 56281634Sbrianncprange_copy(struct ncprange *range, const struct ncprange *from) 56381634Sbrian{ 56481634Sbrian switch (from->ncprange_family) { 56581634Sbrian case AF_INET: 56681634Sbrian range->ncprange_family = AF_INET; 56781634Sbrian range->ncprange_ip4addr = from->ncprange_ip4addr; 56881634Sbrian range->ncprange_ip4mask = from->ncprange_ip4mask; 56981634Sbrian range->ncprange_ip4width = from->ncprange_ip4width; 57081634Sbrian break; 57181634Sbrian 57281634Sbrian#ifndef NOINET6 57381634Sbrian case AF_INET6: 57481634Sbrian range->ncprange_family = AF_INET6; 57581634Sbrian range->ncprange_ip6addr = from->ncprange_ip6addr; 57681634Sbrian range->ncprange_ip6width = from->ncprange_ip6width; 57781634Sbrian break; 57881634Sbrian#endif 57981634Sbrian 58081634Sbrian default: 58181634Sbrian range->ncprange_family = AF_UNSPEC; 58281634Sbrian } 58381634Sbrian} 58481634Sbrian 58581634Sbrianvoid 58681634Sbrianncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width) 58781634Sbrian{ 58881634Sbrian ncprange_sethost(range, addr); 58981634Sbrian ncprange_setwidth(range, width); 59081634Sbrian} 59181634Sbrian 59281634Sbrianvoid 59381634Sbrianncprange_sethost(struct ncprange *range, const struct ncpaddr *from) 59481634Sbrian{ 59581634Sbrian switch (from->ncpaddr_family) { 59681634Sbrian case AF_INET: 59781634Sbrian range->ncprange_family = AF_INET; 59881634Sbrian range->ncprange_ip4addr = from->ncpaddr_ip4addr; 59986832Sbrian if (from->ncpaddr_ip4addr.s_addr == INADDR_ANY) { 60086832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 60186832Sbrian range->ncprange_ip4width = 0; 60286832Sbrian } else { 60386832Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 60486832Sbrian range->ncprange_ip4width = 32; 60586832Sbrian } 60681634Sbrian break; 60781634Sbrian 60881634Sbrian#ifndef NOINET6 60981634Sbrian case AF_INET6: 61081634Sbrian range->ncprange_family = AF_INET6; 61181634Sbrian range->ncprange_ip6addr = from->ncpaddr_ip6addr; 61281634Sbrian range->ncprange_ip6width = 128; 61381634Sbrian break; 61481634Sbrian#endif 61581634Sbrian 61681634Sbrian default: 61781634Sbrian range->ncprange_family = AF_UNSPEC; 61881634Sbrian } 61981634Sbrian} 62081634Sbrian 62181634Sbrianint 62286815Sbrianncprange_ishost(const struct ncprange *range) 62386815Sbrian{ 62486815Sbrian switch (range->ncprange_family) { 62586815Sbrian case AF_INET: 62686815Sbrian return range->ncprange_ip4width == 32; 62786815Sbrian#ifndef NOINET6 62886815Sbrian case AF_INET6: 62986815Sbrian return range->ncprange_ip6width == 128; 63086815Sbrian#endif 63186815Sbrian } 63286815Sbrian 63386815Sbrian return (0); 63486815Sbrian} 63586815Sbrian 63686815Sbrianint 63781634Sbrianncprange_setwidth(struct ncprange *range, int width) 63881634Sbrian{ 63981634Sbrian switch (range->ncprange_family) { 64081634Sbrian case AF_INET: 64181634Sbrian if (width < 0 || width > 32) 64281634Sbrian break; 64381634Sbrian range->ncprange_ip4width = width; 64481634Sbrian range->ncprange_ip4mask = bits2mask4(width); 64581634Sbrian break; 64681634Sbrian 64781634Sbrian#ifndef NOINET6 64881634Sbrian case AF_INET6: 64981634Sbrian if (width < 0 || width > 128) 65081634Sbrian break; 65181634Sbrian range->ncprange_ip6width = width; 65281634Sbrian break; 65381634Sbrian#endif 65481634Sbrian 65581634Sbrian case AF_UNSPEC: 65681634Sbrian return 1; 65781634Sbrian } 65881634Sbrian 65981634Sbrian return 0; 66081634Sbrian} 66181634Sbrian 66281634Sbrianvoid 66381634Sbrianncprange_setip4host(struct ncprange *range, struct in_addr from) 66481634Sbrian{ 66581634Sbrian range->ncprange_family = AF_INET; 66681634Sbrian range->ncprange_ip4addr = from; 66786832Sbrian if (from.s_addr == INADDR_ANY) { 66886832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 66986832Sbrian range->ncprange_ip4width = 0; 67086832Sbrian } else { 67186832Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 67286832Sbrian range->ncprange_ip4width = 32; 67386832Sbrian } 67481634Sbrian} 67581634Sbrian 67681634Sbrianvoid 67781634Sbrianncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk) 67881634Sbrian{ 67981634Sbrian range->ncprange_family = AF_INET; 68081634Sbrian range->ncprange_ip4addr = from; 68181634Sbrian range->ncprange_ip4mask = msk; 68281634Sbrian range->ncprange_ip4width = mask42bits(msk); 68381634Sbrian} 68481634Sbrian 68581634Sbrian 68681634Sbrianint 68781634Sbrianncprange_setip4mask(struct ncprange *range, struct in_addr mask) 68881634Sbrian{ 68981634Sbrian if (range->ncprange_family != AF_INET) 69081634Sbrian return 0; 69181634Sbrian range->ncprange_ip4mask = mask; 69281634Sbrian range->ncprange_ip4width = mask42bits(mask); 69381634Sbrian return 1; 69481634Sbrian} 69581634Sbrian 69681634Sbrianvoid 69781634Sbrianncprange_setsa(struct ncprange *range, const struct sockaddr *host, 69881634Sbrian const struct sockaddr *mask) 69981634Sbrian{ 70081634Sbrian const struct sockaddr_in *host4 = (const struct sockaddr_in *)host; 70181634Sbrian const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask; 70281634Sbrian#ifndef NOINET6 70381634Sbrian const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host; 70481634Sbrian const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask; 70581634Sbrian#endif 70681634Sbrian 70781634Sbrian switch (host->sa_family) { 70881634Sbrian case AF_INET: 70981634Sbrian range->ncprange_family = AF_INET; 71081634Sbrian range->ncprange_ip4addr = host4->sin_addr; 71186832Sbrian if (host4->sin_addr.s_addr == INADDR_ANY) { 71286832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 71386832Sbrian range->ncprange_ip4width = 0; 71486832Sbrian } else if (mask4 && mask4->sin_family == AF_INET) { 71581634Sbrian range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr; 71681634Sbrian range->ncprange_ip4width = mask42bits(mask4->sin_addr); 71781634Sbrian } else { 71881634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 71981634Sbrian range->ncprange_ip4width = 32; 72081634Sbrian } 72181634Sbrian break; 72281634Sbrian 72381634Sbrian#ifndef NOINET6 72481634Sbrian case AF_INET6: 72581634Sbrian range->ncprange_family = AF_INET6; 72681634Sbrian range->ncprange_ip6addr = host6->sin6_addr; 727113110Sume if (IN6_IS_ADDR_UNSPECIFIED(&host6->sin6_addr)) 728113110Sume range->ncprange_ip6width = 0; 729113110Sume else 730113110Sume range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128; 73181634Sbrian break; 73281634Sbrian#endif 73381634Sbrian 73481634Sbrian default: 73581634Sbrian range->ncprange_family = AF_UNSPEC; 73681634Sbrian } 73781634Sbrian} 73881634Sbrian 73981634Sbrianvoid 74081634Sbrianncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host, 74181634Sbrian struct sockaddr_storage *mask) 74281634Sbrian{ 74381634Sbrian struct sockaddr_in *host4 = (struct sockaddr_in *)host; 74481634Sbrian struct sockaddr_in *mask4 = (struct sockaddr_in *)mask; 74581634Sbrian#ifndef NOINET6 74681634Sbrian struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host; 74781634Sbrian struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask; 74881634Sbrian#endif 74981634Sbrian 75081634Sbrian memset(host, '\0', sizeof(*host)); 75181634Sbrian if (mask) 75281634Sbrian memset(mask, '\0', sizeof(*mask)); 75381634Sbrian 75481634Sbrian switch (range->ncprange_family) { 75581634Sbrian case AF_INET: 75681634Sbrian host4->sin_family = AF_INET; 75781634Sbrian host4->sin_len = sizeof(*host4); 75881634Sbrian host4->sin_addr = range->ncprange_ip4addr; 75981634Sbrian if (mask4) { 76081634Sbrian mask4->sin_family = AF_INET; 76181634Sbrian mask4->sin_len = sizeof(*host4); 76281690Sbrian mask4->sin_addr = range->ncprange_ip4mask; 76381634Sbrian } 76481634Sbrian break; 76581634Sbrian 76681634Sbrian#ifndef NOINET6 76781634Sbrian case AF_INET6: 76881634Sbrian host6->sin6_family = AF_INET6; 76981634Sbrian host6->sin6_len = sizeof(*host6); 77081634Sbrian host6->sin6_addr = range->ncprange_ip6addr; 77181634Sbrian if (mask6) { 77281634Sbrian mask6->sin6_family = AF_INET6; 77381634Sbrian mask6->sin6_len = sizeof(*host6); 77481634Sbrian mask6->sin6_addr = bits2mask6(range->ncprange_ip6width); 77581634Sbrian } 77681634Sbrian break; 77781634Sbrian#endif 77881634Sbrian 77981634Sbrian default: 78081634Sbrian host->ss_family = AF_UNSPEC; 78181634Sbrian if (mask) 78281634Sbrian mask->ss_family = AF_UNSPEC; 78381634Sbrian break; 78481634Sbrian } 78581634Sbrian} 78681634Sbrian 78781634Sbrianint 78881634Sbrianncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr) 78981634Sbrian{ 79081634Sbrian switch (range->ncprange_family) { 79181634Sbrian case AF_INET: 79281634Sbrian addr->ncpaddr_family = AF_INET; 79381634Sbrian addr->ncpaddr_ip4addr = range->ncprange_ip4addr; 79481634Sbrian return 1; 79581634Sbrian#ifndef NOINET6 79681634Sbrian case AF_INET6: 79781634Sbrian addr->ncpaddr_family = AF_INET6; 79881634Sbrian addr->ncpaddr_ip6addr = range->ncprange_ip6addr; 79981634Sbrian return 1; 80081634Sbrian#endif 80181634Sbrian } 80281634Sbrian 80381634Sbrian return 0; 80481634Sbrian} 80581634Sbrian 80681634Sbrianint 80781634Sbrianncprange_getip4addr(const struct ncprange *range, struct in_addr *addr) 80881634Sbrian{ 80981634Sbrian if (range->ncprange_family != AF_INET) 81081634Sbrian return 0; 81181634Sbrian 81281634Sbrian *addr = range->ncprange_ip4addr; 81381634Sbrian return 1; 81481634Sbrian} 81581634Sbrian 81681634Sbrianint 81781634Sbrianncprange_getip4mask(const struct ncprange *range, struct in_addr *mask) 81881634Sbrian{ 81981634Sbrian switch (range->ncprange_family) { 82081634Sbrian case AF_INET: 82181634Sbrian *mask = range->ncprange_ip4mask; 82281634Sbrian return 1; 82381634Sbrian } 82481634Sbrian 82581634Sbrian return 0; 82681634Sbrian} 82781634Sbrian 82881634Sbrianint 82981634Sbrianncprange_getwidth(const struct ncprange *range, int *width) 83081634Sbrian{ 83181634Sbrian switch (range->ncprange_family) { 83281634Sbrian case AF_INET: 83381634Sbrian *width = range->ncprange_ip4width; 83481634Sbrian return 1; 83581634Sbrian#ifndef NOINET6 83681634Sbrian case AF_INET6: 83781634Sbrian *width = range->ncprange_ip6width; 83881634Sbrian return 1; 83981634Sbrian#endif 84081634Sbrian } 84181634Sbrian 84281634Sbrian return 0; 84381634Sbrian} 84481634Sbrian 84581634Sbrianconst char * 84681634Sbrianncprange_ntoa(const struct ncprange *range) 84781634Sbrian{ 84881634Sbrian char *res; 84981634Sbrian struct ncpaddr addr; 85081634Sbrian int len; 85181634Sbrian 85281634Sbrian if (!ncprange_getaddr(range, &addr)) 85381634Sbrian return "<AF_UNSPEC>"; 85481634Sbrian 85581634Sbrian res = ncpaddr_ntowa(&addr); 85681634Sbrian len = strlen(res); 85781634Sbrian if (len >= NCP_ASCIIBUFFERSIZE - 1) 85881634Sbrian return res; 85981634Sbrian 86081634Sbrian switch (range->ncprange_family) { 86181634Sbrian case AF_INET: 86281634Sbrian if (range->ncprange_ip4width == -1) { 86381634Sbrian /* A non-contiguous mask */ 86481634Sbrian for (; len >= 3; res[len -= 2] = '\0') 86581634Sbrian if (strcmp(res + len - 2, ".0")) 86681634Sbrian break; 86781634Sbrian snprintf(res + len, sizeof res - len, "&0x%08lx", 86881924Sbrian (unsigned long)ntohl(range->ncprange_ip4mask.s_addr)); 86981634Sbrian } else if (range->ncprange_ip4width < 32) 87081634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width); 87181634Sbrian 87281634Sbrian return res; 87381634Sbrian 87481634Sbrian#ifndef NOINET6 87581634Sbrian case AF_INET6: 87681634Sbrian if (range->ncprange_ip6width != 128) 87781634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width); 87881634Sbrian 87981634Sbrian return res; 88081634Sbrian#endif 88181634Sbrian } 88281634Sbrian 88381634Sbrian return "<AF_UNSPEC>"; 88481634Sbrian} 88581634Sbrian 88681634Sbrian#ifndef NOINET6 88781634Sbrianint 88881634Sbrianncprange_scopeid(const struct ncprange *range) 88981634Sbrian{ 89081634Sbrian const struct in6_addr *sin6; 89181634Sbrian int scopeid = -1; 89281634Sbrian 89381634Sbrian if (range->ncprange_family == AF_INET6) { 89481634Sbrian sin6 = &range->ncprange_ip6addr; 89581634Sbrian if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6)) 89681634Sbrian if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0) 89781634Sbrian scopeid = -1; 89881634Sbrian } 89981634Sbrian 90081634Sbrian return scopeid; 90181634Sbrian} 90281634Sbrian#endif 90381634Sbrian 90481634Sbrianint 90581634Sbrianncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data) 90681634Sbrian{ 90781634Sbrian int bits, len; 90881634Sbrian char *wp; 90981634Sbrian const char *cp; 91081634Sbrian char *s; 91181634Sbrian 91281634Sbrian len = strcspn(data, "/"); 91381634Sbrian 91481634Sbrian if (ncp && strncasecmp(data, "HISADDR", len) == 0) { 91581634Sbrian range->ncprange_family = AF_INET; 91681634Sbrian range->ncprange_ip4addr = ncp->ipcp.peer_ip; 91781634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 91881634Sbrian range->ncprange_ip4width = 32; 91981634Sbrian return 1; 92081634Sbrian#ifndef NOINET6 92181634Sbrian } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) { 922112673Sume range->ncprange_family = AF_INET6; 923112673Sume range->ncprange_ip6addr = ncp->ipv6cp.hisaddr.ncpaddr_ip6addr; 924112673Sume range->ncprange_ip6width = 128; 92581634Sbrian return 1; 92681634Sbrian#endif 92781634Sbrian } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) { 92881634Sbrian range->ncprange_family = AF_INET; 92981634Sbrian range->ncprange_ip4addr = ncp->ipcp.my_ip; 93081634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 93181634Sbrian range->ncprange_ip4width = 32; 93281634Sbrian return 1; 93381634Sbrian#ifndef NOINET6 93481634Sbrian } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) { 935112673Sume range->ncprange_family = AF_INET6; 936112673Sume range->ncprange_ip6addr = ncp->ipv6cp.myaddr.ncpaddr_ip6addr; 937112673Sume range->ncprange_ip6width = 128; 93881634Sbrian return 1; 93981634Sbrian#endif 94081634Sbrian } else if (ncp && strncasecmp(data, "DNS0", len) == 0) { 94181634Sbrian range->ncprange_family = AF_INET; 94281634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[0]; 94381634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 94481634Sbrian range->ncprange_ip4width = 32; 94581634Sbrian return 1; 94681634Sbrian } else if (ncp && strncasecmp(data, "DNS1", len) == 0) { 94781634Sbrian range->ncprange_family = AF_INET; 94881634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[1]; 94981634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 95081634Sbrian range->ncprange_ip4width = 32; 95181634Sbrian return 1; 95281634Sbrian } 95381634Sbrian 95481634Sbrian s = (char *)alloca(len + 1); 95581634Sbrian strncpy(s, data, len); 95681634Sbrian s[len] = '\0'; 95781634Sbrian bits = -1; 95881634Sbrian 95981634Sbrian if (data[len] != '\0') { 96081634Sbrian bits = strtol(data + len + 1, &wp, 0); 96181634Sbrian if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) { 96281634Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 96381634Sbrian return 0; 96481634Sbrian } 96581634Sbrian } 96681634Sbrian 96781634Sbrian if ((cp = strchr(data, ':')) == NULL) { 96881634Sbrian range->ncprange_family = AF_INET; 96981634Sbrian 97081634Sbrian range->ncprange_ip4addr = GetIpAddr(s); 97181634Sbrian 97281634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_NONE) { 97381634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 97481634Sbrian return 0; 97581634Sbrian } 97681634Sbrian 97781634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) { 97881634Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 97981634Sbrian range->ncprange_ip4width = 0; 98081690Sbrian } else if (bits == -1) { 98181634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 98281634Sbrian range->ncprange_ip4width = 32; 98381690Sbrian } else if (bits > 32) { 98481690Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 98581690Sbrian return 0; 98681634Sbrian } else { 98781634Sbrian range->ncprange_ip4mask = bits2mask4(bits); 98881634Sbrian range->ncprange_ip4width = bits; 98981634Sbrian } 99081634Sbrian 99181634Sbrian return 1; 99281634Sbrian#ifndef NOINET6 99381634Sbrian } else if (strchr(cp + 1, ':') != NULL) { 99481634Sbrian range->ncprange_family = AF_INET6; 99581634Sbrian 99681634Sbrian if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) { 99781634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 99881634Sbrian return 0; 99981634Sbrian } 100081634Sbrian 100181634Sbrian if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 100281634Sbrian range->ncprange_ip6width = 0; 100381634Sbrian else 100481634Sbrian range->ncprange_ip6width = (bits == -1) ? 128 : bits; 100581634Sbrian return 1; 100681634Sbrian#endif 100781634Sbrian } 100881634Sbrian 100981634Sbrian return 0; 101081634Sbrian} 1011