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