ncpaddr.c revision 81739
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 81739 2001-08-16 02:01:05Z brian $ 2781634Sbrian */ 2881634Sbrian 2981634Sbrian#include <sys/types.h> 3081634Sbrian#include <sys/socket.h> 3181634Sbrian#include <net/if_types.h> 3281634Sbrian#include <net/route.h> 3381634Sbrian#include <netinet/in.h> 3481634Sbrian#include <netinet/in_systm.h> 3581634Sbrian#include <netinet/ip.h> 3681634Sbrian#include <arpa/inet.h> 3781634Sbrian#include <sys/un.h> 3881634Sbrian 3981634Sbrian#include <limits.h> 4081634Sbrian#include <netdb.h> 4181634Sbrian#include <stdio.h> 4281634Sbrian#include <stdlib.h> 4381634Sbrian#include <string.h> 4481634Sbrian#include <termios.h> 4581634Sbrian 4681634Sbrian#include "log.h" 4781634Sbrian#include "ncpaddr.h" 4881634Sbrian#include "timer.h" 4981634Sbrian#include "fsm.h" 5081634Sbrian#include "defs.h" 5181634Sbrian#include "slcompress.h" 5281634Sbrian#include "iplist.h" 5381634Sbrian#include "throughput.h" 5481634Sbrian#include "mbuf.h" 5581634Sbrian#include "ip.h" 5681634Sbrian#include "ipcp.h" 5781634Sbrian#include "filter.h" 5881634Sbrian#include "descriptor.h" 5981634Sbrian#include "route.h" 6081634Sbrian#include "layer.h" 6181634Sbrian#include "lqr.h" 6281634Sbrian#include "hdlc.h" 6381634Sbrian#include "lcp.h" 6481634Sbrian#include "ccp.h" 6581634Sbrian#include "link.h" 6681634Sbrian#include "mp.h" 6781634Sbrian#ifndef NORADIUS 6881634Sbrian#include "radius.h" 6981634Sbrian#endif 7081634Sbrian#include "ipv6cp.h" 7181634Sbrian#include "ncp.h" 7281634Sbrian#include "bundle.h" 7381634Sbrian 7481634Sbrian 7581634Sbrian#define ncprange_ip4addr u.ip4.ipaddr 7681634Sbrian#define ncprange_ip4mask u.ip4.mask 7781634Sbrian#define ncprange_ip4width u.ip4.width 7881634Sbrian#define ncpaddr_ip4addr u.ip4addr 7981634Sbrian#ifndef NOINET6 8081634Sbrian#define ncprange_ip6addr u.ip6.ipaddr 8181634Sbrian#define ncprange_ip6width u.ip6.width 8281634Sbrian#define ncpaddr_ip6addr u.ip6addr 8381634Sbrian#endif 8481634Sbrian 8581634Sbrian#define NCP_ASCIIBUFFERSIZE 52 8681634Sbrian 8781634Sbrianstatic struct in_addr 8881634Sbrianbits2mask4(int bits) 8981634Sbrian{ 9081634Sbrian struct in_addr result; 9181634Sbrian u_int32_t bit = 0x80000000; 9281634Sbrian 9381634Sbrian result.s_addr = 0; 9481634Sbrian 9581634Sbrian while (bits) { 9681634Sbrian result.s_addr |= bit; 9781634Sbrian bit >>= 1; 9881634Sbrian bits--; 9981634Sbrian } 10081634Sbrian 10181634Sbrian result.s_addr = htonl(result.s_addr); 10281634Sbrian return result; 10381634Sbrian} 10481634Sbrian 10581634Sbrianstatic int 10681634Sbrianmask42bits(struct in_addr mask) 10781634Sbrian{ 10881634Sbrian u_int32_t msk = ntohl(mask.s_addr); 10981634Sbrian u_int32_t tst; 11081634Sbrian int ret; 11181634Sbrian 11281634Sbrian for (ret = 32, tst = 1; tst; ret--, tst <<= 1) 11381634Sbrian if (msk & tst) 11481634Sbrian break; 11581634Sbrian 11681634Sbrian for (tst <<= 1; tst; tst <<= 1) 11781634Sbrian if (!(msk & tst)) 11881634Sbrian break; 11981634Sbrian 12081634Sbrian return tst ? -1 : ret; 12181634Sbrian} 12281634Sbrian 12381634Sbrian#ifndef NOINET6 12481634Sbrianstatic struct in6_addr 12581634Sbrianbits2mask6(int bits) 12681634Sbrian{ 12781634Sbrian struct in6_addr result; 12881634Sbrian u_int32_t bit = 0x80; 12981634Sbrian u_char *c = result.s6_addr; 13081634Sbrian 13181634Sbrian memset(&result, '\0', sizeof result); 13281634Sbrian 13381634Sbrian while (bits) { 13481634Sbrian if (bit == 0) { 13581634Sbrian bit = 0x80; 13681634Sbrian c++; 13781634Sbrian } 13881634Sbrian *c |= bit; 13981634Sbrian bit >>= 1; 14081634Sbrian bits--; 14181634Sbrian } 14281634Sbrian 14381634Sbrian return result; 14481634Sbrian} 14581634Sbrian 14681634Sbrianstatic int 14781634Sbrianmask62bits(const struct in6_addr *mask) 14881634Sbrian{ 14981634Sbrian const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; 15081634Sbrian const u_char *c, *p, *end; 15181634Sbrian int masklen; 15281634Sbrian 15381634Sbrian p = (const u_char *)mask; 15481634Sbrian for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++) 15581634Sbrian masklen += 8; 15681634Sbrian 15781634Sbrian if (p < end) { 15881634Sbrian for (c = masks; c < masks + sizeof masks; c++) 15981634Sbrian if (*c == *p) { 16081634Sbrian masklen += c - masks; 16181634Sbrian break; 16281634Sbrian } 16381634Sbrian } 16481634Sbrian 16581634Sbrian return masklen; 16681634Sbrian} 16781634Sbrian 16881634Sbrianstatic void 16981634Sbrianadjust_linklocal(struct sockaddr_in6 *sin6) 17081634Sbrian{ 17181634Sbrian /* XXX: ?????!?!?!!!!! This is horrible ! */ 17281634Sbrian if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 17381634Sbrian IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) { 17481634Sbrian sin6->sin6_scope_id = 17581634Sbrian ntohs(*(u_short *)&sin6->sin6_addr.s6_addr[2]); 17681634Sbrian *(u_short *)&sin6->sin6_addr.s6_addr[2] = 0; 17781634Sbrian } 17881634Sbrian} 17981634Sbrian#endif 18081634Sbrian 18181634Sbrianvoid 18281634Sbrianncpaddr_init(struct ncpaddr *addr) 18381634Sbrian{ 18481634Sbrian addr->ncpaddr_family = AF_UNSPEC; 18581634Sbrian} 18681634Sbrian 18781634Sbrianint 18881739Sbrianncpaddr_isset(const struct ncpaddr *addr) 18981739Sbrian{ 19081739Sbrian return addr->ncpaddr_family != AF_UNSPEC; 19181739Sbrian} 19281739Sbrian 19381739Sbrianint 19481634Sbrianncpaddr_isdefault(const struct ncpaddr *addr) 19581634Sbrian{ 19681634Sbrian switch (addr->ncpaddr_family) { 19781634Sbrian case AF_INET: 19881634Sbrian if (addr->ncpaddr_ip4addr.s_addr == INADDR_ANY) 19981634Sbrian return 1; 20081634Sbrian break; 20181634Sbrian 20281634Sbrian#ifndef NOINET6 20381634Sbrian case AF_INET6: 20481634Sbrian if (IN6_IS_ADDR_UNSPECIFIED(&addr->ncpaddr_ip6addr)) 20581634Sbrian return 1; 20681634Sbrian break; 20781634Sbrian#endif 20881634Sbrian } 20981634Sbrian 21081634Sbrian return 0; 21181634Sbrian} 21281634Sbrian 21381634Sbrianint 21481634Sbrianncpaddr_equal(const struct ncpaddr *addr, const struct ncpaddr *cmp) 21581634Sbrian{ 21681634Sbrian if (addr->ncpaddr_family != cmp->ncpaddr_family) 21781634Sbrian return 0; 21881634Sbrian 21981634Sbrian switch (addr->ncpaddr_family) { 22081634Sbrian case AF_INET: 22181634Sbrian return addr->ncpaddr_ip4addr.s_addr == cmp->ncpaddr_ip4addr.s_addr; 22281634Sbrian 22381634Sbrian#ifndef NOINET6 22481634Sbrian case AF_INET6: 22581634Sbrian return !memcmp(&addr->ncpaddr_ip6addr, &cmp->ncpaddr_ip6addr, 22681634Sbrian sizeof addr->ncpaddr_ip6addr); 22781634Sbrian#endif 22881634Sbrian 22981634Sbrian case AF_UNSPEC: 23081634Sbrian return 1; 23181634Sbrian } 23281634Sbrian 23381634Sbrian return 0; 23481634Sbrian} 23581634Sbrian 23681634Sbrianvoid 23781634Sbrianncpaddr_copy(struct ncpaddr *addr, const struct ncpaddr *from) 23881634Sbrian{ 23981634Sbrian switch (from->ncpaddr_family) { 24081634Sbrian case AF_INET: 24181634Sbrian addr->ncpaddr_family = AF_INET; 24281634Sbrian addr->ncpaddr_ip4addr = from->ncpaddr_ip4addr; 24381634Sbrian break; 24481634Sbrian#ifndef NOINET6 24581634Sbrian case AF_INET6: 24681634Sbrian addr->ncpaddr_family = AF_INET6; 24781634Sbrian addr->ncpaddr_ip6addr = from->ncpaddr_ip6addr; 24881634Sbrian break; 24981634Sbrian#endif 25081634Sbrian default: 25181634Sbrian addr->ncpaddr_family = AF_UNSPEC; 25281634Sbrian } 25381634Sbrian} 25481634Sbrian 25581634Sbrianvoid 25681634Sbrianncpaddr_setip4addr(struct ncpaddr *addr, u_int32_t ip) 25781634Sbrian{ 25881634Sbrian addr->ncpaddr_family = AF_INET; 25981634Sbrian addr->ncpaddr_ip4addr.s_addr = ip; 26081634Sbrian} 26181634Sbrian 26281634Sbrianint 26381634Sbrianncpaddr_getip4addr(const struct ncpaddr *addr, u_int32_t *ip) 26481634Sbrian{ 26581634Sbrian if (addr->ncpaddr_family != AF_INET) 26681634Sbrian return 0; 26781634Sbrian *ip = addr->ncpaddr_ip4addr.s_addr; 26881634Sbrian return 1; 26981634Sbrian} 27081634Sbrian 27181634Sbrianvoid 27281634Sbrianncpaddr_setip4(struct ncpaddr *addr, struct in_addr ip) 27381634Sbrian{ 27481634Sbrian addr->ncpaddr_family = AF_INET; 27581634Sbrian addr->ncpaddr_ip4addr = ip; 27681634Sbrian} 27781634Sbrian 27881634Sbrianint 27981634Sbrianncpaddr_getip4(const struct ncpaddr *addr, struct in_addr *ip) 28081634Sbrian{ 28181634Sbrian if (addr->ncpaddr_family != AF_INET) 28281634Sbrian return 0; 28381634Sbrian *ip = addr->ncpaddr_ip4addr; 28481634Sbrian return 1; 28581634Sbrian} 28681634Sbrian 28781634Sbrian#ifndef NOINET6 28881634Sbrianvoid 28981634Sbrianncpaddr_setip6(struct ncpaddr *addr, const struct in6_addr *ip6) 29081634Sbrian{ 29181634Sbrian addr->ncpaddr_family = AF_INET6; 29281634Sbrian addr->ncpaddr_ip6addr = *ip6; 29381634Sbrian} 29481634Sbrian 29581634Sbrianint 29681634Sbrianncpaddr_getip6(const struct ncpaddr *addr, struct in6_addr *ip6) 29781634Sbrian{ 29881634Sbrian if (addr->ncpaddr_family != AF_INET6) 29981634Sbrian return 0; 30081634Sbrian *ip6 = addr->ncpaddr_ip6addr; 30181634Sbrian return 1; 30281634Sbrian} 30381634Sbrian#endif 30481634Sbrian 30581634Sbrianvoid 30681634Sbrianncpaddr_getsa(const struct ncpaddr *addr, struct sockaddr_storage *host) 30781634Sbrian{ 30881634Sbrian struct sockaddr_in *host4 = (struct sockaddr_in *)host; 30981634Sbrian#ifndef NOINET6 31081634Sbrian struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host; 31181634Sbrian#endif 31281634Sbrian 31381634Sbrian memset(host, '\0', sizeof(*host)); 31481634Sbrian 31581634Sbrian switch (addr->ncpaddr_family) { 31681634Sbrian case AF_INET: 31781634Sbrian host4->sin_family = AF_INET; 31881634Sbrian host4->sin_len = sizeof(*host4); 31981634Sbrian host4->sin_addr = addr->ncpaddr_ip4addr; 32081634Sbrian break; 32181634Sbrian 32281634Sbrian#ifndef NOINET6 32381634Sbrian case AF_INET6: 32481634Sbrian host6->sin6_family = AF_INET6; 32581634Sbrian host6->sin6_len = sizeof(*host6); 32681634Sbrian host6->sin6_addr = addr->ncpaddr_ip6addr; 32781634Sbrian adjust_linklocal(host6); 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); 38981634Sbrian if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res), 39081634Sbrian NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST) != 0) 39181634Sbrian break; 39281634Sbrian 39381634Sbrian return res; 39481634Sbrian#endif 39581634Sbrian } 39681634Sbrian 39781634Sbrian snprintf(res, sizeof res, "<AF_UNSPEC>"); 39881634Sbrian return res; 39981634Sbrian} 40081634Sbrian 40181634Sbrianconst char * 40281634Sbrianncpaddr_ntoa(const struct ncpaddr *addr) 40381634Sbrian{ 40481634Sbrian return ncpaddr_ntowa(addr); 40581634Sbrian} 40681634Sbrian 40781634Sbrian 40881634Sbrianint 40981634Sbrianncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data) 41081634Sbrian{ 41181634Sbrian struct ncprange range; 41281634Sbrian 41381634Sbrian if (!ncprange_aton(&range, ncp, data)) 41481634Sbrian return 0; 41581634Sbrian 41681634Sbrian if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32) { 41781634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data); 41881634Sbrian return 0; 41981634Sbrian } 42081634Sbrian 42181634Sbrian#ifndef NOINET6 42281634Sbrian if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128) { 42381634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data); 42481634Sbrian return 0; 42581634Sbrian } 42681634Sbrian#endif 42781634Sbrian 42881634Sbrian switch (range.ncprange_family) { 42981634Sbrian case AF_INET: 43081634Sbrian addr->ncpaddr_family = range.ncprange_family; 43181634Sbrian addr->ncpaddr_ip4addr = range.ncprange_ip4addr; 43281634Sbrian return 1; 43381634Sbrian 43481634Sbrian#ifndef NOINET6 43581634Sbrian case AF_INET6: 43681634Sbrian addr->ncpaddr_family = range.ncprange_family; 43781634Sbrian addr->ncpaddr_ip6addr = range.ncprange_ip6addr; 43881634Sbrian return 1; 43981634Sbrian#endif 44081634Sbrian } 44181634Sbrian 44281634Sbrian return 0; 44381634Sbrian} 44481634Sbrian 44581634Sbrianvoid 44681634Sbrianncprange_init(struct ncprange *range) 44781634Sbrian{ 44881634Sbrian range->ncprange_family = AF_UNSPEC; 44981634Sbrian} 45081634Sbrian 45181634Sbrianint 45281634Sbrianncprange_isset(const struct ncprange *range) 45381634Sbrian{ 45481634Sbrian return range->ncprange_family != AF_UNSPEC; 45581634Sbrian} 45681634Sbrian 45781634Sbrianint 45881634Sbrianncprange_equal(const struct ncprange *range, const struct ncprange *cmp) 45981634Sbrian{ 46081634Sbrian if (range->ncprange_family != cmp->ncprange_family) 46181634Sbrian return 0; 46281634Sbrian 46381634Sbrian switch (range->ncprange_family) { 46481634Sbrian case AF_INET: 46581634Sbrian if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr) 46681634Sbrian return 0; 46781634Sbrian return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr; 46881634Sbrian 46981634Sbrian#ifndef NOINET6 47081634Sbrian case AF_INET6: 47181634Sbrian if (range->ncprange_ip6width != cmp->ncprange_ip6width) 47281634Sbrian return 0; 47381634Sbrian return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr, 47481634Sbrian sizeof range->ncprange_ip6addr); 47581634Sbrian#endif 47681634Sbrian 47781634Sbrian case AF_UNSPEC: 47881634Sbrian return 1; 47981634Sbrian } 48081634Sbrian 48181634Sbrian return 0; 48281634Sbrian} 48381634Sbrian 48481634Sbrianint 48581634Sbrianncprange_isdefault(const struct ncprange *range) 48681634Sbrian{ 48781634Sbrian switch (range->ncprange_family) { 48881634Sbrian case AF_INET: 48981634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) 49081634Sbrian return 1; 49181634Sbrian break; 49281634Sbrian 49381634Sbrian#ifndef NOINET6 49481634Sbrian case AF_INET6: 49581634Sbrian if (range->ncprange_ip6width == 0 && 49681634Sbrian IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 49781634Sbrian return 1; 49881634Sbrian break; 49981634Sbrian#endif 50081634Sbrian } 50181634Sbrian 50281634Sbrian return 0; 50381634Sbrian} 50481634Sbrian 50581634Sbrianvoid 50681634Sbrianncprange_setdefault(struct ncprange *range, int af) 50781634Sbrian{ 50881634Sbrian memset(range, '\0', sizeof *range); 50981634Sbrian range->ncprange_family = af; 51081634Sbrian} 51181634Sbrian 51281634Sbrianint 51381634Sbrianncprange_contains(const struct ncprange *range, const struct ncpaddr *addr) 51481634Sbrian{ 51581634Sbrian#ifndef NOINET6 51681634Sbrian const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 51781634Sbrian const u_char *addrp, *rangep; 51881634Sbrian int bits; 51981634Sbrian#endif 52081634Sbrian 52181634Sbrian if (range->ncprange_family != addr->ncpaddr_family) 52281634Sbrian return 0; 52381634Sbrian 52481634Sbrian switch (range->ncprange_family) { 52581634Sbrian case AF_INET: 52681634Sbrian return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 52781634Sbrian range->ncprange_ip4mask.s_addr); 52881634Sbrian 52981634Sbrian#ifndef NOINET6 53081634Sbrian case AF_INET6: 53181634Sbrian rangep = (const u_char *)range->ncprange_ip6addr.s6_addr; 53281634Sbrian addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr; 53381634Sbrian 53481634Sbrian for (bits = range->ncprange_ip6width; bits > 0; bits -= 8) 53581634Sbrian if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1]) 53681634Sbrian return 0; 53781634Sbrian 53881634Sbrian return 1; 53981634Sbrian#endif 54081634Sbrian } 54181634Sbrian 54281634Sbrian return 0; 54381634Sbrian} 54481634Sbrian 54581634Sbrianint 54681634Sbrianncprange_containsip4(const struct ncprange *range, struct in_addr addr) 54781634Sbrian{ 54881634Sbrian switch (range->ncprange_family) { 54981634Sbrian case AF_INET: 55081634Sbrian return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 55181634Sbrian range->ncprange_ip4mask.s_addr); 55281634Sbrian } 55381634Sbrian 55481634Sbrian return 0; 55581634Sbrian} 55681634Sbrian 55781634Sbrianvoid 55881634Sbrianncprange_copy(struct ncprange *range, const struct ncprange *from) 55981634Sbrian{ 56081634Sbrian switch (from->ncprange_family) { 56181634Sbrian case AF_INET: 56281634Sbrian range->ncprange_family = AF_INET; 56381634Sbrian range->ncprange_ip4addr = from->ncprange_ip4addr; 56481634Sbrian range->ncprange_ip4mask = from->ncprange_ip4mask; 56581634Sbrian range->ncprange_ip4width = from->ncprange_ip4width; 56681634Sbrian break; 56781634Sbrian 56881634Sbrian#ifndef NOINET6 56981634Sbrian case AF_INET6: 57081634Sbrian range->ncprange_family = AF_INET6; 57181634Sbrian range->ncprange_ip6addr = from->ncprange_ip6addr; 57281634Sbrian range->ncprange_ip6width = from->ncprange_ip6width; 57381634Sbrian break; 57481634Sbrian#endif 57581634Sbrian 57681634Sbrian default: 57781634Sbrian range->ncprange_family = AF_UNSPEC; 57881634Sbrian } 57981634Sbrian} 58081634Sbrian 58181634Sbrianvoid 58281634Sbrianncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width) 58381634Sbrian{ 58481634Sbrian ncprange_sethost(range, addr); 58581634Sbrian ncprange_setwidth(range, width); 58681634Sbrian} 58781634Sbrian 58881634Sbrianvoid 58981634Sbrianncprange_sethost(struct ncprange *range, const struct ncpaddr *from) 59081634Sbrian{ 59181634Sbrian switch (from->ncpaddr_family) { 59281634Sbrian case AF_INET: 59381634Sbrian range->ncprange_family = AF_INET; 59481634Sbrian range->ncprange_ip4addr = from->ncpaddr_ip4addr; 59581634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 59681634Sbrian range->ncprange_ip4width = 32; 59781634Sbrian break; 59881634Sbrian 59981634Sbrian#ifndef NOINET6 60081634Sbrian case AF_INET6: 60181634Sbrian range->ncprange_family = AF_INET6; 60281634Sbrian range->ncprange_ip6addr = from->ncpaddr_ip6addr; 60381634Sbrian range->ncprange_ip6width = 128; 60481634Sbrian break; 60581634Sbrian#endif 60681634Sbrian 60781634Sbrian default: 60881634Sbrian range->ncprange_family = AF_UNSPEC; 60981634Sbrian } 61081634Sbrian} 61181634Sbrian 61281634Sbrianint 61381634Sbrianncprange_setwidth(struct ncprange *range, int width) 61481634Sbrian{ 61581634Sbrian switch (range->ncprange_family) { 61681634Sbrian case AF_INET: 61781634Sbrian if (width < 0 || width > 32) 61881634Sbrian break; 61981634Sbrian range->ncprange_ip4width = width; 62081634Sbrian range->ncprange_ip4mask = bits2mask4(width); 62181634Sbrian break; 62281634Sbrian 62381634Sbrian#ifndef NOINET6 62481634Sbrian case AF_INET6: 62581634Sbrian if (width < 0 || width > 128) 62681634Sbrian break; 62781634Sbrian range->ncprange_ip6width = width; 62881634Sbrian break; 62981634Sbrian#endif 63081634Sbrian 63181634Sbrian case AF_UNSPEC: 63281634Sbrian return 1; 63381634Sbrian } 63481634Sbrian 63581634Sbrian return 0; 63681634Sbrian} 63781634Sbrian 63881634Sbrianvoid 63981634Sbrianncprange_setip4host(struct ncprange *range, struct in_addr from) 64081634Sbrian{ 64181634Sbrian range->ncprange_family = AF_INET; 64281634Sbrian range->ncprange_ip4addr = from; 64381634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 64481634Sbrian range->ncprange_ip4width = 32; 64581634Sbrian} 64681634Sbrian 64781634Sbrianvoid 64881634Sbrianncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk) 64981634Sbrian{ 65081634Sbrian range->ncprange_family = AF_INET; 65181634Sbrian range->ncprange_ip4addr = from; 65281634Sbrian range->ncprange_ip4mask = msk; 65381634Sbrian range->ncprange_ip4width = mask42bits(msk); 65481634Sbrian} 65581634Sbrian 65681634Sbrian 65781634Sbrianint 65881634Sbrianncprange_setip4mask(struct ncprange *range, struct in_addr mask) 65981634Sbrian{ 66081634Sbrian if (range->ncprange_family != AF_INET) 66181634Sbrian return 0; 66281634Sbrian range->ncprange_ip4mask = mask; 66381634Sbrian range->ncprange_ip4width = mask42bits(mask); 66481634Sbrian return 1; 66581634Sbrian} 66681634Sbrian 66781634Sbrianvoid 66881634Sbrianncprange_setsa(struct ncprange *range, const struct sockaddr *host, 66981634Sbrian const struct sockaddr *mask) 67081634Sbrian{ 67181634Sbrian const struct sockaddr_in *host4 = (const struct sockaddr_in *)host; 67281634Sbrian const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask; 67381634Sbrian#ifndef NOINET6 67481634Sbrian const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host; 67581634Sbrian const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask; 67681634Sbrian#endif 67781634Sbrian 67881634Sbrian switch (host->sa_family) { 67981634Sbrian case AF_INET: 68081634Sbrian range->ncprange_family = AF_INET; 68181634Sbrian range->ncprange_ip4addr = host4->sin_addr; 68281634Sbrian if (mask4) { 68381634Sbrian range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr; 68481634Sbrian range->ncprange_ip4width = mask42bits(mask4->sin_addr); 68581634Sbrian } else { 68681634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 68781634Sbrian range->ncprange_ip4width = 32; 68881634Sbrian } 68981634Sbrian break; 69081634Sbrian 69181634Sbrian#ifndef NOINET6 69281634Sbrian case AF_INET6: 69381634Sbrian range->ncprange_family = AF_INET6; 69481634Sbrian range->ncprange_ip6addr = host6->sin6_addr; 69581634Sbrian range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128; 69681634Sbrian break; 69781634Sbrian#endif 69881634Sbrian 69981634Sbrian default: 70081634Sbrian range->ncprange_family = AF_UNSPEC; 70181634Sbrian } 70281634Sbrian} 70381634Sbrian 70481634Sbrianvoid 70581634Sbrianncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host, 70681634Sbrian struct sockaddr_storage *mask) 70781634Sbrian{ 70881634Sbrian struct sockaddr_in *host4 = (struct sockaddr_in *)host; 70981634Sbrian struct sockaddr_in *mask4 = (struct sockaddr_in *)mask; 71081634Sbrian#ifndef NOINET6 71181634Sbrian struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host; 71281634Sbrian struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask; 71381634Sbrian#endif 71481634Sbrian 71581634Sbrian memset(host, '\0', sizeof(*host)); 71681634Sbrian if (mask) 71781634Sbrian memset(mask, '\0', sizeof(*mask)); 71881634Sbrian 71981634Sbrian switch (range->ncprange_family) { 72081634Sbrian case AF_INET: 72181634Sbrian host4->sin_family = AF_INET; 72281634Sbrian host4->sin_len = sizeof(*host4); 72381634Sbrian host4->sin_addr = range->ncprange_ip4addr; 72481634Sbrian if (mask4) { 72581634Sbrian mask4->sin_family = AF_INET; 72681634Sbrian mask4->sin_len = sizeof(*host4); 72781690Sbrian mask4->sin_addr = range->ncprange_ip4mask; 72881634Sbrian } 72981634Sbrian break; 73081634Sbrian 73181634Sbrian#ifndef NOINET6 73281634Sbrian case AF_INET6: 73381634Sbrian host6->sin6_family = AF_INET6; 73481634Sbrian host6->sin6_len = sizeof(*host6); 73581634Sbrian host6->sin6_addr = range->ncprange_ip6addr; 73681634Sbrian adjust_linklocal(host6); 73781634Sbrian if (mask6) { 73881634Sbrian mask6->sin6_family = AF_INET6; 73981634Sbrian mask6->sin6_len = sizeof(*host6); 74081634Sbrian mask6->sin6_addr = bits2mask6(range->ncprange_ip6width); 74181634Sbrian } 74281634Sbrian break; 74381634Sbrian#endif 74481634Sbrian 74581634Sbrian default: 74681634Sbrian host->ss_family = AF_UNSPEC; 74781634Sbrian if (mask) 74881634Sbrian mask->ss_family = AF_UNSPEC; 74981634Sbrian break; 75081634Sbrian } 75181634Sbrian} 75281634Sbrian 75381634Sbrianint 75481634Sbrianncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr) 75581634Sbrian{ 75681634Sbrian switch (range->ncprange_family) { 75781634Sbrian case AF_INET: 75881634Sbrian addr->ncpaddr_family = AF_INET; 75981634Sbrian addr->ncpaddr_ip4addr = range->ncprange_ip4addr; 76081634Sbrian return 1; 76181634Sbrian#ifndef NOINET6 76281634Sbrian case AF_INET6: 76381634Sbrian addr->ncpaddr_family = AF_INET6; 76481634Sbrian addr->ncpaddr_ip6addr = range->ncprange_ip6addr; 76581634Sbrian return 1; 76681634Sbrian#endif 76781634Sbrian } 76881634Sbrian 76981634Sbrian return 0; 77081634Sbrian} 77181634Sbrian 77281634Sbrianint 77381634Sbrianncprange_getip4addr(const struct ncprange *range, struct in_addr *addr) 77481634Sbrian{ 77581634Sbrian if (range->ncprange_family != AF_INET) 77681634Sbrian return 0; 77781634Sbrian 77881634Sbrian *addr = range->ncprange_ip4addr; 77981634Sbrian return 1; 78081634Sbrian} 78181634Sbrian 78281634Sbrianint 78381634Sbrianncprange_getip4mask(const struct ncprange *range, struct in_addr *mask) 78481634Sbrian{ 78581634Sbrian switch (range->ncprange_family) { 78681634Sbrian case AF_INET: 78781634Sbrian *mask = range->ncprange_ip4mask; 78881634Sbrian return 1; 78981634Sbrian } 79081634Sbrian 79181634Sbrian return 0; 79281634Sbrian} 79381634Sbrian 79481634Sbrianint 79581634Sbrianncprange_getwidth(const struct ncprange *range, int *width) 79681634Sbrian{ 79781634Sbrian switch (range->ncprange_family) { 79881634Sbrian case AF_INET: 79981634Sbrian *width = range->ncprange_ip4width; 80081634Sbrian return 1; 80181634Sbrian#ifndef NOINET6 80281634Sbrian case AF_INET6: 80381634Sbrian *width = range->ncprange_ip6width; 80481634Sbrian return 1; 80581634Sbrian#endif 80681634Sbrian } 80781634Sbrian 80881634Sbrian return 0; 80981634Sbrian} 81081634Sbrian 81181634Sbrianconst char * 81281634Sbrianncprange_ntoa(const struct ncprange *range) 81381634Sbrian{ 81481634Sbrian char *res; 81581634Sbrian struct ncpaddr addr; 81681634Sbrian int len; 81781634Sbrian 81881634Sbrian if (!ncprange_getaddr(range, &addr)) 81981634Sbrian return "<AF_UNSPEC>"; 82081634Sbrian 82181634Sbrian res = ncpaddr_ntowa(&addr); 82281634Sbrian len = strlen(res); 82381634Sbrian if (len >= NCP_ASCIIBUFFERSIZE - 1) 82481634Sbrian return res; 82581634Sbrian 82681634Sbrian switch (range->ncprange_family) { 82781634Sbrian case AF_INET: 82881634Sbrian if (range->ncprange_ip4width == -1) { 82981634Sbrian /* A non-contiguous mask */ 83081634Sbrian for (; len >= 3; res[len -= 2] = '\0') 83181634Sbrian if (strcmp(res + len - 2, ".0")) 83281634Sbrian break; 83381634Sbrian snprintf(res + len, sizeof res - len, "&0x%08lx", 83481634Sbrian ntohl(range->ncprange_ip4mask.s_addr)); 83581634Sbrian } else if (range->ncprange_ip4width < 32) 83681634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width); 83781634Sbrian 83881634Sbrian return res; 83981634Sbrian 84081634Sbrian#ifndef NOINET6 84181634Sbrian case AF_INET6: 84281634Sbrian if (range->ncprange_ip6width != 128) 84381634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width); 84481634Sbrian 84581634Sbrian return res; 84681634Sbrian#endif 84781634Sbrian } 84881634Sbrian 84981634Sbrian return "<AF_UNSPEC>"; 85081634Sbrian} 85181634Sbrian 85281634Sbrian#ifndef NOINET6 85381634Sbrianint 85481634Sbrianncprange_scopeid(const struct ncprange *range) 85581634Sbrian{ 85681634Sbrian const struct in6_addr *sin6; 85781634Sbrian int scopeid = -1; 85881634Sbrian 85981634Sbrian if (range->ncprange_family == AF_INET6) { 86081634Sbrian sin6 = &range->ncprange_ip6addr; 86181634Sbrian if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6)) 86281634Sbrian if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0) 86381634Sbrian scopeid = -1; 86481634Sbrian } 86581634Sbrian 86681634Sbrian return scopeid; 86781634Sbrian} 86881634Sbrian#endif 86981634Sbrian 87081634Sbrianint 87181634Sbrianncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data) 87281634Sbrian{ 87381634Sbrian int bits, len; 87481634Sbrian char *wp; 87581634Sbrian const char *cp; 87681634Sbrian char *s; 87781634Sbrian 87881634Sbrian len = strcspn(data, "/"); 87981634Sbrian 88081634Sbrian if (ncp && strncasecmp(data, "HISADDR", len) == 0) { 88181634Sbrian range->ncprange_family = AF_INET; 88281634Sbrian range->ncprange_ip4addr = ncp->ipcp.peer_ip; 88381634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 88481634Sbrian range->ncprange_ip4width = 32; 88581634Sbrian return 1; 88681634Sbrian#ifndef NOINET6 88781634Sbrian } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) { 88881634Sbrian ncprange_sethost(range, &ncp->ipv6cp.hisaddr); 88981634Sbrian return 1; 89081634Sbrian#endif 89181634Sbrian } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) { 89281634Sbrian range->ncprange_family = AF_INET; 89381634Sbrian range->ncprange_ip4addr = ncp->ipcp.my_ip; 89481634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 89581634Sbrian range->ncprange_ip4width = 32; 89681634Sbrian return 1; 89781634Sbrian#ifndef NOINET6 89881634Sbrian } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) { 89981634Sbrian ncprange_sethost(range, &ncp->ipv6cp.myaddr); 90081634Sbrian return 1; 90181634Sbrian#endif 90281634Sbrian } else if (ncp && strncasecmp(data, "DNS0", len) == 0) { 90381634Sbrian range->ncprange_family = AF_INET; 90481634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[0]; 90581634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 90681634Sbrian range->ncprange_ip4width = 32; 90781634Sbrian return 1; 90881634Sbrian } else if (ncp && strncasecmp(data, "DNS1", len) == 0) { 90981634Sbrian range->ncprange_family = AF_INET; 91081634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[1]; 91181634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 91281634Sbrian range->ncprange_ip4width = 32; 91381634Sbrian return 1; 91481634Sbrian } 91581634Sbrian 91681634Sbrian s = (char *)alloca(len + 1); 91781634Sbrian strncpy(s, data, len); 91881634Sbrian s[len] = '\0'; 91981634Sbrian bits = -1; 92081634Sbrian 92181634Sbrian if (data[len] != '\0') { 92281634Sbrian bits = strtol(data + len + 1, &wp, 0); 92381634Sbrian if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) { 92481634Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 92581634Sbrian return 0; 92681634Sbrian } 92781634Sbrian } 92881634Sbrian 92981634Sbrian if ((cp = strchr(data, ':')) == NULL) { 93081634Sbrian range->ncprange_family = AF_INET; 93181634Sbrian 93281634Sbrian range->ncprange_ip4addr = GetIpAddr(s); 93381634Sbrian 93481634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_NONE) { 93581634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 93681634Sbrian return 0; 93781634Sbrian } 93881634Sbrian 93981634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) { 94081634Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 94181634Sbrian range->ncprange_ip4width = 0; 94281690Sbrian } else if (bits == -1) { 94381634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 94481634Sbrian range->ncprange_ip4width = 32; 94581690Sbrian } else if (bits > 32) { 94681690Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 94781690Sbrian return 0; 94881634Sbrian } else { 94981634Sbrian range->ncprange_ip4mask = bits2mask4(bits); 95081634Sbrian range->ncprange_ip4width = bits; 95181634Sbrian } 95281634Sbrian 95381634Sbrian return 1; 95481634Sbrian#ifndef NOINET6 95581634Sbrian } else if (strchr(cp + 1, ':') != NULL) { 95681634Sbrian range->ncprange_family = AF_INET6; 95781634Sbrian 95881634Sbrian if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) { 95981634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 96081634Sbrian return 0; 96181634Sbrian } 96281634Sbrian 96381634Sbrian if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 96481634Sbrian range->ncprange_ip6width = 0; 96581634Sbrian else 96681634Sbrian range->ncprange_ip6width = (bits == -1) ? 128 : bits; 96781634Sbrian return 1; 96881634Sbrian#endif 96981634Sbrian } 97081634Sbrian 97181634Sbrian return 0; 97281634Sbrian} 973