prefix.c revision 1.4 1 /* $NetBSD: prefix.c,v 1.4 2002/06/07 00:20:45 itojun Exp $ */
2 /* $KAME: prefix.c,v 1.11 2001/11/13 12:38:45 jinmei 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 const int niflags = NI_NUMERICHOST;
59
60 static int
61 prefix_set(s, prefix, slash)
62 const char *s;
63 struct prefix *prefix;
64 int slash;
65 {
66 char *p = NULL, *q, *r;
67 struct addrinfo hints, *res = NULL;
68 int max;
69 char *a;
70
71 p = strdup(s);
72 if (!p)
73 goto fail;
74 q = strchr(p, '/');
75 if (q) {
76 if (!slash)
77 goto fail;
78 *q++ = '\0';
79 }
80
81 memset(&hints, 0, sizeof(hints));
82 hints.ai_family = PF_UNSPEC;
83 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
84 hints.ai_flags = AI_NUMERICHOST;
85 if (getaddrinfo(p, "0", &hints, &res))
86 goto fail;
87 if (res->ai_next || res->ai_addrlen > sizeof(prefix->a))
88 goto fail;
89 memcpy(&prefix->a, res->ai_addr, res->ai_addrlen);
90
91 switch (prefix->a.ss_family) {
92 case AF_INET:
93 max = 32;
94 a = (char *)&((struct sockaddr_in *)&prefix->a)->sin_addr;
95 break;
96 case AF_INET6:
97 max = 128;
98 a = (char *)&((struct sockaddr_in6 *)&prefix->a)->sin6_addr;
99 break;
100 default:
101 a = NULL;
102 max = -1;
103 break;
104 }
105
106 if (q) {
107 r = NULL;
108 prefix->l = (int)strtoul(q, &r, 10);
109 if (!*q || *r)
110 goto fail;
111 if (prefix->l < 0 || prefix->l > max)
112 goto fail;
113 } else
114 prefix->l = max;
115
116 if (p)
117 free(p);
118 if (res)
119 freeaddrinfo(res);
120 return 0;
121
122 fail:
123 if (p)
124 free(p);
125 if (res)
126 freeaddrinfo(res);
127 return -1;
128 }
129
130 const char *
131 prefix_string(prefix)
132 const struct prefix *prefix;
133 {
134 static char buf[NI_MAXHOST + 20];
135 char hbuf[NI_MAXHOST];
136
137 if (getnameinfo((const struct sockaddr *)&prefix->a, prefix->a.ss_len,
138 hbuf, sizeof(hbuf), NULL, 0, niflags))
139 return NULL;
140 snprintf(buf, sizeof(buf), "%s/%d", hbuf, prefix->l);
141 return buf;
142 }
143
144 int
145 prefix_match(prefix, sa)
146 const struct prefix *prefix;
147 const struct sockaddr *sa;
148 {
149 struct sockaddr_storage a, b;
150 char *pa, *pb;
151 int off, l;
152
153 if (prefix->a.ss_family != sa->sa_family ||
154 prefix->a.ss_len != sa->sa_len)
155 return 0;
156
157 if (prefix->a.ss_len > sizeof(a) || sa->sa_len > sizeof(b))
158 return 0;
159
160 switch (prefix->a.ss_family) {
161 case AF_INET:
162 off = offsetof(struct sockaddr_in, sin_addr);
163 break;
164 case AF_INET6:
165 off = offsetof(struct sockaddr_in6, sin6_addr);
166 break;
167 default:
168 if (memcmp(&prefix->a, sa, prefix->a.ss_len) != 0)
169 return 0;
170 else
171 return 1;
172 }
173
174 memcpy(&a, &prefix->a, prefix->a.ss_len);
175 memcpy(&b, sa, sa->sa_len);
176 l = prefix->l / 8 + (prefix->l % 8 ? 1 : 0);
177
178 /* overrun check */
179 if (off + l > a.ss_len)
180 return 0;
181
182 pa = ((char *)&a) + off;
183 pb = ((char *)&b) + off;
184 if (prefix->l % 8) {
185 pa[prefix->l / 8] &= 0xff00 >> (prefix->l % 8);
186 pb[prefix->l / 8] &= 0xff00 >> (prefix->l % 8);
187 }
188 if (memcmp(pa, pb, l) != 0)
189 return 0;
190 else
191 return 1;
192 }
193
194 /*
195 * prefix/prefixlen permit/deny prefix/prefixlen [srcaddr]
196 * 3ffe::/16 permit 10.0.0.0/8 10.1.1.1
197 */
198 static struct config *
199 config_load1(line)
200 const char *line;
201 {
202 struct config *conf;
203 char buf[BUFSIZ];
204 char *p;
205 char *token[4];
206 int i;
207
208 if (strlen(line) + 1 > sizeof(buf))
209 return NULL;
210 strlcpy(buf, line, sizeof(buf));
211
212 p = strchr(buf, '\n');
213 if (!p)
214 return NULL;
215 *p = '\0';
216 p = strchr(buf, '#');
217 if (p)
218 *p = '\0';
219 if (strlen(buf) == 0)
220 return NULL;
221
222 p = buf;
223 memset(token, 0, sizeof(token));
224 for (i = 0; i < sizeof(token) / sizeof(token[0]); i++) {
225 token[i] = strtok(p, "\t ");
226 p = NULL;
227 if (token[i] == NULL)
228 break;
229 }
230 /* extra tokens? */
231 if (strtok(p, "\t ") != NULL)
232 return NULL;
233 /* insufficient tokens */
234 switch (i) {
235 case 3:
236 case 4:
237 break;
238 default:
239 return NULL;
240 }
241
242 conf = (struct config *)malloc(sizeof(*conf));
243 if (conf == NULL)
244 return NULL;
245 memset(conf, 0, sizeof(*conf));
246
247 if (strcasecmp(token[1], "permit") == 0)
248 conf->permit = 1;
249 else if (strcasecmp(token[1], "deny") == 0)
250 conf->permit = 0;
251 else {
252 /* invalid keyword is considered as "deny" */
253 conf->permit = 0;
254 }
255
256 if (prefix_set(token[0], &conf->match, 1) < 0)
257 goto fail;
258 if (prefix_set(token[2], &conf->dest, 1) < 0)
259 goto fail;
260 if (token[3]) {
261 if (prefix_set(token[3], &conf->src, 0) < 0)
262 goto fail;
263 }
264
265 return conf;
266
267 fail:
268 free(conf);
269 return NULL;
270 }
271
272 int
273 config_load(configfile)
274 const char *configfile;
275 {
276 FILE *fp;
277 char buf[BUFSIZ];
278 struct config *conf, *p;
279 struct config sentinel;
280
281 config_list = NULL;
282
283 if (!configfile)
284 configfile = _PATH_PREFIX_CONF;
285 fp = fopen(configfile, "r");
286 if (fp == NULL)
287 return -1;
288
289 p = &sentinel;
290 while (fgets(buf, sizeof(buf), fp) != NULL) {
291 conf = config_load1(buf);
292 if (conf) {
293 p->next = conf;
294 p = p->next;
295 }
296 }
297 config_list = sentinel.next;
298
299 fclose(fp);
300 return 0;
301 }
302
303 #if 0
304 static void
305 config_show1(conf)
306 const struct config *conf;
307 {
308 const char *p;
309
310 p = prefix_string(&conf->match);
311 printf("%s", p ? p : "?");
312
313 if (conf->permit)
314 printf(" permit");
315 else
316 printf(" deny");
317
318 p = prefix_string(&conf->dest);
319 printf(" %s", p ? p : "?");
320
321 printf("\n");
322 }
323
324 static void
325 config_show()
326 {
327 struct config *conf;
328
329 for (conf = config_list; conf; conf = conf->next)
330 config_show1(conf);
331 }
332 #endif
333
334 const struct config *
335 config_match(sa1, sa2)
336 struct sockaddr *sa1, *sa2;
337 {
338 static struct config conf;
339 const struct config *p;
340
341 if (sa1->sa_len > sizeof(conf.match.a) ||
342 sa2->sa_len > sizeof(conf.dest.a))
343 return NULL;
344
345 memset(&conf, 0, sizeof(conf));
346 if (!config_list) {
347 conf.permit = 1;
348 memcpy(&conf.match.a, sa1, sa1->sa_len);
349 memcpy(&conf.dest.a, sa2, sa2->sa_len);
350 return &conf;
351 }
352
353 for (p = config_list; p; p = p->next)
354 if (prefix_match(&p->match, sa1) && prefix_match(&p->dest, sa2))
355 return p;
356
357 return NULL;
358 }
359