1122679Sume/* $KAME: prefix.c,v 1.13 2003/09/02 22:50:17 itojun Exp $ */ 278064Sume/* $FreeBSD: releng/10.3/usr.sbin/faithd/prefix.c 230359 2012-01-20 01:39:08Z eadler $ */ 378064Sume 478064Sume/* 578064Sume * Copyright (C) 2000 WIDE Project. 678064Sume * All rights reserved. 778064Sume * 878064Sume * Redistribution and use in source and binary forms, with or without 978064Sume * modification, are permitted provided that the following conditions 1078064Sume * are met: 1178064Sume * 1. Redistributions of source code must retain the above copyright 1278064Sume * notice, this list of conditions and the following disclaimer. 1378064Sume * 2. Redistributions in binary form must reproduce the above copyright 1478064Sume * notice, this list of conditions and the following disclaimer in the 1578064Sume * documentation and/or other materials provided with the distribution. 1678064Sume * 3. Neither the name of the project nor the names of its contributors 1778064Sume * may be used to endorse or promote products derived from this software 1878064Sume * without specific prior written permission. 1978064Sume * 2078064Sume * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2178064Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2278064Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2378064Sume * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2478064Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2578064Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2678064Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2778064Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2878064Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2978064Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3078064Sume * SUCH DAMAGE. 3178064Sume */ 3278064Sume 3378064Sume#include <sys/types.h> 3478064Sume#include <sys/socket.h> 3578064Sume#include <netinet/in.h> 3678064Sume#include <stdio.h> 3778064Sume#include <netdb.h> 3878064Sume#include <string.h> 3978064Sume#include <stddef.h> 4078064Sume#include <stdlib.h> 4178064Sume#include <limits.h> 4278064Sume 4378064Sume#ifndef offsetof 4478064Sume#define offsetof(type, member) ((size_t)(u_long)(&((type *)0)->member)) 4578064Sume#endif 4678064Sume 4778064Sume#include "faithd.h" 4878064Sume#include "prefix.h" 4978064Sume 50173412Skevlostatic int prefix_set(const char *, struct prefix *, int); 51173412Skevlostatic struct config *config_load1(const char *); 5278064Sume#if 0 53173412Skevlostatic void config_show1(const struct config *); 54173412Skevlostatic void config_show(void); 5578064Sume#endif 5678064Sume 5778064Sumestruct config *config_list = NULL; 5878064Sumeconst int niflags = NI_NUMERICHOST; 5978064Sume 6078064Sumestatic int 61122679Sumeprefix_set(const char *s, struct prefix *prefix, int slash) 6278064Sume{ 63122679Sume char *p = NULL, *q, *r; 6478064Sume struct addrinfo hints, *res = NULL; 6578064Sume int max; 6678064Sume 6778064Sume p = strdup(s); 68122679Sume if (!p) 69122679Sume goto fail; 7078064Sume q = strchr(p, '/'); 7178064Sume if (q) { 7278064Sume if (!slash) 7378064Sume goto fail; 7478064Sume *q++ = '\0'; 7578064Sume } 7678064Sume 7778064Sume memset(&hints, 0, sizeof(hints)); 7878064Sume hints.ai_family = PF_UNSPEC; 7978064Sume hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 8078064Sume hints.ai_flags = AI_NUMERICHOST; 8178064Sume if (getaddrinfo(p, "0", &hints, &res)) 8278064Sume goto fail; 8378064Sume if (res->ai_next || res->ai_addrlen > sizeof(prefix->a)) 8478064Sume goto fail; 8578064Sume memcpy(&prefix->a, res->ai_addr, res->ai_addrlen); 8678064Sume 8778064Sume switch (prefix->a.ss_family) { 8878064Sume case AF_INET: 8978064Sume max = 32; 9078064Sume break; 9178064Sume case AF_INET6: 9278064Sume max = 128; 9378064Sume break; 9478064Sume default: 9578064Sume max = -1; 9678064Sume break; 9778064Sume } 9878064Sume 9978064Sume if (q) { 10078064Sume r = NULL; 10178064Sume prefix->l = (int)strtoul(q, &r, 10); 10278064Sume if (!*q || *r) 10378064Sume goto fail; 10478064Sume if (prefix->l < 0 || prefix->l > max) 10578064Sume goto fail; 10678064Sume } else 10778064Sume prefix->l = max; 10878064Sume 10978064Sume if (p) 11078064Sume free(p); 11178064Sume if (res) 11278064Sume freeaddrinfo(res); 11378064Sume return 0; 11478064Sume 11578064Sumefail: 11678064Sume if (p) 11778064Sume free(p); 11878064Sume if (res) 11978064Sume freeaddrinfo(res); 12078064Sume return -1; 12178064Sume} 12278064Sume 12378064Sumeconst char * 124122679Sumeprefix_string(const struct prefix *prefix) 12578064Sume{ 12678064Sume static char buf[NI_MAXHOST + 20]; 12778064Sume char hbuf[NI_MAXHOST]; 12878064Sume 12995023Ssuz if (getnameinfo((const struct sockaddr *)&prefix->a, prefix->a.ss_len, 13095023Ssuz hbuf, sizeof(hbuf), NULL, 0, niflags)) 13178064Sume return NULL; 13278064Sume snprintf(buf, sizeof(buf), "%s/%d", hbuf, prefix->l); 13378064Sume return buf; 13478064Sume} 13578064Sume 13678064Sumeint 137122679Sumeprefix_match(const struct prefix *prefix, const struct sockaddr *sa) 13878064Sume{ 13978064Sume struct sockaddr_storage a, b; 14078064Sume char *pa, *pb; 14178064Sume int off, l; 14278064Sume 14378064Sume if (prefix->a.ss_family != sa->sa_family || 14478064Sume prefix->a.ss_len != sa->sa_len) 14578064Sume return 0; 14678064Sume 14778064Sume if (prefix->a.ss_len > sizeof(a) || sa->sa_len > sizeof(b)) 14878064Sume return 0; 14978064Sume 15078064Sume switch (prefix->a.ss_family) { 15178064Sume case AF_INET: 15278064Sume off = offsetof(struct sockaddr_in, sin_addr); 15378064Sume break; 15478064Sume case AF_INET6: 15578064Sume off = offsetof(struct sockaddr_in6, sin6_addr); 15678064Sume break; 15778064Sume default: 15878064Sume if (memcmp(&prefix->a, sa, prefix->a.ss_len) != 0) 15978064Sume return 0; 16078064Sume else 16178064Sume return 1; 16278064Sume } 16378064Sume 16478064Sume memcpy(&a, &prefix->a, prefix->a.ss_len); 16578064Sume memcpy(&b, sa, sa->sa_len); 16678064Sume l = prefix->l / 8 + (prefix->l % 8 ? 1 : 0); 16778064Sume 16878064Sume /* overrun check */ 16978064Sume if (off + l > a.ss_len) 17078064Sume return 0; 17178064Sume 17278064Sume pa = ((char *)&a) + off; 17378064Sume pb = ((char *)&b) + off; 17478064Sume if (prefix->l % 8) { 17578064Sume pa[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); 17678064Sume pb[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); 17778064Sume } 17878064Sume if (memcmp(pa, pb, l) != 0) 17978064Sume return 0; 18078064Sume else 18178064Sume return 1; 18278064Sume} 18378064Sume 18478064Sume/* 18578064Sume * prefix/prefixlen permit/deny prefix/prefixlen [srcaddr] 18678064Sume * 3ffe::/16 permit 10.0.0.0/8 10.1.1.1 18778064Sume */ 18878064Sumestatic struct config * 189122679Sumeconfig_load1(const char *line) 19078064Sume{ 19178064Sume struct config *conf; 19278064Sume char buf[BUFSIZ]; 19378064Sume char *p; 19478064Sume char *token[4]; 19578064Sume int i; 19678064Sume 19778064Sume if (strlen(line) + 1 > sizeof(buf)) 19878064Sume return NULL; 19978064Sume strlcpy(buf, line, sizeof(buf)); 20078064Sume 20178064Sume p = strchr(buf, '\n'); 20278064Sume if (!p) 20378064Sume return NULL; 20478064Sume *p = '\0'; 20578064Sume p = strchr(buf, '#'); 20678064Sume if (p) 20778064Sume *p = '\0'; 20878064Sume if (strlen(buf) == 0) 20978064Sume return NULL; 21078064Sume 21178064Sume p = buf; 21278064Sume memset(token, 0, sizeof(token)); 21378064Sume for (i = 0; i < sizeof(token) / sizeof(token[0]); i++) { 21478064Sume token[i] = strtok(p, "\t "); 21578064Sume p = NULL; 21678064Sume if (token[i] == NULL) 21778064Sume break; 21878064Sume } 21978064Sume /* extra tokens? */ 22078064Sume if (strtok(p, "\t ") != NULL) 22178064Sume return NULL; 22278064Sume /* insufficient tokens */ 22378064Sume switch (i) { 22478064Sume case 3: 22578064Sume case 4: 22678064Sume break; 22778064Sume default: 22878064Sume return NULL; 22978064Sume } 23078064Sume 23178064Sume conf = (struct config *)malloc(sizeof(*conf)); 23278064Sume if (conf == NULL) 23378064Sume return NULL; 23478064Sume memset(conf, 0, sizeof(*conf)); 23578064Sume 23678064Sume if (strcasecmp(token[1], "permit") == 0) 23778064Sume conf->permit = 1; 23878064Sume else if (strcasecmp(token[1], "deny") == 0) 23978064Sume conf->permit = 0; 24078064Sume else { 24178064Sume /* invalid keyword is considered as "deny" */ 24278064Sume conf->permit = 0; 24378064Sume } 24478064Sume 24578064Sume if (prefix_set(token[0], &conf->match, 1) < 0) 24678064Sume goto fail; 24778064Sume if (prefix_set(token[2], &conf->dest, 1) < 0) 24878064Sume goto fail; 24978064Sume if (token[3]) { 25078064Sume if (prefix_set(token[3], &conf->src, 0) < 0) 25178064Sume goto fail; 25278064Sume } 25378064Sume 25478064Sume return conf; 25578064Sume 25678064Sumefail: 25778064Sume free(conf); 25878064Sume return NULL; 25978064Sume} 26078064Sume 26178064Sumeint 262122679Sumeconfig_load(const char *configfile) 26378064Sume{ 26478064Sume FILE *fp; 26578064Sume char buf[BUFSIZ]; 26678064Sume struct config *conf, *p; 26778064Sume struct config sentinel; 26878064Sume 26978064Sume config_list = NULL; 27078064Sume 27178064Sume if (!configfile) 27278064Sume configfile = _PATH_PREFIX_CONF; 27378064Sume fp = fopen(configfile, "r"); 27478064Sume if (fp == NULL) 27578064Sume return -1; 27678064Sume 27778064Sume p = &sentinel; 278122679Sume sentinel.next = NULL; 27978064Sume while (fgets(buf, sizeof(buf), fp) != NULL) { 28078064Sume conf = config_load1(buf); 28178064Sume if (conf) { 28278064Sume p->next = conf; 28378064Sume p = p->next; 28478064Sume } 28578064Sume } 28678064Sume config_list = sentinel.next; 28778064Sume 28878064Sume fclose(fp); 28978064Sume return 0; 29078064Sume} 29178064Sume 29278064Sume#if 0 29378064Sumestatic void 294122679Sumeconfig_show1(const struct config *conf) 29578064Sume{ 29678064Sume const char *p; 29778064Sume 29878064Sume p = prefix_string(&conf->match); 29978064Sume printf("%s", p ? p : "?"); 30078064Sume 30178064Sume if (conf->permit) 30278064Sume printf(" permit"); 30378064Sume else 30478064Sume printf(" deny"); 30578064Sume 30678064Sume p = prefix_string(&conf->dest); 30778064Sume printf(" %s", p ? p : "?"); 30878064Sume 30978064Sume printf("\n"); 31078064Sume} 31178064Sume 31278064Sumestatic void 31378064Sumeconfig_show() 31478064Sume{ 31578064Sume struct config *conf; 31678064Sume 31778064Sume for (conf = config_list; conf; conf = conf->next) 31878064Sume config_show1(conf); 31978064Sume} 32078064Sume#endif 32178064Sume 32278064Sumeconst struct config * 323122679Sumeconfig_match(struct sockaddr *sa1, struct sockaddr *sa2) 32478064Sume{ 32578064Sume static struct config conf; 32678064Sume const struct config *p; 32778064Sume 32878064Sume if (sa1->sa_len > sizeof(conf.match.a) || 32978064Sume sa2->sa_len > sizeof(conf.dest.a)) 33078064Sume return NULL; 33178064Sume 33278064Sume memset(&conf, 0, sizeof(conf)); 33378064Sume if (!config_list) { 33478064Sume conf.permit = 1; 33578064Sume memcpy(&conf.match.a, sa1, sa1->sa_len); 33678064Sume memcpy(&conf.dest.a, sa2, sa2->sa_len); 33778064Sume return &conf; 33878064Sume } 33978064Sume 34078064Sume for (p = config_list; p; p = p->next) 34178064Sume if (prefix_match(&p->match, sa1) && prefix_match(&p->dest, sa2)) 34278064Sume return p; 34378064Sume 34478064Sume return NULL; 34578064Sume} 346