prefix.c revision 1.3 1 /* $NetBSD: prefix.c,v 1.3 2001/11/21 06:52:35 itojun Exp $ */
2 /* $KAME: prefix.c,v 1.9 2001/07/02 14:36:49 itojun Exp $ */
3
4 /*
5 * Copyright (C) 2000 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <stdio.h>
37 #include <netdb.h>
38 #include <string.h>
39 #include <stddef.h>
40 #include <stdlib.h>
41 #include <limits.h>
42
43 #ifndef offsetof
44 #define offsetof(type, member) ((size_t)(u_long)(&((type *)0)->member))
45 #endif
46
47 #include "faithd.h"
48 #include "prefix.h"
49
50 static int prefix_set __P((const char *, struct prefix *, int));
51 static struct config *config_load1 __P((const char *));
52 #if 0
53 static void config_show1 __P((const struct config *));
54 static void config_show __P((void));
55 #endif
56
57 struct config *config_list = NULL;
58 #ifdef NI_WITHSCOPEID
59 const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
60 #else
61 const int niflags = NI_NUMERICHOST;
62 #endif
63
64 static int
65 prefix_set(s, prefix, slash)
66 const char *s;
67 struct prefix *prefix;
68 int slash;
69 {
70 char *p = NULL, *q, *r;
71 struct addrinfo hints, *res = NULL;
72 int max;
73 char *a;
74
75 p = strdup(s);
76 if (!p)
77 goto fail;
78 q = strchr(p, '/');
79 if (q) {
80 if (!slash)
81 goto fail;
82 *q++ = '\0';
83 }
84
85 memset(&hints, 0, sizeof(hints));
86 hints.ai_family = PF_UNSPEC;
87 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
88 hints.ai_flags = AI_NUMERICHOST;
89 if (getaddrinfo(p, "0", &hints, &res))
90 goto fail;
91 if (res->ai_next || res->ai_addrlen > sizeof(prefix->a))
92 goto fail;
93 memcpy(&prefix->a, res->ai_addr, res->ai_addrlen);
94
95 switch (prefix->a.ss_family) {
96 case AF_INET:
97 max = 32;
98 a = (char *)&((struct sockaddr_in *)&prefix->a)->sin_addr;
99 break;
100 case AF_INET6:
101 max = 128;
102 a = (char *)&((struct sockaddr_in6 *)&prefix->a)->sin6_addr;
103 break;
104 default:
105 a = NULL;
106 max = -1;
107 break;
108 }
109
110 if (q) {
111 r = NULL;
112 prefix->l = (int)strtoul(q, &r, 10);
113 if (!*q || *r)
114 goto fail;
115 if (prefix->l < 0 || prefix->l > max)
116 goto fail;
117 } else
118 prefix->l = max;
119
120 if (p)
121 free(p);
122 if (res)
123 freeaddrinfo(res);
124 return 0;
125
126 fail:
127 if (p)
128 free(p);
129 if (res)
130 freeaddrinfo(res);
131 return -1;
132 }
133
134 const char *
135 prefix_string(prefix)
136 const struct prefix *prefix;
137 {
138 static char buf[NI_MAXHOST + 20];
139 char hbuf[NI_MAXHOST];
140
141 if (getnameinfo((const struct sockaddr *)&prefix->a, prefix->a.ss_len,
142 hbuf, sizeof(hbuf), NULL, 0, niflags))
143 return NULL;
144 snprintf(buf, sizeof(buf), "%s/%d", hbuf, prefix->l);
145 return buf;
146 }
147
148 int
149 prefix_match(prefix, sa)
150 const struct prefix *prefix;
151 const struct sockaddr *sa;
152 {
153 struct sockaddr_storage a, b;
154 char *pa, *pb;
155 int off, l;
156
157 if (prefix->a.ss_family != sa->sa_family ||
158 prefix->a.ss_len != sa->sa_len)
159 return 0;
160
161 if (prefix->a.ss_len > sizeof(a) || sa->sa_len > sizeof(b))
162 return 0;
163
164 switch (prefix->a.ss_family) {
165 case AF_INET:
166 off = offsetof(struct sockaddr_in, sin_addr);
167 break;
168 case AF_INET6:
169 off = offsetof(struct sockaddr_in6, sin6_addr);
170 break;
171 default:
172 if (memcmp(&prefix->a, sa, prefix->a.ss_len) != 0)
173 return 0;
174 else
175 return 1;
176 }
177
178 memcpy(&a, &prefix->a, prefix->a.ss_len);
179 memcpy(&b, sa, sa->sa_len);
180 l = prefix->l / 8 + (prefix->l % 8 ? 1 : 0);
181
182 /* overrun check */
183 if (off + l > a.ss_len)
184 return 0;
185
186 pa = ((char *)&a) + off;
187 pb = ((char *)&b) + off;
188 if (prefix->l % 8) {
189 pa[prefix->l / 8] &= 0xff00 >> (prefix->l % 8);
190 pb[prefix->l / 8] &= 0xff00 >> (prefix->l % 8);
191 }
192 if (memcmp(pa, pb, l) != 0)
193 return 0;
194 else
195 return 1;
196 }
197
198 /*
199 * prefix/prefixlen permit/deny prefix/prefixlen [srcaddr]
200 * 3ffe::/16 permit 10.0.0.0/8 10.1.1.1
201 */
202 static struct config *
203 config_load1(line)
204 const char *line;
205 {
206 struct config *conf;
207 char buf[BUFSIZ];
208 char *p;
209 char *token[4];
210 int i;
211
212 if (strlen(line) + 1 > sizeof(buf))
213 return NULL;
214 strlcpy(buf, line, sizeof(buf));
215
216 p = strchr(buf, '\n');
217 if (!p)
218 return NULL;
219 *p = '\0';
220 p = strchr(buf, '#');
221 if (p)
222 *p = '\0';
223 if (strlen(buf) == 0)
224 return NULL;
225
226 p = buf;
227 memset(token, 0, sizeof(token));
228 for (i = 0; i < sizeof(token) / sizeof(token[0]); i++) {
229 token[i] = strtok(p, "\t ");
230 p = NULL;
231 if (token[i] == NULL)
232 break;
233 }
234 /* extra tokens? */
235 if (strtok(p, "\t ") != NULL)
236 return NULL;
237 /* insufficient tokens */
238 switch (i) {
239 case 3:
240 case 4:
241 break;
242 default:
243 return NULL;
244 }
245
246 conf = (struct config *)malloc(sizeof(*conf));
247 if (conf == NULL)
248 return NULL;
249 memset(conf, 0, sizeof(*conf));
250
251 if (strcasecmp(token[1], "permit") == 0)
252 conf->permit = 1;
253 else if (strcasecmp(token[1], "deny") == 0)
254 conf->permit = 0;
255 else {
256 /* invalid keyword is considered as "deny" */
257 conf->permit = 0;
258 }
259
260 if (prefix_set(token[0], &conf->match, 1) < 0)
261 goto fail;
262 if (prefix_set(token[2], &conf->dest, 1) < 0)
263 goto fail;
264 if (token[3]) {
265 if (prefix_set(token[3], &conf->src, 0) < 0)
266 goto fail;
267 }
268
269 return conf;
270
271 fail:
272 free(conf);
273 return NULL;
274 }
275
276 int
277 config_load(configfile)
278 const char *configfile;
279 {
280 FILE *fp;
281 char buf[BUFSIZ];
282 struct config *conf, *p;
283 struct config sentinel;
284
285 config_list = NULL;
286
287 if (!configfile)
288 configfile = _PATH_PREFIX_CONF;
289 fp = fopen(configfile, "r");
290 if (fp == NULL)
291 return -1;
292
293 p = &sentinel;
294 while (fgets(buf, sizeof(buf), fp) != NULL) {
295 conf = config_load1(buf);
296 if (conf) {
297 p->next = conf;
298 p = p->next;
299 }
300 }
301 config_list = sentinel.next;
302
303 fclose(fp);
304 return 0;
305 }
306
307 #if 0
308 static void
309 config_show1(conf)
310 const struct config *conf;
311 {
312 const char *p;
313
314 p = prefix_string(&conf->match);
315 printf("%s", p ? p : "?");
316
317 if (conf->permit)
318 printf(" permit");
319 else
320 printf(" deny");
321
322 p = prefix_string(&conf->dest);
323 printf(" %s", p ? p : "?");
324
325 printf("\n");
326 }
327
328 static void
329 config_show()
330 {
331 struct config *conf;
332
333 for (conf = config_list; conf; conf = conf->next)
334 config_show1(conf);
335 }
336 #endif
337
338 const struct config *
339 config_match(sa1, sa2)
340 struct sockaddr *sa1, *sa2;
341 {
342 static struct config conf;
343 const struct config *p;
344
345 if (sa1->sa_len > sizeof(conf.match.a) ||
346 sa2->sa_len > sizeof(conf.dest.a))
347 return NULL;
348
349 memset(&conf, 0, sizeof(conf));
350 if (!config_list) {
351 conf.permit = 1;
352 memcpy(&conf.match.a, sa1, sa1->sa_len);
353 memcpy(&conf.dest.a, sa2, sa2->sa_len);
354 return &conf;
355 }
356
357 for (p = config_list; p; p = p->next)
358 if (prefix_match(&p->match, sa1) && prefix_match(&p->dest, sa2))
359 return p;
360
361 return NULL;
362 }
363