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