prefix.c revision 122679
1122679Sume/* $KAME: prefix.c,v 1.13 2003/09/02 22:50:17 itojun Exp $ */ 278064Sume/* $FreeBSD: head/usr.sbin/faithd/prefix.c 122679 2003-11-14 17:34:08Z ume $ */ 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 5078064Sumestatic int prefix_set __P((const char *, struct prefix *, int)); 5178064Sumestatic struct config *config_load1 __P((const char *)); 5278064Sume#if 0 5378064Sumestatic void config_show1 __P((const struct config *)); 5478064Sumestatic void config_show __P((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 char *a; 6778064Sume 6878064Sume p = strdup(s); 69122679Sume if (!p) 70122679Sume goto fail; 7178064Sume q = strchr(p, '/'); 7278064Sume if (q) { 7378064Sume if (!slash) 7478064Sume goto fail; 7578064Sume *q++ = '\0'; 7678064Sume } 7778064Sume 7878064Sume memset(&hints, 0, sizeof(hints)); 7978064Sume hints.ai_family = PF_UNSPEC; 8078064Sume hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 8178064Sume hints.ai_flags = AI_NUMERICHOST; 8278064Sume if (getaddrinfo(p, "0", &hints, &res)) 8378064Sume goto fail; 8478064Sume if (res->ai_next || res->ai_addrlen > sizeof(prefix->a)) 8578064Sume goto fail; 8678064Sume memcpy(&prefix->a, res->ai_addr, res->ai_addrlen); 8778064Sume 8878064Sume switch (prefix->a.ss_family) { 8978064Sume case AF_INET: 9078064Sume max = 32; 9178064Sume a = (char *)&((struct sockaddr_in *)&prefix->a)->sin_addr; 9278064Sume break; 9378064Sume case AF_INET6: 9478064Sume max = 128; 9578064Sume a = (char *)&((struct sockaddr_in6 *)&prefix->a)->sin6_addr; 9678064Sume break; 9778064Sume default: 9878064Sume a = NULL; 9978064Sume max = -1; 10078064Sume break; 10178064Sume } 10278064Sume 10378064Sume if (q) { 10478064Sume r = NULL; 10578064Sume prefix->l = (int)strtoul(q, &r, 10); 10678064Sume if (!*q || *r) 10778064Sume goto fail; 10878064Sume if (prefix->l < 0 || prefix->l > max) 10978064Sume goto fail; 11078064Sume } else 11178064Sume prefix->l = max; 11278064Sume 11378064Sume if (p) 11478064Sume free(p); 11578064Sume if (res) 11678064Sume freeaddrinfo(res); 11778064Sume return 0; 11878064Sume 11978064Sumefail: 12078064Sume if (p) 12178064Sume free(p); 12278064Sume if (res) 12378064Sume freeaddrinfo(res); 12478064Sume return -1; 12578064Sume} 12678064Sume 12778064Sumeconst char * 128122679Sumeprefix_string(const struct prefix *prefix) 12978064Sume{ 13078064Sume static char buf[NI_MAXHOST + 20]; 13178064Sume char hbuf[NI_MAXHOST]; 13278064Sume 13395023Ssuz if (getnameinfo((const struct sockaddr *)&prefix->a, prefix->a.ss_len, 13495023Ssuz hbuf, sizeof(hbuf), NULL, 0, niflags)) 13578064Sume return NULL; 13678064Sume snprintf(buf, sizeof(buf), "%s/%d", hbuf, prefix->l); 13778064Sume return buf; 13878064Sume} 13978064Sume 14078064Sumeint 141122679Sumeprefix_match(const struct prefix *prefix, const struct sockaddr *sa) 14278064Sume{ 14378064Sume struct sockaddr_storage a, b; 14478064Sume char *pa, *pb; 14578064Sume int off, l; 14678064Sume 14778064Sume if (prefix->a.ss_family != sa->sa_family || 14878064Sume prefix->a.ss_len != sa->sa_len) 14978064Sume return 0; 15078064Sume 15178064Sume if (prefix->a.ss_len > sizeof(a) || sa->sa_len > sizeof(b)) 15278064Sume return 0; 15378064Sume 15478064Sume switch (prefix->a.ss_family) { 15578064Sume case AF_INET: 15678064Sume off = offsetof(struct sockaddr_in, sin_addr); 15778064Sume break; 15878064Sume case AF_INET6: 15978064Sume off = offsetof(struct sockaddr_in6, sin6_addr); 16078064Sume break; 16178064Sume default: 16278064Sume if (memcmp(&prefix->a, sa, prefix->a.ss_len) != 0) 16378064Sume return 0; 16478064Sume else 16578064Sume return 1; 16678064Sume } 16778064Sume 16878064Sume memcpy(&a, &prefix->a, prefix->a.ss_len); 16978064Sume memcpy(&b, sa, sa->sa_len); 17078064Sume l = prefix->l / 8 + (prefix->l % 8 ? 1 : 0); 17178064Sume 17278064Sume /* overrun check */ 17378064Sume if (off + l > a.ss_len) 17478064Sume return 0; 17578064Sume 17678064Sume pa = ((char *)&a) + off; 17778064Sume pb = ((char *)&b) + off; 17878064Sume if (prefix->l % 8) { 17978064Sume pa[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); 18078064Sume pb[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); 18178064Sume } 18278064Sume if (memcmp(pa, pb, l) != 0) 18378064Sume return 0; 18478064Sume else 18578064Sume return 1; 18678064Sume} 18778064Sume 18878064Sume/* 18978064Sume * prefix/prefixlen permit/deny prefix/prefixlen [srcaddr] 19078064Sume * 3ffe::/16 permit 10.0.0.0/8 10.1.1.1 19178064Sume */ 19278064Sumestatic struct config * 193122679Sumeconfig_load1(const char *line) 19478064Sume{ 19578064Sume struct config *conf; 19678064Sume char buf[BUFSIZ]; 19778064Sume char *p; 19878064Sume char *token[4]; 19978064Sume int i; 20078064Sume 20178064Sume if (strlen(line) + 1 > sizeof(buf)) 20278064Sume return NULL; 20378064Sume strlcpy(buf, line, sizeof(buf)); 20478064Sume 20578064Sume p = strchr(buf, '\n'); 20678064Sume if (!p) 20778064Sume return NULL; 20878064Sume *p = '\0'; 20978064Sume p = strchr(buf, '#'); 21078064Sume if (p) 21178064Sume *p = '\0'; 21278064Sume if (strlen(buf) == 0) 21378064Sume return NULL; 21478064Sume 21578064Sume p = buf; 21678064Sume memset(token, 0, sizeof(token)); 21778064Sume for (i = 0; i < sizeof(token) / sizeof(token[0]); i++) { 21878064Sume token[i] = strtok(p, "\t "); 21978064Sume p = NULL; 22078064Sume if (token[i] == NULL) 22178064Sume break; 22278064Sume } 22378064Sume /* extra tokens? */ 22478064Sume if (strtok(p, "\t ") != NULL) 22578064Sume return NULL; 22678064Sume /* insufficient tokens */ 22778064Sume switch (i) { 22878064Sume case 3: 22978064Sume case 4: 23078064Sume break; 23178064Sume default: 23278064Sume return NULL; 23378064Sume } 23478064Sume 23578064Sume conf = (struct config *)malloc(sizeof(*conf)); 23678064Sume if (conf == NULL) 23778064Sume return NULL; 23878064Sume memset(conf, 0, sizeof(*conf)); 23978064Sume 24078064Sume if (strcasecmp(token[1], "permit") == 0) 24178064Sume conf->permit = 1; 24278064Sume else if (strcasecmp(token[1], "deny") == 0) 24378064Sume conf->permit = 0; 24478064Sume else { 24578064Sume /* invalid keyword is considered as "deny" */ 24678064Sume conf->permit = 0; 24778064Sume } 24878064Sume 24978064Sume if (prefix_set(token[0], &conf->match, 1) < 0) 25078064Sume goto fail; 25178064Sume if (prefix_set(token[2], &conf->dest, 1) < 0) 25278064Sume goto fail; 25378064Sume if (token[3]) { 25478064Sume if (prefix_set(token[3], &conf->src, 0) < 0) 25578064Sume goto fail; 25678064Sume } 25778064Sume 25878064Sume return conf; 25978064Sume 26078064Sumefail: 26178064Sume free(conf); 26278064Sume return NULL; 26378064Sume} 26478064Sume 26578064Sumeint 266122679Sumeconfig_load(const char *configfile) 26778064Sume{ 26878064Sume FILE *fp; 26978064Sume char buf[BUFSIZ]; 27078064Sume struct config *conf, *p; 27178064Sume struct config sentinel; 27278064Sume 27378064Sume config_list = NULL; 27478064Sume 27578064Sume if (!configfile) 27678064Sume configfile = _PATH_PREFIX_CONF; 27778064Sume fp = fopen(configfile, "r"); 27878064Sume if (fp == NULL) 27978064Sume return -1; 28078064Sume 28178064Sume p = &sentinel; 282122679Sume sentinel.next = NULL; 28378064Sume while (fgets(buf, sizeof(buf), fp) != NULL) { 28478064Sume conf = config_load1(buf); 28578064Sume if (conf) { 28678064Sume p->next = conf; 28778064Sume p = p->next; 28878064Sume } 28978064Sume } 29078064Sume config_list = sentinel.next; 29178064Sume 29278064Sume fclose(fp); 29378064Sume return 0; 29478064Sume} 29578064Sume 29678064Sume#if 0 29778064Sumestatic void 298122679Sumeconfig_show1(const struct config *conf) 29978064Sume{ 30078064Sume const char *p; 30178064Sume 30278064Sume p = prefix_string(&conf->match); 30378064Sume printf("%s", p ? p : "?"); 30478064Sume 30578064Sume if (conf->permit) 30678064Sume printf(" permit"); 30778064Sume else 30878064Sume printf(" deny"); 30978064Sume 31078064Sume p = prefix_string(&conf->dest); 31178064Sume printf(" %s", p ? p : "?"); 31278064Sume 31378064Sume printf("\n"); 31478064Sume} 31578064Sume 31678064Sumestatic void 31778064Sumeconfig_show() 31878064Sume{ 31978064Sume struct config *conf; 32078064Sume 32178064Sume for (conf = config_list; conf; conf = conf->next) 32278064Sume config_show1(conf); 32378064Sume} 32478064Sume#endif 32578064Sume 32678064Sumeconst struct config * 327122679Sumeconfig_match(struct sockaddr *sa1, struct sockaddr *sa2) 32878064Sume{ 32978064Sume static struct config conf; 33078064Sume const struct config *p; 33178064Sume 33278064Sume if (sa1->sa_len > sizeof(conf.match.a) || 33378064Sume sa2->sa_len > sizeof(conf.dest.a)) 33478064Sume return NULL; 33578064Sume 33678064Sume memset(&conf, 0, sizeof(conf)); 33778064Sume if (!config_list) { 33878064Sume conf.permit = 1; 33978064Sume memcpy(&conf.match.a, sa1, sa1->sa_len); 34078064Sume memcpy(&conf.dest.a, sa2, sa2->sa_len); 34178064Sume return &conf; 34278064Sume } 34378064Sume 34478064Sume for (p = config_list; p; p = p->next) 34578064Sume if (prefix_match(&p->match, sa1) && prefix_match(&p->dest, sa2)) 34678064Sume return p; 34778064Sume 34878064Sume return NULL; 34978064Sume} 350