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