ncpaddr.c revision 81690
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 81690 2001-08-15 12:07:39Z 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 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 adjust_linklocal(host6); 32281634Sbrian break; 32381634Sbrian#endif 32481634Sbrian 32581634Sbrian default: 32681634Sbrian host->ss_family = AF_UNSPEC; 32781634Sbrian break; 32881634Sbrian } 32981634Sbrian} 33081634Sbrian 33181634Sbrianvoid 33281634Sbrianncpaddr_setsa(struct ncpaddr *addr, const struct sockaddr *host) 33381634Sbrian{ 33481634Sbrian const struct sockaddr_in *host4 = (const struct sockaddr_in *)host; 33581634Sbrian#ifndef NOINET6 33681634Sbrian const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host; 33781634Sbrian#endif 33881634Sbrian 33981634Sbrian switch (host->sa_family) { 34081634Sbrian case AF_INET: 34181634Sbrian addr->ncpaddr_family = AF_INET; 34281634Sbrian addr->ncpaddr_ip4addr = host4->sin_addr; 34381634Sbrian break; 34481634Sbrian 34581634Sbrian#ifndef NOINET6 34681634Sbrian case AF_INET6: 34781634Sbrian if (IN6_IS_ADDR_V4MAPPED(&host6->sin6_addr)) { 34881634Sbrian addr->ncpaddr_family = AF_INET; 34981634Sbrian addr->ncpaddr_ip4addr.s_addr = 35081634Sbrian *(const u_int32_t *)(host6->sin6_addr.s6_addr + 12); 35181634Sbrian } else { 35281634Sbrian addr->ncpaddr_family = AF_INET6; 35381634Sbrian addr->ncpaddr_ip6addr = host6->sin6_addr; 35481634Sbrian } 35581634Sbrian break; 35681634Sbrian#endif 35781634Sbrian 35881634Sbrian default: 35981634Sbrian addr->ncpaddr_family = AF_UNSPEC; 36081634Sbrian } 36181634Sbrian} 36281634Sbrian 36381634Sbrianstatic char * 36481634Sbrianncpaddr_ntowa(const struct ncpaddr *addr) 36581634Sbrian{ 36681634Sbrian static char res[NCP_ASCIIBUFFERSIZE]; 36781634Sbrian#ifndef NOINET6 36881634Sbrian struct sockaddr_in6 sin6; 36981634Sbrian#endif 37081634Sbrian 37181634Sbrian switch (addr->ncpaddr_family) { 37281634Sbrian case AF_INET: 37381634Sbrian snprintf(res, sizeof res, "%s", inet_ntoa(addr->ncpaddr_ip4addr)); 37481634Sbrian return res; 37581634Sbrian 37681634Sbrian#ifndef NOINET6 37781634Sbrian case AF_INET6: 37881634Sbrian memset(&sin6, '\0', sizeof(sin6)); 37981634Sbrian sin6.sin6_len = sizeof(sin6); 38081634Sbrian sin6.sin6_family = AF_INET6; 38181634Sbrian sin6.sin6_addr = addr->ncpaddr_ip6addr; 38281634Sbrian adjust_linklocal(&sin6); 38381634Sbrian if (getnameinfo((struct sockaddr *)&sin6, sizeof sin6, res, sizeof(res), 38481634Sbrian NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST) != 0) 38581634Sbrian break; 38681634Sbrian 38781634Sbrian return res; 38881634Sbrian#endif 38981634Sbrian } 39081634Sbrian 39181634Sbrian snprintf(res, sizeof res, "<AF_UNSPEC>"); 39281634Sbrian return res; 39381634Sbrian} 39481634Sbrian 39581634Sbrianconst char * 39681634Sbrianncpaddr_ntoa(const struct ncpaddr *addr) 39781634Sbrian{ 39881634Sbrian return ncpaddr_ntowa(addr); 39981634Sbrian} 40081634Sbrian 40181634Sbrian 40281634Sbrianint 40381634Sbrianncpaddr_aton(struct ncpaddr *addr, struct ncp *ncp, const char *data) 40481634Sbrian{ 40581634Sbrian struct ncprange range; 40681634Sbrian 40781634Sbrian if (!ncprange_aton(&range, ncp, data)) 40881634Sbrian return 0; 40981634Sbrian 41081634Sbrian if (range.ncprange_family == AF_INET && range.ncprange_ip4width != 32) { 41181634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 32 bits allowed\n", data); 41281634Sbrian return 0; 41381634Sbrian } 41481634Sbrian 41581634Sbrian#ifndef NOINET6 41681634Sbrian if (range.ncprange_family == AF_INET6 && range.ncprange_ip6width != 128) { 41781634Sbrian log_Printf(LogWARN, "ncpaddr_aton: %s: Only 128 bits allowed\n", data); 41881634Sbrian return 0; 41981634Sbrian } 42081634Sbrian#endif 42181634Sbrian 42281634Sbrian switch (range.ncprange_family) { 42381634Sbrian case AF_INET: 42481634Sbrian addr->ncpaddr_family = range.ncprange_family; 42581634Sbrian addr->ncpaddr_ip4addr = range.ncprange_ip4addr; 42681634Sbrian return 1; 42781634Sbrian 42881634Sbrian#ifndef NOINET6 42981634Sbrian case AF_INET6: 43081634Sbrian addr->ncpaddr_family = range.ncprange_family; 43181634Sbrian addr->ncpaddr_ip6addr = range.ncprange_ip6addr; 43281634Sbrian return 1; 43381634Sbrian#endif 43481634Sbrian } 43581634Sbrian 43681634Sbrian return 0; 43781634Sbrian} 43881634Sbrian 43981634Sbrianvoid 44081634Sbrianncprange_init(struct ncprange *range) 44181634Sbrian{ 44281634Sbrian range->ncprange_family = AF_UNSPEC; 44381634Sbrian} 44481634Sbrian 44581634Sbrianint 44681634Sbrianncprange_isset(const struct ncprange *range) 44781634Sbrian{ 44881634Sbrian return range->ncprange_family != AF_UNSPEC; 44981634Sbrian} 45081634Sbrian 45181634Sbrianint 45281634Sbrianncprange_equal(const struct ncprange *range, const struct ncprange *cmp) 45381634Sbrian{ 45481634Sbrian if (range->ncprange_family != cmp->ncprange_family) 45581634Sbrian return 0; 45681634Sbrian 45781634Sbrian switch (range->ncprange_family) { 45881634Sbrian case AF_INET: 45981634Sbrian if (range->ncprange_ip4addr.s_addr != cmp->ncprange_ip4addr.s_addr) 46081634Sbrian return 0; 46181634Sbrian return range->ncprange_ip4mask.s_addr == cmp->ncprange_ip4mask.s_addr; 46281634Sbrian 46381634Sbrian#ifndef NOINET6 46481634Sbrian case AF_INET6: 46581634Sbrian if (range->ncprange_ip6width != cmp->ncprange_ip6width) 46681634Sbrian return 0; 46781634Sbrian return !memcmp(&range->ncprange_ip6addr, &cmp->ncprange_ip6addr, 46881634Sbrian sizeof range->ncprange_ip6addr); 46981634Sbrian#endif 47081634Sbrian 47181634Sbrian case AF_UNSPEC: 47281634Sbrian return 1; 47381634Sbrian } 47481634Sbrian 47581634Sbrian return 0; 47681634Sbrian} 47781634Sbrian 47881634Sbrianint 47981634Sbrianncprange_isdefault(const struct ncprange *range) 48081634Sbrian{ 48181634Sbrian switch (range->ncprange_family) { 48281634Sbrian case AF_INET: 48381634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) 48481634Sbrian return 1; 48581634Sbrian break; 48681634Sbrian 48781634Sbrian#ifndef NOINET6 48881634Sbrian case AF_INET6: 48981634Sbrian if (range->ncprange_ip6width == 0 && 49081634Sbrian IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 49181634Sbrian return 1; 49281634Sbrian break; 49381634Sbrian#endif 49481634Sbrian } 49581634Sbrian 49681634Sbrian return 0; 49781634Sbrian} 49881634Sbrian 49981634Sbrianvoid 50081634Sbrianncprange_setdefault(struct ncprange *range, int af) 50181634Sbrian{ 50281634Sbrian memset(range, '\0', sizeof *range); 50381634Sbrian range->ncprange_family = af; 50481634Sbrian} 50581634Sbrian 50681634Sbrianint 50781634Sbrianncprange_contains(const struct ncprange *range, const struct ncpaddr *addr) 50881634Sbrian{ 50981634Sbrian#ifndef NOINET6 51081634Sbrian const u_char masks[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 51181634Sbrian const u_char *addrp, *rangep; 51281634Sbrian int bits; 51381634Sbrian#endif 51481634Sbrian 51581634Sbrian if (range->ncprange_family != addr->ncpaddr_family) 51681634Sbrian return 0; 51781634Sbrian 51881634Sbrian switch (range->ncprange_family) { 51981634Sbrian case AF_INET: 52081634Sbrian return !((addr->ncpaddr_ip4addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 52181634Sbrian range->ncprange_ip4mask.s_addr); 52281634Sbrian 52381634Sbrian#ifndef NOINET6 52481634Sbrian case AF_INET6: 52581634Sbrian rangep = (const u_char *)range->ncprange_ip6addr.s6_addr; 52681634Sbrian addrp = (const u_char *)addr->ncpaddr_ip6addr.s6_addr; 52781634Sbrian 52881634Sbrian for (bits = range->ncprange_ip6width; bits > 0; bits -= 8) 52981634Sbrian if ((*addrp++ ^ *rangep++) & masks[bits > 7 ? 7 : bits - 1]) 53081634Sbrian return 0; 53181634Sbrian 53281634Sbrian return 1; 53381634Sbrian#endif 53481634Sbrian } 53581634Sbrian 53681634Sbrian return 0; 53781634Sbrian} 53881634Sbrian 53981634Sbrianint 54081634Sbrianncprange_containsip4(const struct ncprange *range, struct in_addr addr) 54181634Sbrian{ 54281634Sbrian switch (range->ncprange_family) { 54381634Sbrian case AF_INET: 54481634Sbrian return !((addr.s_addr ^ range->ncprange_ip4addr.s_addr) & 54581634Sbrian range->ncprange_ip4mask.s_addr); 54681634Sbrian } 54781634Sbrian 54881634Sbrian return 0; 54981634Sbrian} 55081634Sbrian 55181634Sbrianvoid 55281634Sbrianncprange_copy(struct ncprange *range, const struct ncprange *from) 55381634Sbrian{ 55481634Sbrian switch (from->ncprange_family) { 55581634Sbrian case AF_INET: 55681634Sbrian range->ncprange_family = AF_INET; 55781634Sbrian range->ncprange_ip4addr = from->ncprange_ip4addr; 55881634Sbrian range->ncprange_ip4mask = from->ncprange_ip4mask; 55981634Sbrian range->ncprange_ip4width = from->ncprange_ip4width; 56081634Sbrian break; 56181634Sbrian 56281634Sbrian#ifndef NOINET6 56381634Sbrian case AF_INET6: 56481634Sbrian range->ncprange_family = AF_INET6; 56581634Sbrian range->ncprange_ip6addr = from->ncprange_ip6addr; 56681634Sbrian range->ncprange_ip6width = from->ncprange_ip6width; 56781634Sbrian break; 56881634Sbrian#endif 56981634Sbrian 57081634Sbrian default: 57181634Sbrian range->ncprange_family = AF_UNSPEC; 57281634Sbrian } 57381634Sbrian} 57481634Sbrian 57581634Sbrianvoid 57681634Sbrianncprange_set(struct ncprange *range, const struct ncpaddr *addr, int width) 57781634Sbrian{ 57881634Sbrian ncprange_sethost(range, addr); 57981634Sbrian ncprange_setwidth(range, width); 58081634Sbrian} 58181634Sbrian 58281634Sbrianvoid 58381634Sbrianncprange_sethost(struct ncprange *range, const struct ncpaddr *from) 58481634Sbrian{ 58581634Sbrian switch (from->ncpaddr_family) { 58681634Sbrian case AF_INET: 58781634Sbrian range->ncprange_family = AF_INET; 58881634Sbrian range->ncprange_ip4addr = from->ncpaddr_ip4addr; 58981634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 59081634Sbrian range->ncprange_ip4width = 32; 59181634Sbrian break; 59281634Sbrian 59381634Sbrian#ifndef NOINET6 59481634Sbrian case AF_INET6: 59581634Sbrian range->ncprange_family = AF_INET6; 59681634Sbrian range->ncprange_ip6addr = from->ncpaddr_ip6addr; 59781634Sbrian range->ncprange_ip6width = 128; 59881634Sbrian break; 59981634Sbrian#endif 60081634Sbrian 60181634Sbrian default: 60281634Sbrian range->ncprange_family = AF_UNSPEC; 60381634Sbrian } 60481634Sbrian} 60581634Sbrian 60681634Sbrianint 60781634Sbrianncprange_setwidth(struct ncprange *range, int width) 60881634Sbrian{ 60981634Sbrian switch (range->ncprange_family) { 61081634Sbrian case AF_INET: 61181634Sbrian if (width < 0 || width > 32) 61281634Sbrian break; 61381634Sbrian range->ncprange_ip4width = width; 61481634Sbrian range->ncprange_ip4mask = bits2mask4(width); 61581634Sbrian break; 61681634Sbrian 61781634Sbrian#ifndef NOINET6 61881634Sbrian case AF_INET6: 61981634Sbrian if (width < 0 || width > 128) 62081634Sbrian break; 62181634Sbrian range->ncprange_ip6width = width; 62281634Sbrian break; 62381634Sbrian#endif 62481634Sbrian 62581634Sbrian case AF_UNSPEC: 62681634Sbrian return 1; 62781634Sbrian } 62881634Sbrian 62981634Sbrian return 0; 63081634Sbrian} 63181634Sbrian 63281634Sbrianvoid 63381634Sbrianncprange_setip4host(struct ncprange *range, struct in_addr from) 63481634Sbrian{ 63581634Sbrian range->ncprange_family = AF_INET; 63681634Sbrian range->ncprange_ip4addr = from; 63781634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 63881634Sbrian range->ncprange_ip4width = 32; 63981634Sbrian} 64081634Sbrian 64181634Sbrianvoid 64281634Sbrianncprange_setip4(struct ncprange *range, struct in_addr from, struct in_addr msk) 64381634Sbrian{ 64481634Sbrian range->ncprange_family = AF_INET; 64581634Sbrian range->ncprange_ip4addr = from; 64681634Sbrian range->ncprange_ip4mask = msk; 64781634Sbrian range->ncprange_ip4width = mask42bits(msk); 64881634Sbrian} 64981634Sbrian 65081634Sbrian 65181634Sbrianint 65281634Sbrianncprange_setip4mask(struct ncprange *range, struct in_addr mask) 65381634Sbrian{ 65481634Sbrian if (range->ncprange_family != AF_INET) 65581634Sbrian return 0; 65681634Sbrian range->ncprange_ip4mask = mask; 65781634Sbrian range->ncprange_ip4width = mask42bits(mask); 65881634Sbrian return 1; 65981634Sbrian} 66081634Sbrian 66181634Sbrianvoid 66281634Sbrianncprange_setsa(struct ncprange *range, const struct sockaddr *host, 66381634Sbrian const struct sockaddr *mask) 66481634Sbrian{ 66581634Sbrian const struct sockaddr_in *host4 = (const struct sockaddr_in *)host; 66681634Sbrian const struct sockaddr_in *mask4 = (const struct sockaddr_in *)mask; 66781634Sbrian#ifndef NOINET6 66881634Sbrian const struct sockaddr_in6 *host6 = (const struct sockaddr_in6 *)host; 66981634Sbrian const struct sockaddr_in6 *mask6 = (const struct sockaddr_in6 *)mask; 67081634Sbrian#endif 67181634Sbrian 67281634Sbrian switch (host->sa_family) { 67381634Sbrian case AF_INET: 67481634Sbrian range->ncprange_family = AF_INET; 67581634Sbrian range->ncprange_ip4addr = host4->sin_addr; 67681634Sbrian if (mask4) { 67781634Sbrian range->ncprange_ip4mask.s_addr = mask4->sin_addr.s_addr; 67881634Sbrian range->ncprange_ip4width = mask42bits(mask4->sin_addr); 67981634Sbrian } else { 68081634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 68181634Sbrian range->ncprange_ip4width = 32; 68281634Sbrian } 68381634Sbrian break; 68481634Sbrian 68581634Sbrian#ifndef NOINET6 68681634Sbrian case AF_INET6: 68781634Sbrian range->ncprange_family = AF_INET6; 68881634Sbrian range->ncprange_ip6addr = host6->sin6_addr; 68981634Sbrian range->ncprange_ip6width = mask6 ? mask62bits(&mask6->sin6_addr) : 128; 69081634Sbrian break; 69181634Sbrian#endif 69281634Sbrian 69381634Sbrian default: 69481634Sbrian range->ncprange_family = AF_UNSPEC; 69581634Sbrian } 69681634Sbrian} 69781634Sbrian 69881634Sbrianvoid 69981634Sbrianncprange_getsa(const struct ncprange *range, struct sockaddr_storage *host, 70081634Sbrian struct sockaddr_storage *mask) 70181634Sbrian{ 70281634Sbrian struct sockaddr_in *host4 = (struct sockaddr_in *)host; 70381634Sbrian struct sockaddr_in *mask4 = (struct sockaddr_in *)mask; 70481634Sbrian#ifndef NOINET6 70581634Sbrian struct sockaddr_in6 *host6 = (struct sockaddr_in6 *)host; 70681634Sbrian struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask; 70781634Sbrian#endif 70881634Sbrian 70981634Sbrian memset(host, '\0', sizeof(*host)); 71081634Sbrian if (mask) 71181634Sbrian memset(mask, '\0', sizeof(*mask)); 71281634Sbrian 71381634Sbrian switch (range->ncprange_family) { 71481634Sbrian case AF_INET: 71581634Sbrian host4->sin_family = AF_INET; 71681634Sbrian host4->sin_len = sizeof(*host4); 71781634Sbrian host4->sin_addr = range->ncprange_ip4addr; 71881634Sbrian if (mask4) { 71981634Sbrian mask4->sin_family = AF_INET; 72081634Sbrian mask4->sin_len = sizeof(*host4); 72181690Sbrian mask4->sin_addr = range->ncprange_ip4mask; 72281634Sbrian } 72381634Sbrian break; 72481634Sbrian 72581634Sbrian#ifndef NOINET6 72681634Sbrian case AF_INET6: 72781634Sbrian host6->sin6_family = AF_INET6; 72881634Sbrian host6->sin6_len = sizeof(*host6); 72981634Sbrian host6->sin6_addr = range->ncprange_ip6addr; 73081634Sbrian adjust_linklocal(host6); 73181634Sbrian if (mask6) { 73281634Sbrian mask6->sin6_family = AF_INET6; 73381634Sbrian mask6->sin6_len = sizeof(*host6); 73481634Sbrian mask6->sin6_addr = bits2mask6(range->ncprange_ip6width); 73581634Sbrian } 73681634Sbrian break; 73781634Sbrian#endif 73881634Sbrian 73981634Sbrian default: 74081634Sbrian host->ss_family = AF_UNSPEC; 74181634Sbrian if (mask) 74281634Sbrian mask->ss_family = AF_UNSPEC; 74381634Sbrian break; 74481634Sbrian } 74581634Sbrian} 74681634Sbrian 74781634Sbrianint 74881634Sbrianncprange_getaddr(const struct ncprange *range, struct ncpaddr *addr) 74981634Sbrian{ 75081634Sbrian switch (range->ncprange_family) { 75181634Sbrian case AF_INET: 75281634Sbrian addr->ncpaddr_family = AF_INET; 75381634Sbrian addr->ncpaddr_ip4addr = range->ncprange_ip4addr; 75481634Sbrian return 1; 75581634Sbrian#ifndef NOINET6 75681634Sbrian case AF_INET6: 75781634Sbrian addr->ncpaddr_family = AF_INET6; 75881634Sbrian addr->ncpaddr_ip6addr = range->ncprange_ip6addr; 75981634Sbrian return 1; 76081634Sbrian#endif 76181634Sbrian } 76281634Sbrian 76381634Sbrian return 0; 76481634Sbrian} 76581634Sbrian 76681634Sbrianint 76781634Sbrianncprange_getip4addr(const struct ncprange *range, struct in_addr *addr) 76881634Sbrian{ 76981634Sbrian if (range->ncprange_family != AF_INET) 77081634Sbrian return 0; 77181634Sbrian 77281634Sbrian *addr = range->ncprange_ip4addr; 77381634Sbrian return 1; 77481634Sbrian} 77581634Sbrian 77681634Sbrianint 77781634Sbrianncprange_getip4mask(const struct ncprange *range, struct in_addr *mask) 77881634Sbrian{ 77981634Sbrian switch (range->ncprange_family) { 78081634Sbrian case AF_INET: 78181634Sbrian *mask = range->ncprange_ip4mask; 78281634Sbrian return 1; 78381634Sbrian } 78481634Sbrian 78581634Sbrian return 0; 78681634Sbrian} 78781634Sbrian 78881634Sbrianint 78981634Sbrianncprange_getwidth(const struct ncprange *range, int *width) 79081634Sbrian{ 79181634Sbrian switch (range->ncprange_family) { 79281634Sbrian case AF_INET: 79381634Sbrian *width = range->ncprange_ip4width; 79481634Sbrian return 1; 79581634Sbrian#ifndef NOINET6 79681634Sbrian case AF_INET6: 79781634Sbrian *width = range->ncprange_ip6width; 79881634Sbrian return 1; 79981634Sbrian#endif 80081634Sbrian } 80181634Sbrian 80281634Sbrian return 0; 80381634Sbrian} 80481634Sbrian 80581634Sbrianconst char * 80681634Sbrianncprange_ntoa(const struct ncprange *range) 80781634Sbrian{ 80881634Sbrian char *res; 80981634Sbrian struct ncpaddr addr; 81081634Sbrian int len; 81181634Sbrian 81281634Sbrian if (!ncprange_getaddr(range, &addr)) 81381634Sbrian return "<AF_UNSPEC>"; 81481634Sbrian 81581634Sbrian res = ncpaddr_ntowa(&addr); 81681634Sbrian len = strlen(res); 81781634Sbrian if (len >= NCP_ASCIIBUFFERSIZE - 1) 81881634Sbrian return res; 81981634Sbrian 82081634Sbrian switch (range->ncprange_family) { 82181634Sbrian case AF_INET: 82281634Sbrian if (range->ncprange_ip4width == -1) { 82381634Sbrian /* A non-contiguous mask */ 82481634Sbrian for (; len >= 3; res[len -= 2] = '\0') 82581634Sbrian if (strcmp(res + len - 2, ".0")) 82681634Sbrian break; 82781634Sbrian snprintf(res + len, sizeof res - len, "&0x%08lx", 82881634Sbrian ntohl(range->ncprange_ip4mask.s_addr)); 82981634Sbrian } else if (range->ncprange_ip4width < 32) 83081634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip4width); 83181634Sbrian 83281634Sbrian return res; 83381634Sbrian 83481634Sbrian#ifndef NOINET6 83581634Sbrian case AF_INET6: 83681634Sbrian if (range->ncprange_ip6width != 128) 83781634Sbrian snprintf(res + len, sizeof res - len, "/%d", range->ncprange_ip6width); 83881634Sbrian 83981634Sbrian return res; 84081634Sbrian#endif 84181634Sbrian } 84281634Sbrian 84381634Sbrian return "<AF_UNSPEC>"; 84481634Sbrian} 84581634Sbrian 84681634Sbrian#ifndef NOINET6 84781634Sbrianint 84881634Sbrianncprange_scopeid(const struct ncprange *range) 84981634Sbrian{ 85081634Sbrian const struct in6_addr *sin6; 85181634Sbrian int scopeid = -1; 85281634Sbrian 85381634Sbrian if (range->ncprange_family == AF_INET6) { 85481634Sbrian sin6 = &range->ncprange_ip6addr; 85581634Sbrian if (IN6_IS_ADDR_LINKLOCAL(sin6) || IN6_IS_ADDR_MC_LINKLOCAL(sin6)) 85681634Sbrian if ((scopeid = ntohs(*(const u_short *)&sin6->s6_addr[2])) == 0) 85781634Sbrian scopeid = -1; 85881634Sbrian } 85981634Sbrian 86081634Sbrian return scopeid; 86181634Sbrian} 86281634Sbrian#endif 86381634Sbrian 86481634Sbrianint 86581634Sbrianncprange_aton(struct ncprange *range, struct ncp *ncp, const char *data) 86681634Sbrian{ 86781634Sbrian int bits, len; 86881634Sbrian char *wp; 86981634Sbrian const char *cp; 87081634Sbrian char *s; 87181634Sbrian 87281634Sbrian len = strcspn(data, "/"); 87381634Sbrian 87481634Sbrian if (ncp && strncasecmp(data, "HISADDR", len) == 0) { 87581634Sbrian range->ncprange_family = AF_INET; 87681634Sbrian range->ncprange_ip4addr = ncp->ipcp.peer_ip; 87781634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 87881634Sbrian range->ncprange_ip4width = 32; 87981634Sbrian return 1; 88081634Sbrian#ifndef NOINET6 88181634Sbrian } else if (ncp && strncasecmp(data, "HISADDR6", len) == 0) { 88281634Sbrian ncprange_sethost(range, &ncp->ipv6cp.hisaddr); 88381634Sbrian return 1; 88481634Sbrian#endif 88581634Sbrian } else if (ncp && strncasecmp(data, "MYADDR", len) == 0) { 88681634Sbrian range->ncprange_family = AF_INET; 88781634Sbrian range->ncprange_ip4addr = ncp->ipcp.my_ip; 88881634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 88981634Sbrian range->ncprange_ip4width = 32; 89081634Sbrian return 1; 89181634Sbrian#ifndef NOINET6 89281634Sbrian } else if (ncp && strncasecmp(data, "MYADDR6", len) == 0) { 89381634Sbrian ncprange_sethost(range, &ncp->ipv6cp.myaddr); 89481634Sbrian return 1; 89581634Sbrian#endif 89681634Sbrian } else if (ncp && strncasecmp(data, "DNS0", len) == 0) { 89781634Sbrian range->ncprange_family = AF_INET; 89881634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[0]; 89981634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 90081634Sbrian range->ncprange_ip4width = 32; 90181634Sbrian return 1; 90281634Sbrian } else if (ncp && strncasecmp(data, "DNS1", len) == 0) { 90381634Sbrian range->ncprange_family = AF_INET; 90481634Sbrian range->ncprange_ip4addr = ncp->ipcp.ns.dns[1]; 90581634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 90681634Sbrian range->ncprange_ip4width = 32; 90781634Sbrian return 1; 90881634Sbrian } 90981634Sbrian 91081634Sbrian s = (char *)alloca(len + 1); 91181634Sbrian strncpy(s, data, len); 91281634Sbrian s[len] = '\0'; 91381634Sbrian bits = -1; 91481634Sbrian 91581634Sbrian if (data[len] != '\0') { 91681634Sbrian bits = strtol(data + len + 1, &wp, 0); 91781634Sbrian if (*wp || wp == data + len + 1 || bits < 0 || bits > 128) { 91881634Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 91981634Sbrian return 0; 92081634Sbrian } 92181634Sbrian } 92281634Sbrian 92381634Sbrian if ((cp = strchr(data, ':')) == NULL) { 92481634Sbrian range->ncprange_family = AF_INET; 92581634Sbrian 92681634Sbrian range->ncprange_ip4addr = GetIpAddr(s); 92781634Sbrian 92881634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_NONE) { 92981634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 93081634Sbrian return 0; 93181634Sbrian } 93281634Sbrian 93381634Sbrian if (range->ncprange_ip4addr.s_addr == INADDR_ANY) { 93481634Sbrian range->ncprange_ip4mask.s_addr = INADDR_ANY; 93581634Sbrian range->ncprange_ip4width = 0; 93681690Sbrian } else if (bits == -1) { 93781634Sbrian range->ncprange_ip4mask.s_addr = INADDR_BROADCAST; 93881634Sbrian range->ncprange_ip4width = 32; 93981690Sbrian } else if (bits > 32) { 94081690Sbrian log_Printf(LogWARN, "ncprange_aton: bad mask width.\n"); 94181690Sbrian return 0; 94281634Sbrian } else { 94381634Sbrian range->ncprange_ip4mask = bits2mask4(bits); 94481634Sbrian range->ncprange_ip4width = bits; 94581634Sbrian } 94681634Sbrian 94781634Sbrian return 1; 94881634Sbrian#ifndef NOINET6 94981634Sbrian } else if (strchr(cp + 1, ':') != NULL) { 95081634Sbrian range->ncprange_family = AF_INET6; 95181634Sbrian 95281634Sbrian if (inet_pton(AF_INET6, s, &range->ncprange_ip6addr) != 1) { 95381634Sbrian log_Printf(LogWARN, "ncprange_aton: %s: Bad address\n", s); 95481634Sbrian return 0; 95581634Sbrian } 95681634Sbrian 95781634Sbrian if (IN6_IS_ADDR_UNSPECIFIED(&range->ncprange_ip6addr)) 95881634Sbrian range->ncprange_ip6width = 0; 95981634Sbrian else 96081634Sbrian range->ncprange_ip6width = (bits == -1) ? 128 : bits; 96181634Sbrian return 1; 96281634Sbrian#endif 96381634Sbrian } 96481634Sbrian 96581634Sbrian return 0; 96681634Sbrian} 967