prefix.c revision 78064
180708Sjake/* $KAME: prefix.c,v 1.8 2000/11/24 06:16:56 itojun Exp $ */ 282895Sjake/* $FreeBSD: head/usr.sbin/faithd/prefix.c 78064 2001-06-11 12:39:29Z ume $ */ 380708Sjake 480708Sjake/* 580708Sjake * Copyright (C) 2000 WIDE Project. 680708Sjake * All rights reserved. 780708Sjake * 880708Sjake * Redistribution and use in source and binary forms, with or without 980708Sjake * modification, are permitted provided that the following conditions 1080708Sjake * are met: 1180708Sjake * 1. Redistributions of source code must retain the above copyright 1280708Sjake * notice, this list of conditions and the following disclaimer. 1380708Sjake * 2. Redistributions in binary form must reproduce the above copyright 1480708Sjake * notice, this list of conditions and the following disclaimer in the 1581334Sobrien * documentation and/or other materials provided with the distribution. 1680708Sjake * 3. Neither the name of the project nor the names of its contributors 1780708Sjake * may be used to endorse or promote products derived from this software 1881334Sobrien * without specific prior written permission. 1980708Sjake * 2080708Sjake * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2180708Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2280708Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2380708Sjake * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2480708Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2580708Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2680708Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2782895Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2880708Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2980708Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3080708Sjake * SUCH DAMAGE. 3180709Sjake */ 3280709Sjake 3380709Sjake#include <sys/types.h> 3480709Sjake#include <sys/socket.h> 3580709Sjake#include <netinet/in.h> 36225890Smarius#include <stdio.h> 37225890Smarius#include <netdb.h> 38225890Smarius#include <string.h> 39225890Smarius#include <stddef.h> 4088617Sjake#include <stdlib.h> 4188617Sjake#include <limits.h> 4288617Sjake 4388617Sjake#ifndef offsetof 4488617Sjake#define offsetof(type, member) ((size_t)(u_long)(&((type *)0)->member)) 4588617Sjake#endif 4688617Sjake 4780708Sjake#include "faithd.h" 4880709Sjake#include "prefix.h" 4980709Sjake 5080709Sjakestatic int prefix_set __P((const char *, struct prefix *, int)); 5180709Sjakestatic struct config *config_load1 __P((const char *)); 5280709Sjake#if 0 5380709Sjakestatic void config_show1 __P((const struct config *)); 5480709Sjakestatic void config_show __P((void)); 5580709Sjake#endif 5680709Sjake 5780709Sjakestruct config *config_list = NULL; 5880709Sjake#ifdef NI_WITHSCOPEID 5980709Sjakeconst int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; 6080709Sjake#else 6180709Sjakeconst int niflags = NI_NUMERICHOST; 6280709Sjake#endif 6380709Sjake 6480709Sjakestatic int 6580709Sjakeprefix_set(s, prefix, slash) 6680709Sjake const char *s; 6780709Sjake struct prefix *prefix; 6880709Sjake int slash; 6980709Sjake{ 7080709Sjake char *p, *q, *r; 7180709Sjake struct addrinfo hints, *res = NULL; 7280709Sjake int max; 7380709Sjake char *a; 7480709Sjake 75108153Sjake p = strdup(s); 7680709Sjake q = strchr(p, '/'); 77225889Smarius if (q) { 78225889Smarius if (!slash) 79225889Smarius goto fail; 80225889Smarius *q++ = '\0'; 81228222Smarius } 82225889Smarius 83225889Smarius memset(&hints, 0, sizeof(hints)); 84225889Smarius hints.ai_family = PF_UNSPEC; 8580709Sjake hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 86225889Smarius hints.ai_flags = AI_NUMERICHOST; 8780708Sjake if (getaddrinfo(p, "0", &hints, &res)) 8880708Sjake goto fail; 89129568Smarius if (res->ai_next || res->ai_addrlen > sizeof(prefix->a)) 9080708Sjake goto fail; 91225890Smarius memcpy(&prefix->a, res->ai_addr, res->ai_addrlen); 92225890Smarius 9380708Sjake switch (prefix->a.ss_family) { 9480709Sjake case AF_INET: 95225890Smarius max = 32; 9680709Sjake a = (char *)&((struct sockaddr_in *)&prefix->a)->sin_addr; 9780709Sjake break; 9880709Sjake case AF_INET6: 99225890Smarius max = 128; 100241374Sattilio a = (char *)&((struct sockaddr_in6 *)&prefix->a)->sin6_addr; 10180709Sjake break; 10280708Sjake default: 10380708Sjake a = NULL; 10480709Sjake max = -1; 10580709Sjake break; 10680709Sjake } 107225890Smarius 10880709Sjake if (q) { 10980708Sjake r = NULL; 11080708Sjake prefix->l = (int)strtoul(q, &r, 10); 111108153Sjake if (!*q || *r) 11280709Sjake goto fail; 113225890Smarius if (prefix->l < 0 || prefix->l > max) 114225890Smarius goto fail; 115225890Smarius } else 11680709Sjake prefix->l = max; 11780709Sjake 11880708Sjake if (p) 119108153Sjake free(p); 120108153Sjake if (res) 12180708Sjake freeaddrinfo(res); 122108153Sjake return 0; 123108153Sjake 124225890Smariusfail: 125241374Sattilio if (p) 126108153Sjake free(p); 127108153Sjake if (res) 12880708Sjake freeaddrinfo(res); 129108153Sjake return -1; 130108153Sjake} 13180709Sjake 132225890Smariusconst char * 133108153Sjakeprefix_string(prefix) 134108153Sjake const struct prefix *prefix; 13580708Sjake{ 136253994Smarius static char buf[NI_MAXHOST + 20]; 13780709Sjake char hbuf[NI_MAXHOST]; 138251783Sed 139241374Sattilio if (getnameinfo((struct sockaddr *)&prefix->a, prefix->a.ss_len, hbuf, 14080709Sjake sizeof(hbuf), NULL, 0, niflags)) 14180709Sjake return NULL; 14280708Sjake snprintf(buf, sizeof(buf), "%s/%d", hbuf, prefix->l); 143253994Smarius return buf; 14480709Sjake} 145225890Smarius 146225890Smariusint 14780709Sjakeprefix_match(prefix, sa) 14880709Sjake const struct prefix *prefix; 14980709Sjake const struct sockaddr *sa; 15080709Sjake{ 15180709Sjake struct sockaddr_storage a, b; 15280708Sjake char *pa, *pb; 153253994Smarius int off, l; 15480709Sjake 155225890Smarius if (prefix->a.ss_family != sa->sa_family || 156225890Smarius prefix->a.ss_len != sa->sa_len) 15780709Sjake return 0; 15880709Sjake 15980709Sjake if (prefix->a.ss_len > sizeof(a) || sa->sa_len > sizeof(b)) 16080709Sjake return 0; 16180708Sjake 162253994Smarius switch (prefix->a.ss_family) { 163253994Smarius case AF_INET: 164253994Smarius off = offsetof(struct sockaddr_in, sin_addr); 165253994Smarius break; 166253994Smarius case AF_INET6: 167253994Smarius off = offsetof(struct sockaddr_in6, sin6_addr); 168253994Smarius break; 169253994Smarius default: 170253994Smarius if (memcmp(&prefix->a, sa, prefix->a.ss_len) != 0) 171253994Smarius return 0; 17280709Sjake else 17380709Sjake return 1; 174108153Sjake } 17580709Sjake 17680709Sjake memcpy(&a, &prefix->a, prefix->a.ss_len); 177225890Smarius memcpy(&b, sa, sa->sa_len); 17880709Sjake l = prefix->l / 8 + (prefix->l % 8 ? 1 : 0); 179108153Sjake 18080709Sjake /* overrun check */ 18180709Sjake if (off + l > a.ss_len) 182225890Smarius return 0; 18380709Sjake 184108153Sjake pa = ((char *)&a) + off; 18580709Sjake pb = ((char *)&b) + off; 18680709Sjake if (prefix->l % 8) { 187225890Smarius pa[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); 18880709Sjake pb[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); 18980709Sjake } 190108153Sjake if (memcmp(pa, pb, l) != 0) 19180709Sjake return 0; 19280709Sjake else 193225890Smarius return 1; 19480709Sjake} 195108153Sjake 19680709Sjake/* 19780709Sjake * prefix/prefixlen permit/deny prefix/prefixlen [srcaddr] 198225890Smarius * 3ffe::/16 permit 10.0.0.0/8 10.1.1.1 19980709Sjake */ 200108153Sjakestatic struct config * 20180709Sjakeconfig_load1(line) 20280709Sjake const char *line; 203225890Smarius{ 20480709Sjake struct config *conf; 20580709Sjake char buf[BUFSIZ]; 20680709Sjake char *p; 20780709Sjake char *token[4]; 20880709Sjake int i; 209225890Smarius 21080709Sjake if (strlen(line) + 1 > sizeof(buf)) 21180709Sjake return NULL; 21280709Sjake strlcpy(buf, line, sizeof(buf)); 21380709Sjake 214225890Smarius p = strchr(buf, '\n'); 21580709Sjake if (!p) 21680709Sjake return NULL; 21780709Sjake *p = '\0'; 21880709Sjake p = strchr(buf, '#'); 219225890Smarius if (p) 22080709Sjake *p = '\0'; 22180709Sjake if (strlen(buf) == 0) 22280709Sjake return NULL; 22382895Sjake 22482895Sjake p = buf; 225225890Smarius memset(token, 0, sizeof(token)); 22682895Sjake for (i = 0; i < sizeof(token) / sizeof(token[0]); i++) { 22782895Sjake token[i] = strtok(p, "\t "); 22880709Sjake p = NULL; 22980709Sjake if (token[i] == NULL) 230225890Smarius break; 23180709Sjake } 23280709Sjake /* extra tokens? */ 23380709Sjake if (strtok(p, "\t ") != NULL) 23480709Sjake return NULL; 23580709Sjake /* insufficient tokens */ 236253994Smarius switch (i) { 23780709Sjake case 3: 23880709Sjake case 4: 239108153Sjake break; 24080709Sjake default: 24180709Sjake return NULL; 242225890Smarius } 24380709Sjake 244108153Sjake conf = (struct config *)malloc(sizeof(*conf)); 24580709Sjake if (conf == NULL) 24680709Sjake return NULL; 247225890Smarius memset(conf, 0, sizeof(*conf)); 24880709Sjake 249108153Sjake if (strcasecmp(token[1], "permit") == 0) 25080709Sjake conf->permit = 1; 25180709Sjake else if (strcasecmp(token[1], "deny") == 0) 252225890Smarius conf->permit = 0; 25380709Sjake else { 25480709Sjake /* invalid keyword is considered as "deny" */ 255108153Sjake conf->permit = 0; 25680709Sjake } 25780709Sjake 258225890Smarius if (prefix_set(token[0], &conf->match, 1) < 0) 25980709Sjake goto fail; 260108153Sjake if (prefix_set(token[2], &conf->dest, 1) < 0) 26180709Sjake goto fail; 26280709Sjake if (token[3]) { 263225890Smarius if (prefix_set(token[3], &conf->src, 0) < 0) 26480709Sjake goto fail; 265108153Sjake } 26680709Sjake 26780709Sjake return conf; 268225890Smarius 26980709Sjakefail: 27080709Sjake free(conf); 27180709Sjake return NULL; 272253994Smarius} 273253994Smarius 274253994Smariusint 275253994Smariusconfig_load(configfile) 276253994Smarius const char *configfile; 27780709Sjake{ 27880709Sjake FILE *fp; 279253994Smarius char buf[BUFSIZ]; 28080709Sjake struct config *conf, *p; 28180708Sjake struct config sentinel; 282285283Skib 283285283Skib config_list = NULL; 284285283Skib 285285283Skib if (!configfile) 286285283Skib configfile = _PATH_PREFIX_CONF; 287285283Skib fp = fopen(configfile, "r"); 288285283Skib if (fp == NULL) 289285283Skib return -1; 290285283Skib 291285283Skib p = &sentinel; 292285283Skib while (fgets(buf, sizeof(buf), fp) != NULL) { 293285283Skib conf = config_load1(buf); 294285283Skib if (conf) { 295285283Skib p->next = conf; 296285283Skib p = p->next; 297285283Skib } 298285283Skib } 299285283Skib config_list = sentinel.next; 300285283Skib 301285283Skib fclose(fp); 302285283Skib return 0; 303285283Skib} 304285283Skib 305285283Skib#if 0 306285283Skibstatic void 307285283Skibconfig_show1(conf) 308285283Skib const struct config *conf; 309285283Skib{ 310285283Skib const char *p; 311129569Smarius 312129569Smarius p = prefix_string(&conf->match); 31380708Sjake printf("%s", p ? p : "?"); 314129569Smarius 315129569Smarius if (conf->permit) 31680708Sjake printf(" permit"); 317148067Sjhb else 31880708Sjake printf(" deny"); 319150627Sjhb 320150627Sjhb p = prefix_string(&conf->dest); 321177373Spjd printf(" %s", p ? p : "?"); 322294539Sjhb 323150627Sjhb printf("\n"); 32480709Sjake} 32580709Sjake 32680709Sjakestatic void 32780709Sjakeconfig_show() 32880709Sjake{ 32980709Sjake struct config *conf; 33080709Sjake 331253994Smarius for (conf = config_list; conf; conf = conf->next) 332253994Smarius config_show1(conf); 333253994Smarius} 334253994Smarius#endif 335253994Smarius 33680708Sjakeconst struct config * 33780708Sjakeconfig_match(sa1, sa2) 338 struct sockaddr *sa1, *sa2; 339{ 340 static struct config conf; 341 const struct config *p; 342 343 if (sa1->sa_len > sizeof(conf.match.a) || 344 sa2->sa_len > sizeof(conf.dest.a)) 345 return NULL; 346 347 memset(&conf, 0, sizeof(conf)); 348 if (!config_list) { 349 conf.permit = 1; 350 memcpy(&conf.match.a, sa1, sa1->sa_len); 351 memcpy(&conf.dest.a, sa2, sa2->sa_len); 352 return &conf; 353 } 354 355 for (p = config_list; p; p = p->next) 356 if (prefix_match(&p->match, sa1) && prefix_match(&p->dest, sa2)) 357 return p; 358 359 return NULL; 360} 361