ncpaddr.c revision 96732
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 96732 2002-05-16 14:47:19Z brian $ 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 ! */ 16681634Sbrian if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 16781634Sbrian IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) { 16881634Sbrian sin6->sin6_scope_id = 16981634Sbrian ntohs(*(u_short *)&sin6->sin6_addr.s6_addr[2]); 17081634Sbrian *(u_short *)&sin6->sin6_addr.s6_addr[2] = 0; 17181634Sbrian } 17281634Sbrian} 17381634Sbrian#endif 17481634Sbrian 17581634Sbrianvoid 17681634Sbrianncpaddr_init(struct ncpaddr *addr) 17781634Sbrian{ 17881634Sbrian addr->ncpaddr_family = AF_UNSPEC; 17981634Sbrian} 18081634Sbrian 18181634Sbrianint 18281739Sbrianncpaddr_isset(const struct ncpaddr *addr) 18381739Sbrian{ 18481739Sbrian return addr->ncpaddr_family != AF_UNSPEC; 18581739Sbrian} 18681739Sbrian 18781739Sbrianint 18881634Sbrianncpaddr_isdefault(const struct ncpaddr *addr) 18981634Sbrian{ 19081634Sbrian switch (addr->ncpaddr_family) { 19181634Sbrian case AF_INET: 19281634Sbrian if (addr->ncpaddr_ip4addr.s_addr == INADDR_ANY) 19381634Sbrian return 1; 19481634Sbrian break; 19581634Sbrian 19681634Sbrian#ifndef NOINET6 19781634Sbrian case AF_INET6: 19881634Sbrian if (IN6_IS_ADDR_UNSPECIFIED(&addr->ncpaddr_ip6addr)) 19981634Sbrian return 1; 20081634Sbrian break; 20181634Sbrian#endif 20281634Sbrian } 20381634Sbrian 20481634Sbrian return 0; 20581634Sbrian} 20681634Sbrian 20781634Sbrianint 20881634Sbrianncpaddr_equal(const struct ncpaddr *addr, const struct ncpaddr *cmp) 20981634Sbrian{ 21081634Sbrian if (addr->ncpaddr_family != cmp->ncpaddr_family) 21181634Sbrian return 0; 21281634Sbrian 21381634Sbrian switch (addr->ncpaddr_family) { 21481634Sbrian case AF_INET: 21581634Sbrian return addr->ncpaddr_ip4addr.s_addr == cmp->ncpaddr_ip4addr.s_addr; 21681634Sbrian 21781634Sbrian#ifndef NOINET6 21881634Sbrian case AF_INET6: 21981634Sbrian return !memcmp(&addr->ncpaddr_ip6addr, &cmp->ncpaddr_ip6addr, 22081634Sbrian sizeof addr->ncpaddr_ip6addr); 22181634Sbrian#endif 22281634Sbrian 22381634Sbrian case AF_UNSPEC: 22481634Sbrian return 1; 22581634Sbrian } 22681634Sbrian 22781634Sbrian return 0; 22881634Sbrian} 22981634Sbrian 23081634Sbrianvoid 23181634Sbrianncpaddr_copy(struct ncpaddr *addr, const struct ncpaddr *from) 23281634Sbrian{ 23381634Sbrian switch (from->ncpaddr_family) { 23481634Sbrian case AF_INET: 23581634Sbrian addr->ncpaddr_family = AF_INET; 23681634Sbrian addr->ncpaddr_ip4addr = from->ncpaddr_ip4addr; 23781634Sbrian break; 23881634Sbrian#ifndef NOINET6 23981634Sbrian case AF_INET6: 24081634Sbrian addr->ncpaddr_family = AF_INET6; 24181634Sbrian addr->ncpaddr_ip6addr = from->ncpaddr_ip6addr; 24281634Sbrian break; 24381634Sbrian#endif 24481634Sbrian default: 24581634Sbrian addr->ncpaddr_family = AF_UNSPEC; 24681634Sbrian } 24781634Sbrian} 24881634Sbrian 24981634Sbrianvoid 25081634Sbrianncpaddr_setip4addr(struct ncpaddr *addr, u_int32_t ip) 25181634Sbrian{ 25281634Sbrian addr->ncpaddr_family = AF_INET; 25381634Sbrian addr->ncpaddr_ip4addr.s_addr = ip; 25481634Sbrian} 25581634Sbrian 25681634Sbrianint 25781634Sbrianncpaddr_getip4addr(const struct ncpaddr *addr, u_int32_t *ip) 25881634Sbrian{ 25981634Sbrian if (addr->ncpaddr_family != AF_INET) 26081634Sbrian return 0; 26181634Sbrian *ip = addr->ncpaddr_ip4addr.s_addr; 26281634Sbrian return 1; 26381634Sbrian} 26481634Sbrian 26581634Sbrianvoid 26681634Sbrianncpaddr_setip4(struct ncpaddr *addr, struct in_addr ip) 26781634Sbrian{ 26881634Sbrian addr->ncpaddr_family = AF_INET; 26981634Sbrian addr->ncpaddr_ip4addr = ip; 27081634Sbrian} 27181634Sbrian 27281634Sbrianint 27381634Sbrianncpaddr_getip4(const struct ncpaddr *addr, struct in_addr *ip) 27481634Sbrian{ 27581634Sbrian if (addr->ncpaddr_family != AF_INET) 27681634Sbrian return 0; 27781634Sbrian *ip = addr->ncpaddr_ip4addr; 27881634Sbrian return 1; 27981634Sbrian} 28081634Sbrian 28181634Sbrian#ifndef NOINET6 28281634Sbrianvoid 28381634Sbrianncpaddr_setip6(struct ncpaddr *addr, const struct in6_addr *ip6) 28481634Sbrian{ 28581634Sbrian addr->ncpaddr_family = AF_INET6; 28681634Sbrian addr->ncpaddr_ip6addr = *ip6; 28781634Sbrian} 28881634Sbrian 28981634Sbrianint 29081634Sbrianncpaddr_getip6(const struct ncpaddr *addr, struct in6_addr *ip6) 29181634Sbrian{ 29281634Sbrian if (addr->ncpaddr_family != AF_INET6) 29381634Sbrian return 0; 29481634Sbrian *ip6 = addr->ncpaddr_ip6addr; 29581634Sbrian return 1; 29681634Sbrian} 29781634Sbrian#endif 29881634Sbrian 29981634Sbrianvoid 30081634Sbrianncpaddr_getsa(const struct ncpaddr *addr, struct sockaddr_storage *host) 30181634Sbrian{ 30281634Sbrian struct sockaddr_in *host4 = (struct sockaddr_in *)host; 30381634Sbrian#ifndef NOINET6 30481634Sbrian struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host; 30581634Sbrian#endif 30681634Sbrian 30781634Sbrian memset(host, '\0', sizeof(*host)); 30881634Sbrian 30981634Sbrian switch (addr->ncpaddr_family) { 31081634Sbrian case AF_INET: 31181634Sbrian host4->sin_family = AF_INET; 31281634Sbrian host4->sin_len = sizeof(*host4); 31381634Sbrian host4->sin_addr = addr->ncpaddr_ip4addr; 31481634Sbrian break; 31581634Sbrian 31681634Sbrian#ifndef NOINET6 31781634Sbrian case AF_INET6: 31881634Sbrian host6->sin6_family = AF_INET6; 31981634Sbrian host6->sin6_len = sizeof(*host6); 32081634Sbrian host6->sin6_addr = addr->ncpaddr_ip6addr; 32181634Sbrian break; 32281634Sbrian#endif 32381634Sbrian 32481634Sbrian default: 32581634Sbrian host->ss_family = AF_UNSPEC; 32681634Sbrian break; 32781634Sbrian } 32881634Sbrian} 32981634Sbrian 33081634Sbrianvoid 33181634Sbrianncpaddr_setsa(struct ncpaddr *addr, const struct sockaddr *host) 33281634Sbrian{ 33381634Sbrian const struct sockaddr_in *host4 = (const struct sockaddr_in *)host; 33481634Sbrian#ifndef NOINET6 33581634Sbrian const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host; 33681634Sbrian#endif 33781634Sbrian 33881634Sbrian switch (host->sa_family) { 33981634Sbrian case AF_INET: 34081634Sbrian addr->ncpaddr_family = AF_INET; 34181634Sbrian addr->ncpaddr_ip4addr = host4->sin_addr; 34281634Sbrian break; 34381634Sbrian 34481634Sbrian#ifndef NOINET6 34581634Sbrian case AF_INET6: 34681634Sbrian if (IN6_IS_ADDR_V4MAPPED(&host6->sin6_addr)) { 34781634Sbrian addr->ncpaddr_family = AF_INET; 34881634Sbrian addr->ncpaddr_ip4addr.s_addr = 34981634Sbrian *(const u_int32_t *)(host6->sin6_addr.s6_addr + 12); 35081634Sbrian } else { 35181634Sbrian addr->ncpaddr_family = AF_INET6; 35281634Sbrian addr->ncpaddr_ip6addr = host6->sin6_addr; 35381634Sbrian } 35481634Sbrian break; 35581634Sbrian#endif 35681634Sbrian 35781634Sbrian default: 35881634Sbrian addr->ncpaddr_family = AF_UNSPEC; 35981634Sbrian } 36081634Sbrian} 36181634Sbrian 36281634Sbrianstatic char * 36381634Sbrianncpaddr_ntowa(const struct ncpaddr *addr) 36481634Sbrian{ 36581634Sbrian static char res[NCP_ASCIIBUFFERSIZE]; 36681634Sbrian#ifndef NOINET6 36781634Sbrian struct sockaddr_in6 sin6; 36881634Sbrian#endif 36981634Sbrian 37081634Sbrian switch (addr->ncpaddr_family) { 37181634Sbrian case AF_INET: 37281634Sbrian snprintf(res, sizeof res, "%s", inet_ntoa(addr->ncpaddr_ip4addr)); 37381634Sbrian return res; 37481634Sbrian 37581634Sbrian#ifndef NOINET6 37681634Sbrian case AF_INET6: 37781634Sbrian memset(&sin6, '\0', sizeof(sin6)); 37881634Sbrian sin6.sin6_len = sizeof(sin6); 37981634Sbrian sin6.sin6_family = AF_INET6; 38081634Sbrian sin6.sin6_addr = addr->ncpaddr_ip6addr; 38181634Sbrian adjust_linklocal(&sin6); 38281634Sbrian if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res), 38381634Sbrian NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST) != 0) 38481634Sbrian break; 38581634Sbrian 38681634Sbrian return res; 38781634Sbrian#endif 38881634Sbrian } 38981634Sbrian 39081634Sbrian snprintf(res, sizeof res, "<AF_UNSPEC>"); 39181634Sbrian return res; 39281634Sbrian} 39381634Sbrian 39481634Sbrianconst char * 39581634Sbrianncpaddr_ntoa(const struct ncpaddr *addr) 39681634Sbrian{ 39781634Sbrian return ncpaddr_ntowa(addr); 39881634Sbrian} 39981634Sbrian 40081634Sbrian 40181634Sbrianint 40281634Sbrianncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data) 40381634Sbrian{ 40481634Sbrian struct ncprange range; 40581634Sbrian 40681634Sbrian if (!ncprange_aton(&range, ncp, data)) 40781634Sbrian return 0; 40881634Sbrian 40981634Sbrian if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32) { 41081634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data); 41181634Sbrian return 0; 41281634Sbrian } 41381634Sbrian 41481634Sbrian#ifndef NOINET6 41581634Sbrian if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128) { 41681634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data); 41781634Sbrian return 0; 41881634Sbrian } 41981634Sbrian#endif 42081634Sbrian 42181634Sbrian switch (range.ncprange_family) { 42281634Sbrian case AF_INET: 42381634Sbrian addr->ncpaddr_family = range.ncprange_family; 42481634Sbrian addr->ncpaddr_ip4addr = range.ncprange_ip4addr; 42581634Sbrian return 1; 42681634Sbrian 42781634Sbrian#ifndef NOINET6 42881634Sbrian case AF_INET6: 42981634Sbrian addr->ncpaddr_family = range.ncprange_family; 43081634Sbrian addr->ncpaddr_ip6addr = range.ncprange_ip6addr; 43181634Sbrian return 1; 43281634Sbrian#endif 43381634Sbrian } 43481634Sbrian 43581634Sbrian return 0; 43681634Sbrian} 43781634Sbrian 43881634Sbrianvoid 43981634Sbrianncprange_init(struct ncprange *range) 44081634Sbrian{ 44181634Sbrian range->ncprange_family = AF_UNSPEC; 44281634Sbrian} 44381634Sbrian 44481634Sbrianint 44581634Sbrianncprange_isset(const struct ncprange *range) 44681634Sbrian{ 44781634Sbrian return range->ncprange_family != AF_UNSPEC; 44881634Sbrian} 44981634Sbrian 45081634Sbrianint 45181634Sbrianncprange_equal(const struct ncprange *range, const struct ncprange *cmp) 45281634Sbrian{ 45381634Sbrian if (range->ncprange_family != cmp->ncprange_family) 45481634Sbrian return 0; 45581634Sbrian 45681634Sbrian switch (range->ncprange_family) { 45781634Sbrian case AF_INET: 45881634Sbrian if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr) 45981634Sbrian return 0; 46081634Sbrian return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr; 46181634Sbrian 46281634Sbrian#ifndef NOINET6 46381634Sbrian case AF_INET6: 46481634Sbrian if (range->ncprange_ip6width != cmp->ncprange_ip6width) 46581634Sbrian return 0; 46681634Sbrian return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr, 46781634Sbrian sizeof range->ncprange_ip6addr); 46881634Sbrian#endif 46981634Sbrian 47081634Sbrian case AF_UNSPEC: 47181634Sbrian return 1; 47281634Sbrian } 47381634Sbrian 47481634Sbrian return 0; 47581634Sbrian} 47681634Sbrian 47781634Sbrianint 47881634Sbrianncprange_isdefault(const struct ncprange *range) 47981634Sbrian{ 48081634Sbrian switch (range->ncprange_family) { 48181634Sbrian case AF_INET: 48281634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) 48381634Sbrian return 1; 48481634Sbrian break; 48581634Sbrian 48681634Sbrian#ifndef NOINET6 48781634Sbrian case AF_INET6: 48881634Sbrian if (range->ncprange_ip6width == 0 && 48981634Sbrian IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 49081634Sbrian return 1; 49181634Sbrian break; 49281634Sbrian#endif 49381634Sbrian } 49481634Sbrian 49581634Sbrian return 0; 49681634Sbrian} 49781634Sbrian 49881634Sbrianvoid 49981634Sbrianncprange_setdefault(struct ncprange *range, int af) 50081634Sbrian{ 50181634Sbrian memset(range, '\0', sizeof *range); 50281634Sbrian range->ncprange_family = af; 50381634Sbrian} 50481634Sbrian 50581634Sbrianint 50681634Sbrianncprange_contains(const struct ncprange *range, const struct ncpaddr *addr) 50781634Sbrian{ 50881634Sbrian#ifndef NOINET6 50981634Sbrian const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 51081634Sbrian const u_char *addrp, *rangep; 51181634Sbrian int bits; 51281634Sbrian#endif 51381634Sbrian 51481634Sbrian if (range->ncprange_family != addr->ncpaddr_family) 51581634Sbrian return 0; 51681634Sbrian 51781634Sbrian switch (range->ncprange_family) { 51881634Sbrian case AF_INET: 51981634Sbrian return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 52081634Sbrian range->ncprange_ip4mask.s_addr); 52181634Sbrian 52281634Sbrian#ifndef NOINET6 52381634Sbrian case AF_INET6: 52481634Sbrian rangep = (const u_char *)range->ncprange_ip6addr.s6_addr; 52581634Sbrian addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr; 52681634Sbrian 52781634Sbrian for (bits = range->ncprange_ip6width; bits > 0; bits -= 8) 52881634Sbrian if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1]) 52981634Sbrian return 0; 53081634Sbrian 53181634Sbrian return 1; 53281634Sbrian#endif 53381634Sbrian } 53481634Sbrian 53581634Sbrian return 0; 53681634Sbrian} 53781634Sbrian 53881634Sbrianint 53981634Sbrianncprange_containsip4(const struct ncprange *range, struct in_addr addr) 54081634Sbrian{ 54181634Sbrian switch (range->ncprange_family) { 54281634Sbrian case AF_INET: 54381634Sbrian return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 54481634Sbrian range->ncprange_ip4mask.s_addr); 54581634Sbrian } 54681634Sbrian 54781634Sbrian return 0; 54881634Sbrian} 54981634Sbrian 55081634Sbrianvoid 55181634Sbrianncprange_copy(struct ncprange *range, const struct ncprange *from) 55281634Sbrian{ 55381634Sbrian switch (from->ncprange_family) { 55481634Sbrian case AF_INET: 55581634Sbrian range->ncprange_family = AF_INET; 55681634Sbrian range->ncprange_ip4addr = from->ncprange_ip4addr; 55781634Sbrian range->ncprange_ip4mask = from->ncprange_ip4mask; 55881634Sbrian range->ncprange_ip4width = from->ncprange_ip4width; 55981634Sbrian break; 56081634Sbrian 56181634Sbrian#ifndef NOINET6 56281634Sbrian case AF_INET6: 56381634Sbrian range->ncprange_family = AF_INET6; 56481634Sbrian range->ncprange_ip6addr = from->ncprange_ip6addr; 56581634Sbrian range->ncprange_ip6width = from->ncprange_ip6width; 56681634Sbrian break; 56781634Sbrian#endif 56881634Sbrian 56981634Sbrian default: 57081634Sbrian range->ncprange_family = AF_UNSPEC; 57181634Sbrian } 57281634Sbrian} 57381634Sbrian 57481634Sbrianvoid 57581634Sbrianncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width) 57681634Sbrian{ 57781634Sbrian ncprange_sethost(range, addr); 57881634Sbrian ncprange_setwidth(range, width); 57981634Sbrian} 58081634Sbrian 58181634Sbrianvoid 58281634Sbrianncprange_sethost(struct ncprange *range, const struct ncpaddr *from) 58381634Sbrian{ 58481634Sbrian switch (from->ncpaddr_family) { 58581634Sbrian case AF_INET: 58681634Sbrian range->ncprange_family = AF_INET; 58781634Sbrian range->ncprange_ip4addr = from->ncpaddr_ip4addr; 58886832Sbrian if (from->ncpaddr_ip4addr.s_addr == INADDR_ANY) { 58986832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 59086832Sbrian range->ncprange_ip4width = 0; 59186832Sbrian } else { 59286832Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 59386832Sbrian range->ncprange_ip4width = 32; 59486832Sbrian } 59581634Sbrian break; 59681634Sbrian 59781634Sbrian#ifndef NOINET6 59881634Sbrian case AF_INET6: 59981634Sbrian range->ncprange_family = AF_INET6; 60081634Sbrian range->ncprange_ip6addr = from->ncpaddr_ip6addr; 60181634Sbrian range->ncprange_ip6width = 128; 60281634Sbrian break; 60381634Sbrian#endif 60481634Sbrian 60581634Sbrian default: 60681634Sbrian range->ncprange_family = AF_UNSPEC; 60781634Sbrian } 60881634Sbrian} 60981634Sbrian 61081634Sbrianint 61186815Sbrianncprange_ishost(const struct ncprange *range) 61286815Sbrian{ 61386815Sbrian switch (range->ncprange_family) { 61486815Sbrian case AF_INET: 61586815Sbrian return range->ncprange_ip4width == 32; 61686815Sbrian#ifndef NOINET6 61786815Sbrian case AF_INET6: 61886815Sbrian return range->ncprange_ip6width == 128; 61986815Sbrian#endif 62086815Sbrian } 62186815Sbrian 62286815Sbrian return (0); 62386815Sbrian} 62486815Sbrian 62586815Sbrianint 62681634Sbrianncprange_setwidth(struct ncprange *range, int width) 62781634Sbrian{ 62881634Sbrian switch (range->ncprange_family) { 62981634Sbrian case AF_INET: 63081634Sbrian if (width < 0 || width > 32) 63181634Sbrian break; 63281634Sbrian range->ncprange_ip4width = width; 63381634Sbrian range->ncprange_ip4mask = bits2mask4(width); 63481634Sbrian break; 63581634Sbrian 63681634Sbrian#ifndef NOINET6 63781634Sbrian case AF_INET6: 63881634Sbrian if (width < 0 || width > 128) 63981634Sbrian break; 64081634Sbrian range->ncprange_ip6width = width; 64181634Sbrian break; 64281634Sbrian#endif 64381634Sbrian 64481634Sbrian case AF_UNSPEC: 64581634Sbrian return 1; 64681634Sbrian } 64781634Sbrian 64881634Sbrian return 0; 64981634Sbrian} 65081634Sbrian 65181634Sbrianvoid 65281634Sbrianncprange_setip4host(struct ncprange *range, struct in_addr from) 65381634Sbrian{ 65481634Sbrian range->ncprange_family = AF_INET; 65581634Sbrian range->ncprange_ip4addr = from; 65686832Sbrian if (from.s_addr == INADDR_ANY) { 65786832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 65886832Sbrian range->ncprange_ip4width = 0; 65986832Sbrian } else { 66086832Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 66186832Sbrian range->ncprange_ip4width = 32; 66286832Sbrian } 66381634Sbrian} 66481634Sbrian 66581634Sbrianvoid 66681634Sbrianncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk) 66781634Sbrian{ 66881634Sbrian range->ncprange_family = AF_INET; 66981634Sbrian range->ncprange_ip4addr = from; 67081634Sbrian range->ncprange_ip4mask = msk; 67181634Sbrian range->ncprange_ip4width = mask42bits(msk); 67281634Sbrian} 67381634Sbrian 67481634Sbrian 67581634Sbrianint 67681634Sbrianncprange_setip4mask(struct ncprange *range, struct in_addr mask) 67781634Sbrian{ 67881634Sbrian if (range->ncprange_family != AF_INET) 67981634Sbrian return 0; 68081634Sbrian range->ncprange_ip4mask = mask; 68181634Sbrian range->ncprange_ip4width = mask42bits(mask); 68281634Sbrian return 1; 68381634Sbrian} 68481634Sbrian 68581634Sbrianvoid 68681634Sbrianncprange_setsa(struct ncprange *range, const struct sockaddr *host, 68781634Sbrian const struct sockaddr *mask) 68881634Sbrian{ 68981634Sbrian const struct sockaddr_in *host4 = (const struct sockaddr_in *)host; 69081634Sbrian const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask; 69181634Sbrian#ifndef NOINET6 69281634Sbrian const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host; 69381634Sbrian const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask; 69481634Sbrian#endif 69581634Sbrian 69681634Sbrian switch (host->sa_family) { 69781634Sbrian case AF_INET: 69881634Sbrian range->ncprange_family = AF_INET; 69981634Sbrian range->ncprange_ip4addr = host4->sin_addr; 70086832Sbrian if (host4->sin_addr.s_addr == INADDR_ANY) { 70186832Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 70286832Sbrian range->ncprange_ip4width = 0; 70386832Sbrian } else if (mask4 && mask4->sin_family == AF_INET) { 70481634Sbrian range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr; 70581634Sbrian range->ncprange_ip4width = mask42bits(mask4->sin_addr); 70681634Sbrian } else { 70781634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 70881634Sbrian range->ncprange_ip4width = 32; 70981634Sbrian } 71081634Sbrian break; 71181634Sbrian 71281634Sbrian#ifndef NOINET6 71381634Sbrian case AF_INET6: 71481634Sbrian range->ncprange_family = AF_INET6; 71581634Sbrian range->ncprange_ip6addr = host6->sin6_addr; 71681634Sbrian range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128; 71781634Sbrian break; 71881634Sbrian#endif 71981634Sbrian 72081634Sbrian default: 72181634Sbrian range->ncprange_family = AF_UNSPEC; 72281634Sbrian } 72381634Sbrian} 72481634Sbrian 72581634Sbrianvoid 72681634Sbrianncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host, 72781634Sbrian struct sockaddr_storage *mask) 72881634Sbrian{ 72981634Sbrian struct sockaddr_in *host4 = (struct sockaddr_in *)host; 73081634Sbrian struct sockaddr_in *mask4 = (struct sockaddr_in *)mask; 73181634Sbrian#ifndef NOINET6 73281634Sbrian struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host; 73381634Sbrian struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask; 73481634Sbrian#endif 73581634Sbrian 73681634Sbrian memset(host, '\0', sizeof(*host)); 73781634Sbrian if (mask) 73881634Sbrian memset(mask, '\0', sizeof(*mask)); 73981634Sbrian 74081634Sbrian switch (range->ncprange_family) { 74181634Sbrian case AF_INET: 74281634Sbrian host4->sin_family = AF_INET; 74381634Sbrian host4->sin_len = sizeof(*host4); 74481634Sbrian host4->sin_addr = range->ncprange_ip4addr; 74581634Sbrian if (mask4) { 74681634Sbrian mask4->sin_family = AF_INET; 74781634Sbrian mask4->sin_len = sizeof(*host4); 74881690Sbrian mask4->sin_addr = range->ncprange_ip4mask; 74981634Sbrian } 75081634Sbrian break; 75181634Sbrian 75281634Sbrian#ifndef NOINET6 75381634Sbrian case AF_INET6: 75481634Sbrian host6->sin6_family = AF_INET6; 75581634Sbrian host6->sin6_len = sizeof(*host6); 75681634Sbrian host6->sin6_addr = range->ncprange_ip6addr; 75781634Sbrian if (mask6) { 75881634Sbrian mask6->sin6_family = AF_INET6; 75981634Sbrian mask6->sin6_len = sizeof(*host6); 76081634Sbrian mask6->sin6_addr = bits2mask6(range->ncprange_ip6width); 76181634Sbrian } 76281634Sbrian break; 76381634Sbrian#endif 76481634Sbrian 76581634Sbrian default: 76681634Sbrian host->ss_family = AF_UNSPEC; 76781634Sbrian if (mask) 76881634Sbrian mask->ss_family = AF_UNSPEC; 76981634Sbrian break; 77081634Sbrian } 77181634Sbrian} 77281634Sbrian 77381634Sbrianint 77481634Sbrianncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr) 77581634Sbrian{ 77681634Sbrian switch (range->ncprange_family) { 77781634Sbrian case AF_INET: 77881634Sbrian addr->ncpaddr_family = AF_INET; 77981634Sbrian addr->ncpaddr_ip4addr = range->ncprange_ip4addr; 78081634Sbrian return 1; 78181634Sbrian#ifndef NOINET6 78281634Sbrian case AF_INET6: 78381634Sbrian addr->ncpaddr_family = AF_INET6; 78481634Sbrian addr->ncpaddr_ip6addr = range->ncprange_ip6addr; 78581634Sbrian return 1; 78681634Sbrian#endif 78781634Sbrian } 78881634Sbrian 78981634Sbrian return 0; 79081634Sbrian} 79181634Sbrian 79281634Sbrianint 79381634Sbrianncprange_getip4addr(const struct ncprange *range, struct in_addr *addr) 79481634Sbrian{ 79581634Sbrian if (range->ncprange_family != AF_INET) 79681634Sbrian return 0; 79781634Sbrian 79881634Sbrian *addr = range->ncprange_ip4addr; 79981634Sbrian return 1; 80081634Sbrian} 80181634Sbrian 80281634Sbrianint 80381634Sbrianncprange_getip4mask(const struct ncprange *range, struct in_addr *mask) 80481634Sbrian{ 80581634Sbrian switch (range->ncprange_family) { 80681634Sbrian case AF_INET: 80781634Sbrian *mask = range->ncprange_ip4mask; 80881634Sbrian return 1; 80981634Sbrian } 81081634Sbrian 81181634Sbrian return 0; 81281634Sbrian} 81381634Sbrian 81481634Sbrianint 81581634Sbrianncprange_getwidth(const struct ncprange *range, int *width) 81681634Sbrian{ 81781634Sbrian switch (range->ncprange_family) { 81881634Sbrian case AF_INET: 81981634Sbrian *width = range->ncprange_ip4width; 82081634Sbrian return 1; 82181634Sbrian#ifndef NOINET6 82281634Sbrian case AF_INET6: 82381634Sbrian *width = range->ncprange_ip6width; 82481634Sbrian return 1; 82581634Sbrian#endif 82681634Sbrian } 82781634Sbrian 82881634Sbrian return 0; 82981634Sbrian} 83081634Sbrian 83181634Sbrianconst char * 83281634Sbrianncprange_ntoa(const struct ncprange *range) 83381634Sbrian{ 83481634Sbrian char *res; 83581634Sbrian struct ncpaddr addr; 83681634Sbrian int len; 83781634Sbrian 83881634Sbrian if (!ncprange_getaddr(range, &addr)) 83981634Sbrian return "<AF_UNSPEC>"; 84081634Sbrian 84181634Sbrian res = ncpaddr_ntowa(&addr); 84281634Sbrian len = strlen(res); 84381634Sbrian if (len >= NCP_ASCIIBUFFERSIZE - 1) 84481634Sbrian return res; 84581634Sbrian 84681634Sbrian switch (range->ncprange_family) { 84781634Sbrian case AF_INET: 84881634Sbrian if (range->ncprange_ip4width == -1) { 84981634Sbrian /* A non-contiguous mask */ 85081634Sbrian for (; len >= 3; res[len -= 2] = '\0') 85181634Sbrian if (strcmp(res + len - 2, ".0")) 85281634Sbrian break; 85381634Sbrian snprintf(res + len, sizeof res - len, "&0x%08lx", 85481924Sbrian (unsigned long)ntohl(range->ncprange_ip4mask.s_addr)); 85581634Sbrian } else if (range->ncprange_ip4width < 32) 85681634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width); 85781634Sbrian 85881634Sbrian return res; 85981634Sbrian 86081634Sbrian#ifndef NOINET6 86181634Sbrian case AF_INET6: 86281634Sbrian if (range->ncprange_ip6width != 128) 86381634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width); 86481634Sbrian 86581634Sbrian return res; 86681634Sbrian#endif 86781634Sbrian } 86881634Sbrian 86981634Sbrian return "<AF_UNSPEC>"; 87081634Sbrian} 87181634Sbrian 87281634Sbrian#ifndef NOINET6 87381634Sbrianint 87481634Sbrianncprange_scopeid(const struct ncprange *range) 87581634Sbrian{ 87681634Sbrian const struct in6_addr *sin6; 87781634Sbrian int scopeid = -1; 87881634Sbrian 87981634Sbrian if (range->ncprange_family == AF_INET6) { 88081634Sbrian sin6 = &range->ncprange_ip6addr; 88181634Sbrian if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6)) 88281634Sbrian if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0) 88381634Sbrian scopeid = -1; 88481634Sbrian } 88581634Sbrian 88681634Sbrian return scopeid; 88781634Sbrian} 88881634Sbrian#endif 88981634Sbrian 89081634Sbrianint 89181634Sbrianncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data) 89281634Sbrian{ 89381634Sbrian int bits, len; 89481634Sbrian char *wp; 89581634Sbrian const char *cp; 89681634Sbrian char *s; 89781634Sbrian 89881634Sbrian len = strcspn(data, "/"); 89981634Sbrian 90081634Sbrian if (ncp && strncasecmp(data, "HISADDR", len) == 0) { 90181634Sbrian range->ncprange_family = AF_INET; 90281634Sbrian range->ncprange_ip4addr = ncp->ipcp.peer_ip; 90381634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 90481634Sbrian range->ncprange_ip4width = 32; 90581634Sbrian return 1; 90681634Sbrian#ifndef NOINET6 90781634Sbrian } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) { 90881634Sbrian ncprange_sethost(range, &ncp->ipv6cp.hisaddr); 90981634Sbrian return 1; 91081634Sbrian#endif 91181634Sbrian } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) { 91281634Sbrian range->ncprange_family = AF_INET; 91381634Sbrian range->ncprange_ip4addr = ncp->ipcp.my_ip; 91481634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 91581634Sbrian range->ncprange_ip4width = 32; 91681634Sbrian return 1; 91781634Sbrian#ifndef NOINET6 91881634Sbrian } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) { 91981634Sbrian ncprange_sethost(range, &ncp->ipv6cp.myaddr); 92081634Sbrian return 1; 92181634Sbrian#endif 92281634Sbrian } else if (ncp && strncasecmp(data, "DNS0", len) == 0) { 92381634Sbrian range->ncprange_family = AF_INET; 92481634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[0]; 92581634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 92681634Sbrian range->ncprange_ip4width = 32; 92781634Sbrian return 1; 92881634Sbrian } else if (ncp && strncasecmp(data, "DNS1", len) == 0) { 92981634Sbrian range->ncprange_family = AF_INET; 93081634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[1]; 93181634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 93281634Sbrian range->ncprange_ip4width = 32; 93381634Sbrian return 1; 93481634Sbrian } 93581634Sbrian 93681634Sbrian s = (char *)alloca(len + 1); 93781634Sbrian strncpy(s, data, len); 93881634Sbrian s[len] = '\0'; 93981634Sbrian bits = -1; 94081634Sbrian 94181634Sbrian if (data[len] != '\0') { 94281634Sbrian bits = strtol(data + len + 1, &wp, 0); 94381634Sbrian if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) { 94481634Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 94581634Sbrian return 0; 94681634Sbrian } 94781634Sbrian } 94881634Sbrian 94981634Sbrian if ((cp = strchr(data, ':')) == NULL) { 95081634Sbrian range->ncprange_family = AF_INET; 95181634Sbrian 95281634Sbrian range->ncprange_ip4addr = GetIpAddr(s); 95381634Sbrian 95481634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_NONE) { 95581634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 95681634Sbrian return 0; 95781634Sbrian } 95881634Sbrian 95981634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) { 96081634Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 96181634Sbrian range->ncprange_ip4width = 0; 96281690Sbrian } else if (bits == -1) { 96381634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 96481634Sbrian range->ncprange_ip4width = 32; 96581690Sbrian } else if (bits > 32) { 96681690Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 96781690Sbrian return 0; 96881634Sbrian } else { 96981634Sbrian range->ncprange_ip4mask = bits2mask4(bits); 97081634Sbrian range->ncprange_ip4width = bits; 97181634Sbrian } 97281634Sbrian 97381634Sbrian return 1; 97481634Sbrian#ifndef NOINET6 97581634Sbrian } else if (strchr(cp + 1, ':') != NULL) { 97681634Sbrian range->ncprange_family = AF_INET6; 97781634Sbrian 97881634Sbrian if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) { 97981634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 98081634Sbrian return 0; 98181634Sbrian } 98281634Sbrian 98381634Sbrian if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 98481634Sbrian range->ncprange_ip6width = 0; 98581634Sbrian else 98681634Sbrian range->ncprange_ip6width = (bits == -1) ? 128 : bits; 98781634Sbrian return 1; 98881634Sbrian#endif 98981634Sbrian } 99081634Sbrian 99181634Sbrian return 0; 99281634Sbrian} 993