ncpaddr.c revision 116654
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 116654 2003-06-21 10:14:52Z 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; 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 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 421116654Sume if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32 && 422116654Sume range.ncprange_ip4addr.s_addr != INADDR_ANY) { 42381634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data); 42481634Sbrian return 0; 42581634Sbrian } 42681634Sbrian 42781634Sbrian#ifndef NOINET6 428116654Sume if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128 && 429116654Sume !IN6_IS_ADDR_UNSPECIFIED(&range.ncprange_ip6addr)) { 43081634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data); 43181634Sbrian return 0; 43281634Sbrian } 43381634Sbrian#endif 43481634Sbrian 43581634Sbrian switch (range.ncprange_family) { 43681634Sbrian case AF_INET: 43781634Sbrian addr->ncpaddr_family = range.ncprange_family; 43881634Sbrian addr->ncpaddr_ip4addr = range.ncprange_ip4addr; 43981634Sbrian return 1; 44081634Sbrian 44181634Sbrian#ifndef NOINET6 44281634Sbrian case AF_INET6: 44381634Sbrian addr->ncpaddr_family = range.ncprange_family; 44481634Sbrian addr->ncpaddr_ip6addr = range.ncprange_ip6addr; 44581634Sbrian return 1; 44681634Sbrian#endif 44781634Sbrian } 44881634Sbrian 44981634Sbrian return 0; 45081634Sbrian} 45181634Sbrian 45281634Sbrianvoid 45381634Sbrianncprange_init(struct ncprange *range) 45481634Sbrian{ 45581634Sbrian range->ncprange_family = AF_UNSPEC; 45681634Sbrian} 45781634Sbrian 45881634Sbrianint 45981634Sbrianncprange_isset(const struct ncprange *range) 46081634Sbrian{ 46181634Sbrian return range->ncprange_family != AF_UNSPEC; 46281634Sbrian} 46381634Sbrian 46481634Sbrianint 46581634Sbrianncprange_equal(const struct ncprange *range, const struct ncprange *cmp) 46681634Sbrian{ 46781634Sbrian if (range->ncprange_family != cmp->ncprange_family) 46881634Sbrian return 0; 46981634Sbrian 47081634Sbrian switch (range->ncprange_family) { 47181634Sbrian case AF_INET: 47281634Sbrian if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr) 47381634Sbrian return 0; 47481634Sbrian return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr; 47581634Sbrian 47681634Sbrian#ifndef NOINET6 47781634Sbrian case AF_INET6: 47881634Sbrian if (range->ncprange_ip6width != cmp->ncprange_ip6width) 47981634Sbrian return 0; 48081634Sbrian return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr, 48181634Sbrian sizeof range->ncprange_ip6addr); 48281634Sbrian#endif 48381634Sbrian 48481634Sbrian case AF_UNSPEC: 48581634Sbrian return 1; 48681634Sbrian } 48781634Sbrian 48881634Sbrian return 0; 48981634Sbrian} 49081634Sbrian 49181634Sbrianint 49281634Sbrianncprange_isdefault(const struct ncprange *range) 49381634Sbrian{ 49481634Sbrian switch (range->ncprange_family) { 49581634Sbrian case AF_INET: 49681634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) 49781634Sbrian return 1; 49881634Sbrian break; 49981634Sbrian 50081634Sbrian#ifndef NOINET6 50181634Sbrian case AF_INET6: 50281634Sbrian if (range->ncprange_ip6width == 0 && 50381634Sbrian IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 50481634Sbrian return 1; 50581634Sbrian break; 50681634Sbrian#endif 50781634Sbrian } 50881634Sbrian 50981634Sbrian return 0; 51081634Sbrian} 51181634Sbrian 51281634Sbrianvoid 51381634Sbrianncprange_setdefault(struct ncprange *range, int af) 51481634Sbrian{ 51581634Sbrian memset(range, '\0', sizeof *range); 51681634Sbrian range->ncprange_family = af; 51781634Sbrian} 51881634Sbrian 51981634Sbrianint 52081634Sbrianncprange_contains(const struct ncprange *range, const struct ncpaddr *addr) 52181634Sbrian{ 52281634Sbrian#ifndef NOINET6 52381634Sbrian const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 52481634Sbrian const u_char *addrp, *rangep; 52581634Sbrian int bits; 52681634Sbrian#endif 52781634Sbrian 52881634Sbrian if (range->ncprange_family != addr->ncpaddr_family) 52981634Sbrian return 0; 53081634Sbrian 53181634Sbrian switch (range->ncprange_family) { 53281634Sbrian case AF_INET: 53381634Sbrian return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 53481634Sbrian range->ncprange_ip4mask.s_addr); 53581634Sbrian 53681634Sbrian#ifndef NOINET6 53781634Sbrian case AF_INET6: 53881634Sbrian rangep = (const u_char *)range->ncprange_ip6addr.s6_addr; 53981634Sbrian addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr; 54081634Sbrian 54181634Sbrian for (bits = range->ncprange_ip6width; bits > 0; bits -= 8) 54281634Sbrian if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1]) 54381634Sbrian return 0; 54481634Sbrian 54581634Sbrian return 1; 54681634Sbrian#endif 54781634Sbrian } 54881634Sbrian 54981634Sbrian return 0; 55081634Sbrian} 55181634Sbrian 55281634Sbrianint 55381634Sbrianncprange_containsip4(const struct ncprange *range, struct in_addr addr) 55481634Sbrian{ 55581634Sbrian switch (range->ncprange_family) { 55681634Sbrian case AF_INET: 55781634Sbrian return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 55881634Sbrian range->ncprange_ip4mask.s_addr); 55981634Sbrian } 56081634Sbrian 56181634Sbrian return 0; 56281634Sbrian} 56381634Sbrian 56481634Sbrianvoid 56581634Sbrianncprange_copy(struct ncprange *range, const struct ncprange *from) 56681634Sbrian{ 56781634Sbrian switch (from->ncprange_family) { 56881634Sbrian case AF_INET: 56981634Sbrian range->ncprange_family = AF_INET; 57081634Sbrian range->ncprange_ip4addr = from->ncprange_ip4addr; 57181634Sbrian range->ncprange_ip4mask = from->ncprange_ip4mask; 57281634Sbrian range->ncprange_ip4width = from->ncprange_ip4width; 57381634Sbrian break; 57481634Sbrian 57581634Sbrian#ifndef NOINET6 57681634Sbrian case AF_INET6: 57781634Sbrian range->ncprange_family = AF_INET6; 57881634Sbrian range->ncprange_ip6addr = from->ncprange_ip6addr; 57981634Sbrian range->ncprange_ip6width = from->ncprange_ip6width; 58081634Sbrian break; 58181634Sbrian#endif 58281634Sbrian 58381634Sbrian default: 58481634Sbrian range->ncprange_family = AF_UNSPEC; 58581634Sbrian } 58681634Sbrian} 58781634Sbrian 58881634Sbrianvoid 58981634Sbrianncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width) 59081634Sbrian{ 59181634Sbrian ncprange_sethost(range, addr); 59281634Sbrian ncprange_setwidth(range, width); 59381634Sbrian} 59481634Sbrian 59581634Sbrianvoid 59681634Sbrianncprange_sethost(struct ncprange *range, const struct ncpaddr *from) 59781634Sbrian{ 59881634Sbrian switch (from->ncpaddr_family) { 59981634Sbrian case AF_INET: 60081634Sbrian range->ncprange_family = AF_INET; 60181634Sbrian range->ncprange_ip4addr = from->ncpaddr_ip4addr; 60286832Sbrian if (from->ncpaddr_ip4addr.s_addr == INADDR_ANY) { 60386832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 60486832Sbrian range->ncprange_ip4width = 0; 60586832Sbrian } else { 60686832Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 60786832Sbrian range->ncprange_ip4width = 32; 60886832Sbrian } 60981634Sbrian break; 61081634Sbrian 61181634Sbrian#ifndef NOINET6 61281634Sbrian case AF_INET6: 61381634Sbrian range->ncprange_family = AF_INET6; 61481634Sbrian range->ncprange_ip6addr = from->ncpaddr_ip6addr; 61581634Sbrian range->ncprange_ip6width = 128; 61681634Sbrian break; 61781634Sbrian#endif 61881634Sbrian 61981634Sbrian default: 62081634Sbrian range->ncprange_family = AF_UNSPEC; 62181634Sbrian } 62281634Sbrian} 62381634Sbrian 62481634Sbrianint 62586815Sbrianncprange_ishost(const struct ncprange *range) 62686815Sbrian{ 62786815Sbrian switch (range->ncprange_family) { 62886815Sbrian case AF_INET: 62986815Sbrian return range->ncprange_ip4width == 32; 63086815Sbrian#ifndef NOINET6 63186815Sbrian case AF_INET6: 63286815Sbrian return range->ncprange_ip6width == 128; 63386815Sbrian#endif 63486815Sbrian } 63586815Sbrian 63686815Sbrian return (0); 63786815Sbrian} 63886815Sbrian 63986815Sbrianint 64081634Sbrianncprange_setwidth(struct ncprange *range, int width) 64181634Sbrian{ 64281634Sbrian switch (range->ncprange_family) { 64381634Sbrian case AF_INET: 64481634Sbrian if (width < 0 || width > 32) 64581634Sbrian break; 64681634Sbrian range->ncprange_ip4width = width; 64781634Sbrian range->ncprange_ip4mask = bits2mask4(width); 64881634Sbrian break; 64981634Sbrian 65081634Sbrian#ifndef NOINET6 65181634Sbrian case AF_INET6: 65281634Sbrian if (width < 0 || width > 128) 65381634Sbrian break; 65481634Sbrian range->ncprange_ip6width = width; 65581634Sbrian break; 65681634Sbrian#endif 65781634Sbrian 65881634Sbrian case AF_UNSPEC: 65981634Sbrian return 1; 66081634Sbrian } 66181634Sbrian 66281634Sbrian return 0; 66381634Sbrian} 66481634Sbrian 66581634Sbrianvoid 66681634Sbrianncprange_setip4host(struct ncprange *range, struct in_addr from) 66781634Sbrian{ 66881634Sbrian range->ncprange_family = AF_INET; 66981634Sbrian range->ncprange_ip4addr = from; 67086832Sbrian if (from.s_addr == INADDR_ANY) { 67186832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 67286832Sbrian range->ncprange_ip4width = 0; 67386832Sbrian } else { 67486832Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 67586832Sbrian range->ncprange_ip4width = 32; 67686832Sbrian } 67781634Sbrian} 67881634Sbrian 67981634Sbrianvoid 68081634Sbrianncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk) 68181634Sbrian{ 68281634Sbrian range->ncprange_family = AF_INET; 68381634Sbrian range->ncprange_ip4addr = from; 68481634Sbrian range->ncprange_ip4mask = msk; 68581634Sbrian range->ncprange_ip4width = mask42bits(msk); 68681634Sbrian} 68781634Sbrian 68881634Sbrian 68981634Sbrianint 69081634Sbrianncprange_setip4mask(struct ncprange *range, struct in_addr mask) 69181634Sbrian{ 69281634Sbrian if (range->ncprange_family != AF_INET) 69381634Sbrian return 0; 69481634Sbrian range->ncprange_ip4mask = mask; 69581634Sbrian range->ncprange_ip4width = mask42bits(mask); 69681634Sbrian return 1; 69781634Sbrian} 69881634Sbrian 69981634Sbrianvoid 70081634Sbrianncprange_setsa(struct ncprange *range, const struct sockaddr *host, 70181634Sbrian const struct sockaddr *mask) 70281634Sbrian{ 70381634Sbrian const struct sockaddr_in *host4 = (const struct sockaddr_in *)host; 70481634Sbrian const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask; 70581634Sbrian#ifndef NOINET6 70681634Sbrian const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host; 70781634Sbrian const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask; 70881634Sbrian#endif 70981634Sbrian 71081634Sbrian switch (host->sa_family) { 71181634Sbrian case AF_INET: 71281634Sbrian range->ncprange_family = AF_INET; 71381634Sbrian range->ncprange_ip4addr = host4->sin_addr; 71486832Sbrian if (host4->sin_addr.s_addr == INADDR_ANY) { 71586832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 71686832Sbrian range->ncprange_ip4width = 0; 71786832Sbrian } else if (mask4 && mask4->sin_family == AF_INET) { 71881634Sbrian range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr; 71981634Sbrian range->ncprange_ip4width = mask42bits(mask4->sin_addr); 72081634Sbrian } else { 72181634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 72281634Sbrian range->ncprange_ip4width = 32; 72381634Sbrian } 72481634Sbrian break; 72581634Sbrian 72681634Sbrian#ifndef NOINET6 72781634Sbrian case AF_INET6: 72881634Sbrian range->ncprange_family = AF_INET6; 72981634Sbrian range->ncprange_ip6addr = host6->sin6_addr; 730113110Sume if (IN6_IS_ADDR_UNSPECIFIED(&host6->sin6_addr)) 731113110Sume range->ncprange_ip6width = 0; 732113110Sume else 733113110Sume range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128; 73481634Sbrian break; 73581634Sbrian#endif 73681634Sbrian 73781634Sbrian default: 73881634Sbrian range->ncprange_family = AF_UNSPEC; 73981634Sbrian } 74081634Sbrian} 74181634Sbrian 74281634Sbrianvoid 74381634Sbrianncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host, 74481634Sbrian struct sockaddr_storage *mask) 74581634Sbrian{ 74681634Sbrian struct sockaddr_in *host4 = (struct sockaddr_in *)host; 74781634Sbrian struct sockaddr_in *mask4 = (struct sockaddr_in *)mask; 74881634Sbrian#ifndef NOINET6 74981634Sbrian struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host; 75081634Sbrian struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask; 75181634Sbrian#endif 75281634Sbrian 75381634Sbrian memset(host, '\0', sizeof(*host)); 75481634Sbrian if (mask) 75581634Sbrian memset(mask, '\0', sizeof(*mask)); 75681634Sbrian 75781634Sbrian switch (range->ncprange_family) { 75881634Sbrian case AF_INET: 75981634Sbrian host4->sin_family = AF_INET; 76081634Sbrian host4->sin_len = sizeof(*host4); 76181634Sbrian host4->sin_addr = range->ncprange_ip4addr; 76281634Sbrian if (mask4) { 76381634Sbrian mask4->sin_family = AF_INET; 76481634Sbrian mask4->sin_len = sizeof(*host4); 76581690Sbrian mask4->sin_addr = range->ncprange_ip4mask; 76681634Sbrian } 76781634Sbrian break; 76881634Sbrian 76981634Sbrian#ifndef NOINET6 77081634Sbrian case AF_INET6: 77181634Sbrian host6->sin6_family = AF_INET6; 77281634Sbrian host6->sin6_len = sizeof(*host6); 77381634Sbrian host6->sin6_addr = range->ncprange_ip6addr; 77481634Sbrian if (mask6) { 77581634Sbrian mask6->sin6_family = AF_INET6; 77681634Sbrian mask6->sin6_len = sizeof(*host6); 77781634Sbrian mask6->sin6_addr = bits2mask6(range->ncprange_ip6width); 77881634Sbrian } 77981634Sbrian break; 78081634Sbrian#endif 78181634Sbrian 78281634Sbrian default: 78381634Sbrian host->ss_family = AF_UNSPEC; 78481634Sbrian if (mask) 78581634Sbrian mask->ss_family = AF_UNSPEC; 78681634Sbrian break; 78781634Sbrian } 78881634Sbrian} 78981634Sbrian 79081634Sbrianint 79181634Sbrianncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr) 79281634Sbrian{ 79381634Sbrian switch (range->ncprange_family) { 79481634Sbrian case AF_INET: 79581634Sbrian addr->ncpaddr_family = AF_INET; 79681634Sbrian addr->ncpaddr_ip4addr = range->ncprange_ip4addr; 79781634Sbrian return 1; 79881634Sbrian#ifndef NOINET6 79981634Sbrian case AF_INET6: 80081634Sbrian addr->ncpaddr_family = AF_INET6; 80181634Sbrian addr->ncpaddr_ip6addr = range->ncprange_ip6addr; 80281634Sbrian return 1; 80381634Sbrian#endif 80481634Sbrian } 80581634Sbrian 80681634Sbrian return 0; 80781634Sbrian} 80881634Sbrian 80981634Sbrianint 81081634Sbrianncprange_getip4addr(const struct ncprange *range, struct in_addr *addr) 81181634Sbrian{ 81281634Sbrian if (range->ncprange_family != AF_INET) 81381634Sbrian return 0; 81481634Sbrian 81581634Sbrian *addr = range->ncprange_ip4addr; 81681634Sbrian return 1; 81781634Sbrian} 81881634Sbrian 81981634Sbrianint 82081634Sbrianncprange_getip4mask(const struct ncprange *range, struct in_addr *mask) 82181634Sbrian{ 82281634Sbrian switch (range->ncprange_family) { 82381634Sbrian case AF_INET: 82481634Sbrian *mask = range->ncprange_ip4mask; 82581634Sbrian return 1; 82681634Sbrian } 82781634Sbrian 82881634Sbrian return 0; 82981634Sbrian} 83081634Sbrian 83181634Sbrianint 83281634Sbrianncprange_getwidth(const struct ncprange *range, int *width) 83381634Sbrian{ 83481634Sbrian switch (range->ncprange_family) { 83581634Sbrian case AF_INET: 83681634Sbrian *width = range->ncprange_ip4width; 83781634Sbrian return 1; 83881634Sbrian#ifndef NOINET6 83981634Sbrian case AF_INET6: 84081634Sbrian *width = range->ncprange_ip6width; 84181634Sbrian return 1; 84281634Sbrian#endif 84381634Sbrian } 84481634Sbrian 84581634Sbrian return 0; 84681634Sbrian} 84781634Sbrian 84881634Sbrianconst char * 84981634Sbrianncprange_ntoa(const struct ncprange *range) 85081634Sbrian{ 85181634Sbrian char *res; 85281634Sbrian struct ncpaddr addr; 85381634Sbrian int len; 85481634Sbrian 85581634Sbrian if (!ncprange_getaddr(range, &addr)) 85681634Sbrian return "<AF_UNSPEC>"; 85781634Sbrian 85881634Sbrian res = ncpaddr_ntowa(&addr); 85981634Sbrian len = strlen(res); 86081634Sbrian if (len >= NCP_ASCIIBUFFERSIZE - 1) 86181634Sbrian return res; 86281634Sbrian 86381634Sbrian switch (range->ncprange_family) { 86481634Sbrian case AF_INET: 86581634Sbrian if (range->ncprange_ip4width == -1) { 86681634Sbrian /* A non-contiguous mask */ 86781634Sbrian for (; len >= 3; res[len -= 2] = '\0') 86881634Sbrian if (strcmp(res + len - 2, ".0")) 86981634Sbrian break; 87081634Sbrian snprintf(res + len, sizeof res - len, "&0x%08lx", 87181924Sbrian (unsigned long)ntohl(range->ncprange_ip4mask.s_addr)); 87281634Sbrian } else if (range->ncprange_ip4width < 32) 87381634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width); 87481634Sbrian 87581634Sbrian return res; 87681634Sbrian 87781634Sbrian#ifndef NOINET6 87881634Sbrian case AF_INET6: 87981634Sbrian if (range->ncprange_ip6width != 128) 88081634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width); 88181634Sbrian 88281634Sbrian return res; 88381634Sbrian#endif 88481634Sbrian } 88581634Sbrian 88681634Sbrian return "<AF_UNSPEC>"; 88781634Sbrian} 88881634Sbrian 88981634Sbrian#ifndef NOINET6 89081634Sbrianint 89181634Sbrianncprange_scopeid(const struct ncprange *range) 89281634Sbrian{ 89381634Sbrian const struct in6_addr *sin6; 89481634Sbrian int scopeid = -1; 89581634Sbrian 89681634Sbrian if (range->ncprange_family == AF_INET6) { 89781634Sbrian sin6 = &range->ncprange_ip6addr; 89881634Sbrian if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6)) 89981634Sbrian if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0) 90081634Sbrian scopeid = -1; 90181634Sbrian } 90281634Sbrian 90381634Sbrian return scopeid; 90481634Sbrian} 90581634Sbrian#endif 90681634Sbrian 90781634Sbrianint 90881634Sbrianncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data) 90981634Sbrian{ 91081634Sbrian int bits, len; 91181634Sbrian char *wp; 91281634Sbrian const char *cp; 91381634Sbrian char *s; 91481634Sbrian 91581634Sbrian len = strcspn(data, "/"); 91681634Sbrian 91781634Sbrian if (ncp && strncasecmp(data, "HISADDR", len) == 0) { 91881634Sbrian range->ncprange_family = AF_INET; 91981634Sbrian range->ncprange_ip4addr = ncp->ipcp.peer_ip; 92081634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 92181634Sbrian range->ncprange_ip4width = 32; 92281634Sbrian return 1; 92381634Sbrian#ifndef NOINET6 92481634Sbrian } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) { 925112673Sume range->ncprange_family = AF_INET6; 926112673Sume range->ncprange_ip6addr = ncp->ipv6cp.hisaddr.ncpaddr_ip6addr; 927112673Sume range->ncprange_ip6width = 128; 92881634Sbrian return 1; 92981634Sbrian#endif 93081634Sbrian } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) { 93181634Sbrian range->ncprange_family = AF_INET; 93281634Sbrian range->ncprange_ip4addr = ncp->ipcp.my_ip; 93381634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 93481634Sbrian range->ncprange_ip4width = 32; 93581634Sbrian return 1; 93681634Sbrian#ifndef NOINET6 93781634Sbrian } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) { 938112673Sume range->ncprange_family = AF_INET6; 939112673Sume range->ncprange_ip6addr = ncp->ipv6cp.myaddr.ncpaddr_ip6addr; 940112673Sume range->ncprange_ip6width = 128; 94181634Sbrian return 1; 94281634Sbrian#endif 94381634Sbrian } else if (ncp && strncasecmp(data, "DNS0", len) == 0) { 94481634Sbrian range->ncprange_family = AF_INET; 94581634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[0]; 94681634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 94781634Sbrian range->ncprange_ip4width = 32; 94881634Sbrian return 1; 94981634Sbrian } else if (ncp && strncasecmp(data, "DNS1", len) == 0) { 95081634Sbrian range->ncprange_family = AF_INET; 95181634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[1]; 95281634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 95381634Sbrian range->ncprange_ip4width = 32; 95481634Sbrian return 1; 95581634Sbrian } 95681634Sbrian 95781634Sbrian s = (char *)alloca(len + 1); 95881634Sbrian strncpy(s, data, len); 95981634Sbrian s[len] = '\0'; 96081634Sbrian bits = -1; 96181634Sbrian 96281634Sbrian if (data[len] != '\0') { 96381634Sbrian bits = strtol(data + len + 1, &wp, 0); 96481634Sbrian if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) { 96581634Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 96681634Sbrian return 0; 96781634Sbrian } 96881634Sbrian } 96981634Sbrian 97081634Sbrian if ((cp = strchr(data, ':')) == NULL) { 97181634Sbrian range->ncprange_family = AF_INET; 97281634Sbrian 97381634Sbrian range->ncprange_ip4addr = GetIpAddr(s); 97481634Sbrian 97581634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_NONE) { 97681634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 97781634Sbrian return 0; 97881634Sbrian } 97981634Sbrian 98081634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) { 98181634Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 98281634Sbrian range->ncprange_ip4width = 0; 98381690Sbrian } else if (bits == -1) { 98481634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 98581634Sbrian range->ncprange_ip4width = 32; 98681690Sbrian } else if (bits > 32) { 98781690Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 98881690Sbrian return 0; 98981634Sbrian } else { 99081634Sbrian range->ncprange_ip4mask = bits2mask4(bits); 99181634Sbrian range->ncprange_ip4width = bits; 99281634Sbrian } 99381634Sbrian 99481634Sbrian return 1; 99581634Sbrian#ifndef NOINET6 99681634Sbrian } else if (strchr(cp + 1, ':') != NULL) { 99781634Sbrian range->ncprange_family = AF_INET6; 99881634Sbrian 99981634Sbrian if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) { 100081634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 100181634Sbrian return 0; 100281634Sbrian } 100381634Sbrian 100481634Sbrian if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 100581634Sbrian range->ncprange_ip6width = 0; 100681634Sbrian else 100781634Sbrian range->ncprange_ip6width = (bits == -1) ? 128 : bits; 100881634Sbrian return 1; 100981634Sbrian#endif 101081634Sbrian } 101181634Sbrian 101281634Sbrian return 0; 101381634Sbrian} 1014