ncpaddr.c revision 113110
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 113110 2003-04-05 10:10:33Z ume $ 2781634Sbrian */ 2881634Sbrian 2981634Sbrian#include <sys/types.h> 3081634Sbrian#include <sys/socket.h> 3196732Sbrian#ifdef __OpenBSD__ 3296732Sbrian#include <net/if_types.h> 3396732Sbrian#include <net/route.h> 3496732Sbrian#endif 3581634Sbrian#include <netinet/in.h> 3681634Sbrian#include <netinet/in_systm.h> 3781634Sbrian#include <netinet/ip.h> 3881634Sbrian#include <arpa/inet.h> 3981634Sbrian#include <sys/un.h> 4081634Sbrian 4181634Sbrian#include <netdb.h> 4281634Sbrian#include <stdio.h> 4381634Sbrian#include <stdlib.h> 4481634Sbrian#include <string.h> 4581634Sbrian#include <termios.h> 4681634Sbrian 4781634Sbrian#include "log.h" 4881634Sbrian#include "ncpaddr.h" 4981634Sbrian#include "timer.h" 5081634Sbrian#include "fsm.h" 5181634Sbrian#include "defs.h" 5281634Sbrian#include "slcompress.h" 5381634Sbrian#include "iplist.h" 5481634Sbrian#include "throughput.h" 5581634Sbrian#include "mbuf.h" 5681634Sbrian#include "ipcp.h" 5781634Sbrian#include "descriptor.h" 5881634Sbrian#include "layer.h" 5981634Sbrian#include "lqr.h" 6081634Sbrian#include "hdlc.h" 6181634Sbrian#include "lcp.h" 6281634Sbrian#include "ccp.h" 6381634Sbrian#include "link.h" 6481634Sbrian#include "mp.h" 6581634Sbrian#include "ipv6cp.h" 6681634Sbrian#include "ncp.h" 6781634Sbrian 6881634Sbrian 6981634Sbrian#define ncprange_ip4addr u.ip4.ipaddr 7081634Sbrian#define ncprange_ip4mask u.ip4.mask 7181634Sbrian#define ncprange_ip4width u.ip4.width 7281634Sbrian#define ncpaddr_ip4addr u.ip4addr 7381634Sbrian#ifndef NOINET6 7481634Sbrian#define ncprange_ip6addr u.ip6.ipaddr 7581634Sbrian#define ncprange_ip6width u.ip6.width 7681634Sbrian#define ncpaddr_ip6addr u.ip6addr 7781634Sbrian#endif 7881634Sbrian 7981634Sbrian#define NCP_ASCIIBUFFERSIZE 52 8081634Sbrian 8181634Sbrianstatic struct in_addr 8281634Sbrianbits2mask4(int bits) 8381634Sbrian{ 8481634Sbrian struct in_addr result; 8581634Sbrian u_int32_t bit = 0x80000000; 8681634Sbrian 8781634Sbrian result.s_addr = 0; 8881634Sbrian 8981634Sbrian while (bits) { 9081634Sbrian result.s_addr |= bit; 9181634Sbrian bit >>= 1; 9281634Sbrian bits--; 9381634Sbrian } 9481634Sbrian 9581634Sbrian result.s_addr = htonl(result.s_addr); 9681634Sbrian return result; 9781634Sbrian} 9881634Sbrian 9981634Sbrianstatic int 10081634Sbrianmask42bits(struct in_addr mask) 10181634Sbrian{ 10281634Sbrian u_int32_t msk = ntohl(mask.s_addr); 10381634Sbrian u_int32_t tst; 10481634Sbrian int ret; 10581634Sbrian 10681634Sbrian for (ret = 32, tst = 1; tst; ret--, tst <<= 1) 10781634Sbrian if (msk & tst) 10881634Sbrian break; 10981634Sbrian 11081634Sbrian for (tst <<= 1; tst; tst <<= 1) 11181634Sbrian if (!(msk & tst)) 11281634Sbrian break; 11381634Sbrian 11481634Sbrian return tst ? -1 : ret; 11581634Sbrian} 11681634Sbrian 11781634Sbrian#ifndef NOINET6 11881634Sbrianstatic struct in6_addr 11981634Sbrianbits2mask6(int bits) 12081634Sbrian{ 12181634Sbrian struct in6_addr result; 12281634Sbrian u_int32_t bit = 0x80; 12381634Sbrian u_char *c = result.s6_addr; 12481634Sbrian 12581634Sbrian memset(&result, '\0', sizeof result); 12681634Sbrian 12781634Sbrian while (bits) { 12881634Sbrian if (bit == 0) { 12981634Sbrian bit = 0x80; 13081634Sbrian c++; 13181634Sbrian } 13281634Sbrian *c |= bit; 13381634Sbrian bit >>= 1; 13481634Sbrian bits--; 13581634Sbrian } 13681634Sbrian 13781634Sbrian return result; 13881634Sbrian} 13981634Sbrian 14081634Sbrianstatic int 14181634Sbrianmask62bits(const struct in6_addr *mask) 14281634Sbrian{ 14381634Sbrian const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; 14481634Sbrian const u_char *c, *p, *end; 14581634Sbrian int masklen; 14681634Sbrian 14781634Sbrian p = (const u_char *)mask; 14881634Sbrian for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++) 14981634Sbrian masklen += 8; 15081634Sbrian 15181634Sbrian if (p < end) { 15281634Sbrian for (c = masks; c < masks + sizeof masks; c++) 15381634Sbrian if (*c == *p) { 15481634Sbrian masklen += c - masks; 15581634Sbrian break; 15681634Sbrian } 15781634Sbrian } 15881634Sbrian 15981634Sbrian return masklen; 16081634Sbrian} 16181634Sbrian 16281634Sbrianstatic void 16381634Sbrianadjust_linklocal(struct sockaddr_in6 *sin6) 16481634Sbrian{ 16581634Sbrian /* XXX: ?????!?!?!!!!! This is horrible ! */ 166102558Sbrian#if 0 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 } 178102558Sbrian#endif 17981634Sbrian} 18081634Sbrian#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; 38881634Sbrian adjust_linklocal(&sin6); 389102558Sbrian#ifdef NI_WITHSCOPEID 39081634Sbrian if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res), 39181634Sbrian NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST) != 0) 392102558Sbrian#else 393102558Sbrian if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res), 394102558Sbrian NULL, 0, NI_NUMERICHOST) != 0) 395102558Sbrian#endif 39681634Sbrian break; 39781634Sbrian 39881634Sbrian return res; 39981634Sbrian#endif 40081634Sbrian } 40181634Sbrian 40281634Sbrian snprintf(res, sizeof res, "<AF_UNSPEC>"); 40381634Sbrian return res; 40481634Sbrian} 40581634Sbrian 40681634Sbrianconst char * 40781634Sbrianncpaddr_ntoa(const struct ncpaddr *addr) 40881634Sbrian{ 40981634Sbrian return ncpaddr_ntowa(addr); 41081634Sbrian} 41181634Sbrian 41281634Sbrian 41381634Sbrianint 41481634Sbrianncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data) 41581634Sbrian{ 41681634Sbrian struct ncprange range; 41781634Sbrian 41881634Sbrian if (!ncprange_aton(&range, ncp, data)) 41981634Sbrian return 0; 42098243Sbrian 42181634Sbrian if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32) { 42281634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data); 42381634Sbrian return 0; 42481634Sbrian } 42581634Sbrian 42681634Sbrian#ifndef NOINET6 42781634Sbrian if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128) { 42881634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data); 42981634Sbrian return 0; 43081634Sbrian } 43181634Sbrian#endif 43281634Sbrian 43381634Sbrian switch (range.ncprange_family) { 43481634Sbrian case AF_INET: 43581634Sbrian addr->ncpaddr_family = range.ncprange_family; 43681634Sbrian addr->ncpaddr_ip4addr = range.ncprange_ip4addr; 43781634Sbrian return 1; 43881634Sbrian 43981634Sbrian#ifndef NOINET6 44081634Sbrian case AF_INET6: 44181634Sbrian addr->ncpaddr_family = range.ncprange_family; 44281634Sbrian addr->ncpaddr_ip6addr = range.ncprange_ip6addr; 44381634Sbrian return 1; 44481634Sbrian#endif 44581634Sbrian } 44681634Sbrian 44781634Sbrian return 0; 44881634Sbrian} 44981634Sbrian 45081634Sbrianvoid 45181634Sbrianncprange_init(struct ncprange *range) 45281634Sbrian{ 45381634Sbrian range->ncprange_family = AF_UNSPEC; 45481634Sbrian} 45581634Sbrian 45681634Sbrianint 45781634Sbrianncprange_isset(const struct ncprange *range) 45881634Sbrian{ 45981634Sbrian return range->ncprange_family != AF_UNSPEC; 46081634Sbrian} 46181634Sbrian 46281634Sbrianint 46381634Sbrianncprange_equal(const struct ncprange *range, const struct ncprange *cmp) 46481634Sbrian{ 46581634Sbrian if (range->ncprange_family != cmp->ncprange_family) 46681634Sbrian return 0; 46781634Sbrian 46881634Sbrian switch (range->ncprange_family) { 46981634Sbrian case AF_INET: 47081634Sbrian if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr) 47181634Sbrian return 0; 47281634Sbrian return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr; 47381634Sbrian 47481634Sbrian#ifndef NOINET6 47581634Sbrian case AF_INET6: 47681634Sbrian if (range->ncprange_ip6width != cmp->ncprange_ip6width) 47781634Sbrian return 0; 47881634Sbrian return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr, 47981634Sbrian sizeof range->ncprange_ip6addr); 48081634Sbrian#endif 48181634Sbrian 48281634Sbrian case AF_UNSPEC: 48381634Sbrian return 1; 48481634Sbrian } 48581634Sbrian 48681634Sbrian return 0; 48781634Sbrian} 48881634Sbrian 48981634Sbrianint 49081634Sbrianncprange_isdefault(const struct ncprange *range) 49181634Sbrian{ 49281634Sbrian switch (range->ncprange_family) { 49381634Sbrian case AF_INET: 49481634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) 49581634Sbrian return 1; 49681634Sbrian break; 49781634Sbrian 49881634Sbrian#ifndef NOINET6 49981634Sbrian case AF_INET6: 50081634Sbrian if (range->ncprange_ip6width == 0 && 50181634Sbrian IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 50281634Sbrian return 1; 50381634Sbrian break; 50481634Sbrian#endif 50581634Sbrian } 50681634Sbrian 50781634Sbrian return 0; 50881634Sbrian} 50981634Sbrian 51081634Sbrianvoid 51181634Sbrianncprange_setdefault(struct ncprange *range, int af) 51281634Sbrian{ 51381634Sbrian memset(range, '\0', sizeof *range); 51481634Sbrian range->ncprange_family = af; 51581634Sbrian} 51681634Sbrian 51781634Sbrianint 51881634Sbrianncprange_contains(const struct ncprange *range, const struct ncpaddr *addr) 51981634Sbrian{ 52081634Sbrian#ifndef NOINET6 52181634Sbrian const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 52281634Sbrian const u_char *addrp, *rangep; 52381634Sbrian int bits; 52481634Sbrian#endif 52581634Sbrian 52681634Sbrian if (range->ncprange_family != addr->ncpaddr_family) 52781634Sbrian return 0; 52881634Sbrian 52981634Sbrian switch (range->ncprange_family) { 53081634Sbrian case AF_INET: 53181634Sbrian return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 53281634Sbrian range->ncprange_ip4mask.s_addr); 53381634Sbrian 53481634Sbrian#ifndef NOINET6 53581634Sbrian case AF_INET6: 53681634Sbrian rangep = (const u_char *)range->ncprange_ip6addr.s6_addr; 53781634Sbrian addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr; 53881634Sbrian 53981634Sbrian for (bits = range->ncprange_ip6width; bits > 0; bits -= 8) 54081634Sbrian if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1]) 54181634Sbrian return 0; 54281634Sbrian 54381634Sbrian return 1; 54481634Sbrian#endif 54581634Sbrian } 54681634Sbrian 54781634Sbrian return 0; 54881634Sbrian} 54981634Sbrian 55081634Sbrianint 55181634Sbrianncprange_containsip4(const struct ncprange *range, struct in_addr addr) 55281634Sbrian{ 55381634Sbrian switch (range->ncprange_family) { 55481634Sbrian case AF_INET: 55581634Sbrian return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 55681634Sbrian range->ncprange_ip4mask.s_addr); 55781634Sbrian } 55881634Sbrian 55981634Sbrian return 0; 56081634Sbrian} 56181634Sbrian 56281634Sbrianvoid 56381634Sbrianncprange_copy(struct ncprange *range, const struct ncprange *from) 56481634Sbrian{ 56581634Sbrian switch (from->ncprange_family) { 56681634Sbrian case AF_INET: 56781634Sbrian range->ncprange_family = AF_INET; 56881634Sbrian range->ncprange_ip4addr = from->ncprange_ip4addr; 56981634Sbrian range->ncprange_ip4mask = from->ncprange_ip4mask; 57081634Sbrian range->ncprange_ip4width = from->ncprange_ip4width; 57181634Sbrian break; 57281634Sbrian 57381634Sbrian#ifndef NOINET6 57481634Sbrian case AF_INET6: 57581634Sbrian range->ncprange_family = AF_INET6; 57681634Sbrian range->ncprange_ip6addr = from->ncprange_ip6addr; 57781634Sbrian range->ncprange_ip6width = from->ncprange_ip6width; 57881634Sbrian break; 57981634Sbrian#endif 58081634Sbrian 58181634Sbrian default: 58281634Sbrian range->ncprange_family = AF_UNSPEC; 58381634Sbrian } 58481634Sbrian} 58581634Sbrian 58681634Sbrianvoid 58781634Sbrianncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width) 58881634Sbrian{ 58981634Sbrian ncprange_sethost(range, addr); 59081634Sbrian ncprange_setwidth(range, width); 59181634Sbrian} 59281634Sbrian 59381634Sbrianvoid 59481634Sbrianncprange_sethost(struct ncprange *range, const struct ncpaddr *from) 59581634Sbrian{ 59681634Sbrian switch (from->ncpaddr_family) { 59781634Sbrian case AF_INET: 59881634Sbrian range->ncprange_family = AF_INET; 59981634Sbrian range->ncprange_ip4addr = from->ncpaddr_ip4addr; 60086832Sbrian if (from->ncpaddr_ip4addr.s_addr == INADDR_ANY) { 60186832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 60286832Sbrian range->ncprange_ip4width = 0; 60386832Sbrian } else { 60486832Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 60586832Sbrian range->ncprange_ip4width = 32; 60686832Sbrian } 60781634Sbrian break; 60881634Sbrian 60981634Sbrian#ifndef NOINET6 61081634Sbrian case AF_INET6: 61181634Sbrian range->ncprange_family = AF_INET6; 61281634Sbrian range->ncprange_ip6addr = from->ncpaddr_ip6addr; 61381634Sbrian range->ncprange_ip6width = 128; 61481634Sbrian break; 61581634Sbrian#endif 61681634Sbrian 61781634Sbrian default: 61881634Sbrian range->ncprange_family = AF_UNSPEC; 61981634Sbrian } 62081634Sbrian} 62181634Sbrian 62281634Sbrianint 62386815Sbrianncprange_ishost(const struct ncprange *range) 62486815Sbrian{ 62586815Sbrian switch (range->ncprange_family) { 62686815Sbrian case AF_INET: 62786815Sbrian return range->ncprange_ip4width == 32; 62886815Sbrian#ifndef NOINET6 62986815Sbrian case AF_INET6: 63086815Sbrian return range->ncprange_ip6width == 128; 63186815Sbrian#endif 63286815Sbrian } 63386815Sbrian 63486815Sbrian return (0); 63586815Sbrian} 63686815Sbrian 63786815Sbrianint 63881634Sbrianncprange_setwidth(struct ncprange *range, int width) 63981634Sbrian{ 64081634Sbrian switch (range->ncprange_family) { 64181634Sbrian case AF_INET: 64281634Sbrian if (width < 0 || width > 32) 64381634Sbrian break; 64481634Sbrian range->ncprange_ip4width = width; 64581634Sbrian range->ncprange_ip4mask = bits2mask4(width); 64681634Sbrian break; 64781634Sbrian 64881634Sbrian#ifndef NOINET6 64981634Sbrian case AF_INET6: 65081634Sbrian if (width < 0 || width > 128) 65181634Sbrian break; 65281634Sbrian range->ncprange_ip6width = width; 65381634Sbrian break; 65481634Sbrian#endif 65581634Sbrian 65681634Sbrian case AF_UNSPEC: 65781634Sbrian return 1; 65881634Sbrian } 65981634Sbrian 66081634Sbrian return 0; 66181634Sbrian} 66281634Sbrian 66381634Sbrianvoid 66481634Sbrianncprange_setip4host(struct ncprange *range, struct in_addr from) 66581634Sbrian{ 66681634Sbrian range->ncprange_family = AF_INET; 66781634Sbrian range->ncprange_ip4addr = from; 66886832Sbrian if (from.s_addr == INADDR_ANY) { 66986832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 67086832Sbrian range->ncprange_ip4width = 0; 67186832Sbrian } else { 67286832Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 67386832Sbrian range->ncprange_ip4width = 32; 67486832Sbrian } 67581634Sbrian} 67681634Sbrian 67781634Sbrianvoid 67881634Sbrianncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk) 67981634Sbrian{ 68081634Sbrian range->ncprange_family = AF_INET; 68181634Sbrian range->ncprange_ip4addr = from; 68281634Sbrian range->ncprange_ip4mask = msk; 68381634Sbrian range->ncprange_ip4width = mask42bits(msk); 68481634Sbrian} 68581634Sbrian 68681634Sbrian 68781634Sbrianint 68881634Sbrianncprange_setip4mask(struct ncprange *range, struct in_addr mask) 68981634Sbrian{ 69081634Sbrian if (range->ncprange_family != AF_INET) 69181634Sbrian return 0; 69281634Sbrian range->ncprange_ip4mask = mask; 69381634Sbrian range->ncprange_ip4width = mask42bits(mask); 69481634Sbrian return 1; 69581634Sbrian} 69681634Sbrian 69781634Sbrianvoid 69881634Sbrianncprange_setsa(struct ncprange *range, const struct sockaddr *host, 69981634Sbrian const struct sockaddr *mask) 70081634Sbrian{ 70181634Sbrian const struct sockaddr_in *host4 = (const struct sockaddr_in *)host; 70281634Sbrian const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask; 70381634Sbrian#ifndef NOINET6 70481634Sbrian const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host; 70581634Sbrian const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask; 70681634Sbrian#endif 70781634Sbrian 70881634Sbrian switch (host->sa_family) { 70981634Sbrian case AF_INET: 71081634Sbrian range->ncprange_family = AF_INET; 71181634Sbrian range->ncprange_ip4addr = host4->sin_addr; 71286832Sbrian if (host4->sin_addr.s_addr == INADDR_ANY) { 71386832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 71486832Sbrian range->ncprange_ip4width = 0; 71586832Sbrian } else if (mask4 && mask4->sin_family == AF_INET) { 71681634Sbrian range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr; 71781634Sbrian range->ncprange_ip4width = mask42bits(mask4->sin_addr); 71881634Sbrian } else { 71981634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 72081634Sbrian range->ncprange_ip4width = 32; 72181634Sbrian } 72281634Sbrian break; 72381634Sbrian 72481634Sbrian#ifndef NOINET6 72581634Sbrian case AF_INET6: 72681634Sbrian range->ncprange_family = AF_INET6; 72781634Sbrian range->ncprange_ip6addr = host6->sin6_addr; 728113110Sume if (IN6_IS_ADDR_UNSPECIFIED(&host6->sin6_addr)) 729113110Sume range->ncprange_ip6width = 0; 730113110Sume else 731113110Sume range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128; 73281634Sbrian break; 73381634Sbrian#endif 73481634Sbrian 73581634Sbrian default: 73681634Sbrian range->ncprange_family = AF_UNSPEC; 73781634Sbrian } 73881634Sbrian} 73981634Sbrian 74081634Sbrianvoid 74181634Sbrianncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host, 74281634Sbrian struct sockaddr_storage *mask) 74381634Sbrian{ 74481634Sbrian struct sockaddr_in *host4 = (struct sockaddr_in *)host; 74581634Sbrian struct sockaddr_in *mask4 = (struct sockaddr_in *)mask; 74681634Sbrian#ifndef NOINET6 74781634Sbrian struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host; 74881634Sbrian struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask; 74981634Sbrian#endif 75081634Sbrian 75181634Sbrian memset(host, '\0', sizeof(*host)); 75281634Sbrian if (mask) 75381634Sbrian memset(mask, '\0', sizeof(*mask)); 75481634Sbrian 75581634Sbrian switch (range->ncprange_family) { 75681634Sbrian case AF_INET: 75781634Sbrian host4->sin_family = AF_INET; 75881634Sbrian host4->sin_len = sizeof(*host4); 75981634Sbrian host4->sin_addr = range->ncprange_ip4addr; 76081634Sbrian if (mask4) { 76181634Sbrian mask4->sin_family = AF_INET; 76281634Sbrian mask4->sin_len = sizeof(*host4); 76381690Sbrian mask4->sin_addr = range->ncprange_ip4mask; 76481634Sbrian } 76581634Sbrian break; 76681634Sbrian 76781634Sbrian#ifndef NOINET6 76881634Sbrian case AF_INET6: 76981634Sbrian host6->sin6_family = AF_INET6; 77081634Sbrian host6->sin6_len = sizeof(*host6); 77181634Sbrian host6->sin6_addr = range->ncprange_ip6addr; 77281634Sbrian if (mask6) { 77381634Sbrian mask6->sin6_family = AF_INET6; 77481634Sbrian mask6->sin6_len = sizeof(*host6); 77581634Sbrian mask6->sin6_addr = bits2mask6(range->ncprange_ip6width); 77681634Sbrian } 77781634Sbrian break; 77881634Sbrian#endif 77981634Sbrian 78081634Sbrian default: 78181634Sbrian host->ss_family = AF_UNSPEC; 78281634Sbrian if (mask) 78381634Sbrian mask->ss_family = AF_UNSPEC; 78481634Sbrian break; 78581634Sbrian } 78681634Sbrian} 78781634Sbrian 78881634Sbrianint 78981634Sbrianncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr) 79081634Sbrian{ 79181634Sbrian switch (range->ncprange_family) { 79281634Sbrian case AF_INET: 79381634Sbrian addr->ncpaddr_family = AF_INET; 79481634Sbrian addr->ncpaddr_ip4addr = range->ncprange_ip4addr; 79581634Sbrian return 1; 79681634Sbrian#ifndef NOINET6 79781634Sbrian case AF_INET6: 79881634Sbrian addr->ncpaddr_family = AF_INET6; 79981634Sbrian addr->ncpaddr_ip6addr = range->ncprange_ip6addr; 80081634Sbrian return 1; 80181634Sbrian#endif 80281634Sbrian } 80381634Sbrian 80481634Sbrian return 0; 80581634Sbrian} 80681634Sbrian 80781634Sbrianint 80881634Sbrianncprange_getip4addr(const struct ncprange *range, struct in_addr *addr) 80981634Sbrian{ 81081634Sbrian if (range->ncprange_family != AF_INET) 81181634Sbrian return 0; 81281634Sbrian 81381634Sbrian *addr = range->ncprange_ip4addr; 81481634Sbrian return 1; 81581634Sbrian} 81681634Sbrian 81781634Sbrianint 81881634Sbrianncprange_getip4mask(const struct ncprange *range, struct in_addr *mask) 81981634Sbrian{ 82081634Sbrian switch (range->ncprange_family) { 82181634Sbrian case AF_INET: 82281634Sbrian *mask = range->ncprange_ip4mask; 82381634Sbrian return 1; 82481634Sbrian } 82581634Sbrian 82681634Sbrian return 0; 82781634Sbrian} 82881634Sbrian 82981634Sbrianint 83081634Sbrianncprange_getwidth(const struct ncprange *range, int *width) 83181634Sbrian{ 83281634Sbrian switch (range->ncprange_family) { 83381634Sbrian case AF_INET: 83481634Sbrian *width = range->ncprange_ip4width; 83581634Sbrian return 1; 83681634Sbrian#ifndef NOINET6 83781634Sbrian case AF_INET6: 83881634Sbrian *width = range->ncprange_ip6width; 83981634Sbrian return 1; 84081634Sbrian#endif 84181634Sbrian } 84281634Sbrian 84381634Sbrian return 0; 84481634Sbrian} 84581634Sbrian 84681634Sbrianconst char * 84781634Sbrianncprange_ntoa(const struct ncprange *range) 84881634Sbrian{ 84981634Sbrian char *res; 85081634Sbrian struct ncpaddr addr; 85181634Sbrian int len; 85281634Sbrian 85381634Sbrian if (!ncprange_getaddr(range, &addr)) 85481634Sbrian return "<AF_UNSPEC>"; 85581634Sbrian 85681634Sbrian res = ncpaddr_ntowa(&addr); 85781634Sbrian len = strlen(res); 85881634Sbrian if (len >= NCP_ASCIIBUFFERSIZE - 1) 85981634Sbrian return res; 86081634Sbrian 86181634Sbrian switch (range->ncprange_family) { 86281634Sbrian case AF_INET: 86381634Sbrian if (range->ncprange_ip4width == -1) { 86481634Sbrian /* A non-contiguous mask */ 86581634Sbrian for (; len >= 3; res[len -= 2] = '\0') 86681634Sbrian if (strcmp(res + len - 2, ".0")) 86781634Sbrian break; 86881634Sbrian snprintf(res + len, sizeof res - len, "&0x%08lx", 86981924Sbrian (unsigned long)ntohl(range->ncprange_ip4mask.s_addr)); 87081634Sbrian } else if (range->ncprange_ip4width < 32) 87181634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width); 87281634Sbrian 87381634Sbrian return res; 87481634Sbrian 87581634Sbrian#ifndef NOINET6 87681634Sbrian case AF_INET6: 87781634Sbrian if (range->ncprange_ip6width != 128) 87881634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width); 87981634Sbrian 88081634Sbrian return res; 88181634Sbrian#endif 88281634Sbrian } 88381634Sbrian 88481634Sbrian return "<AF_UNSPEC>"; 88581634Sbrian} 88681634Sbrian 88781634Sbrian#ifndef NOINET6 88881634Sbrianint 88981634Sbrianncprange_scopeid(const struct ncprange *range) 89081634Sbrian{ 89181634Sbrian const struct in6_addr *sin6; 89281634Sbrian int scopeid = -1; 89381634Sbrian 89481634Sbrian if (range->ncprange_family == AF_INET6) { 89581634Sbrian sin6 = &range->ncprange_ip6addr; 89681634Sbrian if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6)) 89781634Sbrian if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0) 89881634Sbrian scopeid = -1; 89981634Sbrian } 90081634Sbrian 90181634Sbrian return scopeid; 90281634Sbrian} 90381634Sbrian#endif 90481634Sbrian 90581634Sbrianint 90681634Sbrianncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data) 90781634Sbrian{ 90881634Sbrian int bits, len; 90981634Sbrian char *wp; 91081634Sbrian const char *cp; 91181634Sbrian char *s; 91281634Sbrian 91381634Sbrian len = strcspn(data, "/"); 91481634Sbrian 91581634Sbrian if (ncp && strncasecmp(data, "HISADDR", len) == 0) { 91681634Sbrian range->ncprange_family = AF_INET; 91781634Sbrian range->ncprange_ip4addr = ncp->ipcp.peer_ip; 91881634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 91981634Sbrian range->ncprange_ip4width = 32; 92081634Sbrian return 1; 92181634Sbrian#ifndef NOINET6 92281634Sbrian } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) { 923112673Sume range->ncprange_family = AF_INET6; 924112673Sume range->ncprange_ip6addr = ncp->ipv6cp.hisaddr.ncpaddr_ip6addr; 925112673Sume range->ncprange_ip6width = 128; 92681634Sbrian return 1; 92781634Sbrian#endif 92881634Sbrian } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) { 92981634Sbrian range->ncprange_family = AF_INET; 93081634Sbrian range->ncprange_ip4addr = ncp->ipcp.my_ip; 93181634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 93281634Sbrian range->ncprange_ip4width = 32; 93381634Sbrian return 1; 93481634Sbrian#ifndef NOINET6 93581634Sbrian } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) { 936112673Sume range->ncprange_family = AF_INET6; 937112673Sume range->ncprange_ip6addr = ncp->ipv6cp.myaddr.ncpaddr_ip6addr; 938112673Sume range->ncprange_ip6width = 128; 93981634Sbrian return 1; 94081634Sbrian#endif 94181634Sbrian } else if (ncp && strncasecmp(data, "DNS0", len) == 0) { 94281634Sbrian range->ncprange_family = AF_INET; 94381634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[0]; 94481634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 94581634Sbrian range->ncprange_ip4width = 32; 94681634Sbrian return 1; 94781634Sbrian } else if (ncp && strncasecmp(data, "DNS1", len) == 0) { 94881634Sbrian range->ncprange_family = AF_INET; 94981634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[1]; 95081634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 95181634Sbrian range->ncprange_ip4width = 32; 95281634Sbrian return 1; 95381634Sbrian } 95481634Sbrian 95581634Sbrian s = (char *)alloca(len + 1); 95681634Sbrian strncpy(s, data, len); 95781634Sbrian s[len] = '\0'; 95881634Sbrian bits = -1; 95981634Sbrian 96081634Sbrian if (data[len] != '\0') { 96181634Sbrian bits = strtol(data + len + 1, &wp, 0); 96281634Sbrian if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) { 96381634Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 96481634Sbrian return 0; 96581634Sbrian } 96681634Sbrian } 96781634Sbrian 96881634Sbrian if ((cp = strchr(data, ':')) == NULL) { 96981634Sbrian range->ncprange_family = AF_INET; 97081634Sbrian 97181634Sbrian range->ncprange_ip4addr = GetIpAddr(s); 97281634Sbrian 97381634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_NONE) { 97481634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 97581634Sbrian return 0; 97681634Sbrian } 97781634Sbrian 97881634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) { 97981634Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 98081634Sbrian range->ncprange_ip4width = 0; 98181690Sbrian } else if (bits == -1) { 98281634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 98381634Sbrian range->ncprange_ip4width = 32; 98481690Sbrian } else if (bits > 32) { 98581690Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 98681690Sbrian return 0; 98781634Sbrian } else { 98881634Sbrian range->ncprange_ip4mask = bits2mask4(bits); 98981634Sbrian range->ncprange_ip4width = bits; 99081634Sbrian } 99181634Sbrian 99281634Sbrian return 1; 99381634Sbrian#ifndef NOINET6 99481634Sbrian } else if (strchr(cp + 1, ':') != NULL) { 99581634Sbrian range->ncprange_family = AF_INET6; 99681634Sbrian 99781634Sbrian if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) { 99881634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 99981634Sbrian return 0; 100081634Sbrian } 100181634Sbrian 100281634Sbrian if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 100381634Sbrian range->ncprange_ip6width = 0; 100481634Sbrian else 100581634Sbrian range->ncprange_ip6width = (bits == -1) ? 128 : bits; 100681634Sbrian return 1; 100781634Sbrian#endif 100881634Sbrian } 100981634Sbrian 101081634Sbrian return 0; 101181634Sbrian} 1012