conf.c revision 1.1 1 1.1 christos /* $NetBSD: conf.c,v 1.1 2020/06/15 01:52:53 christos Exp $ */
2 1.1 christos
3 1.1 christos /*-
4 1.1 christos * Copyright (c) 2015 The NetBSD Foundation, Inc.
5 1.1 christos * All rights reserved.
6 1.1 christos *
7 1.1 christos * This code is derived from software contributed to The NetBSD Foundation
8 1.1 christos * by Christos Zoulas.
9 1.1 christos *
10 1.1 christos * Redistribution and use in source and binary forms, with or without
11 1.1 christos * modification, are permitted provided that the following conditions
12 1.1 christos * are met:
13 1.1 christos * 1. Redistributions of source code must retain the above copyright
14 1.1 christos * notice, this list of conditions and the following disclaimer.
15 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 christos * notice, this list of conditions and the following disclaimer in the
17 1.1 christos * documentation and/or other materials provided with the distribution.
18 1.1 christos *
19 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 christos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 christos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 christos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 christos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 christos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 christos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 christos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 christos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 christos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 christos * POSSIBILITY OF SUCH DAMAGE.
30 1.1 christos */
31 1.1 christos #ifdef HAVE_CONFIG_H
32 1.1 christos #include "config.h"
33 1.1 christos #endif
34 1.1 christos
35 1.1 christos #include <sys/cdefs.h>
36 1.1 christos __RCSID("$NetBSD: conf.c,v 1.1 2020/06/15 01:52:53 christos Exp $");
37 1.1 christos
38 1.1 christos #include <stdio.h>
39 1.1 christos #ifdef HAVE_LIBUTIL_H
40 1.1 christos #include <libutil.h>
41 1.1 christos #endif
42 1.1 christos #ifdef HAVE_UTIL_H
43 1.1 christos #include <util.h>
44 1.1 christos #endif
45 1.1 christos #include <string.h>
46 1.1 christos #include <ctype.h>
47 1.1 christos #include <inttypes.h>
48 1.1 christos #include <netdb.h>
49 1.1 christos #include <unistd.h>
50 1.1 christos #include <pwd.h>
51 1.1 christos #include <syslog.h>
52 1.1 christos #include <errno.h>
53 1.1 christos #include <stdlib.h>
54 1.1 christos #include <limits.h>
55 1.1 christos #include <ifaddrs.h>
56 1.1 christos #include <arpa/inet.h>
57 1.1 christos #include <netinet/in.h>
58 1.1 christos #include <net/if.h>
59 1.1 christos #include <net/route.h>
60 1.1 christos #include <sys/socket.h>
61 1.1 christos
62 1.1 christos #include "bl.h"
63 1.1 christos #include "internal.h"
64 1.1 christos #include "support.h"
65 1.1 christos #include "conf.h"
66 1.1 christos
67 1.1 christos
68 1.1 christos struct sockaddr_if {
69 1.1 christos uint8_t sif_len;
70 1.1 christos sa_family_t sif_family;
71 1.1 christos in_port_t sif_port;
72 1.1 christos char sif_name[16];
73 1.1 christos };
74 1.1 christos
75 1.1 christos #define SIF_NAME(a) \
76 1.1 christos ((const struct sockaddr_if *)(const void *)(a))->sif_name
77 1.1 christos
78 1.1 christos static int conf_is_interface(const char *);
79 1.1 christos
80 1.1 christos #define FSTAR -1
81 1.1 christos #define FEQUAL -2
82 1.1 christos
83 1.1 christos static void
84 1.1 christos advance(char **p)
85 1.1 christos {
86 1.1 christos char *ep = *p;
87 1.1 christos while (*ep && !isspace((unsigned char)*ep))
88 1.1 christos ep++;
89 1.1 christos while (*ep && isspace((unsigned char)*ep))
90 1.1 christos *ep++ = '\0';
91 1.1 christos *p = ep;
92 1.1 christos }
93 1.1 christos
94 1.1 christos static int
95 1.1 christos conf_getnum(const char *f, size_t l, bool local, void *rp, const char *name,
96 1.1 christos const char *p)
97 1.1 christos {
98 1.1 christos int e;
99 1.1 christos intmax_t im;
100 1.1 christos int *r = rp;
101 1.1 christos
102 1.1 christos if (strcmp(p, "*") == 0) {
103 1.1 christos *r = FSTAR;
104 1.1 christos return 0;
105 1.1 christos }
106 1.1 christos if (strcmp(p, "=") == 0) {
107 1.1 christos if (local)
108 1.1 christos goto out;
109 1.1 christos *r = FEQUAL;
110 1.1 christos return 0;
111 1.1 christos }
112 1.1 christos
113 1.1 christos im = strtoi(p, NULL, 0, 0, INT_MAX, &e);
114 1.1 christos if (e == 0) {
115 1.1 christos *r = (int)im;
116 1.1 christos return 0;
117 1.1 christos }
118 1.1 christos
119 1.1 christos if (f == NULL)
120 1.1 christos return -1;
121 1.1 christos (*lfun)(LOG_ERR, "%s: %s, %zu: Bad number for %s [%s]", __func__, f, l,
122 1.1 christos name, p);
123 1.1 christos return -1;
124 1.1 christos out:
125 1.1 christos (*lfun)(LOG_ERR, "%s: %s, %zu: `=' for %s not allowed in local config",
126 1.1 christos __func__, f, l, name);
127 1.1 christos return -1;
128 1.1 christos
129 1.1 christos }
130 1.1 christos
131 1.1 christos static int
132 1.1 christos conf_getnfail(const char *f, size_t l, bool local, struct conf *c,
133 1.1 christos const char *p)
134 1.1 christos {
135 1.1 christos return conf_getnum(f, l, local, &c->c_nfail, "nfail", p);
136 1.1 christos }
137 1.1 christos
138 1.1 christos static int
139 1.1 christos conf_getsecs(const char *f, size_t l, bool local, struct conf *c, const char *p)
140 1.1 christos {
141 1.1 christos int e;
142 1.1 christos char *ep;
143 1.1 christos intmax_t tot, im;
144 1.1 christos
145 1.1 christos tot = 0;
146 1.1 christos if (strcmp(p, "*") == 0) {
147 1.1 christos c->c_duration = FSTAR;
148 1.1 christos return 0;
149 1.1 christos }
150 1.1 christos if (strcmp(p, "=") == 0) {
151 1.1 christos if (local)
152 1.1 christos goto out;
153 1.1 christos c->c_duration = FEQUAL;
154 1.1 christos return 0;
155 1.1 christos }
156 1.1 christos again:
157 1.1 christos im = strtoi(p, &ep, 0, 0, INT_MAX, &e);
158 1.1 christos
159 1.1 christos if (e == ENOTSUP) {
160 1.1 christos switch (*ep) {
161 1.1 christos case 'd':
162 1.1 christos im *= 24;
163 1.1 christos /*FALLTHROUGH*/
164 1.1 christos case 'h':
165 1.1 christos im *= 60;
166 1.1 christos /*FALLTHROUGH*/
167 1.1 christos case 'm':
168 1.1 christos im *= 60;
169 1.1 christos /*FALLTHROUGH*/
170 1.1 christos case 's':
171 1.1 christos e = 0;
172 1.1 christos tot += im;
173 1.1 christos if (ep[1] != '\0') {
174 1.1 christos p = ep + 2;
175 1.1 christos goto again;
176 1.1 christos }
177 1.1 christos break;
178 1.1 christos }
179 1.1 christos } else
180 1.1 christos tot = im;
181 1.1 christos
182 1.1 christos if (e == 0) {
183 1.1 christos c->c_duration = (int)tot;
184 1.1 christos return 0;
185 1.1 christos }
186 1.1 christos
187 1.1 christos if (f == NULL)
188 1.1 christos return -1;
189 1.1 christos (*lfun)(LOG_ERR, "%s: %s, %zu: Bad number [%s]", __func__, f, l, p);
190 1.1 christos return -1;
191 1.1 christos out:
192 1.1 christos (*lfun)(LOG_ERR, "%s: %s, %zu: `=' duration not allowed in local"
193 1.1 christos " config", __func__, f, l);
194 1.1 christos return -1;
195 1.1 christos
196 1.1 christos }
197 1.1 christos
198 1.1 christos static int
199 1.1 christos conf_getport(const char *f, size_t l, bool local, void *r, const char *p)
200 1.1 christos {
201 1.1 christos struct servent *sv;
202 1.1 christos
203 1.1 christos // XXX: Pass in the proto instead
204 1.1 christos if ((sv = getservbyname(p, "tcp")) != NULL) {
205 1.1 christos *(int *)r = ntohs(sv->s_port);
206 1.1 christos return 0;
207 1.1 christos }
208 1.1 christos if ((sv = getservbyname(p, "udp")) != NULL) {
209 1.1 christos *(int *)r = ntohs(sv->s_port);
210 1.1 christos return 0;
211 1.1 christos }
212 1.1 christos
213 1.1 christos return conf_getnum(f, l, local, r, "service", p);
214 1.1 christos }
215 1.1 christos
216 1.1 christos static int
217 1.1 christos conf_getmask(const char *f, size_t l, bool local, const char **p, int *mask)
218 1.1 christos {
219 1.1 christos char *d;
220 1.1 christos const char *s = *p;
221 1.1 christos
222 1.1 christos if ((d = strchr(s, ':')) != NULL) {
223 1.1 christos *d++ = '\0';
224 1.1 christos *p = d;
225 1.1 christos }
226 1.1 christos if ((d = strchr(s, '/')) == NULL) {
227 1.1 christos *mask = FSTAR;
228 1.1 christos return 0;
229 1.1 christos }
230 1.1 christos
231 1.1 christos *d++ = '\0';
232 1.1 christos return conf_getnum(f, l, local, mask, "mask", d);
233 1.1 christos }
234 1.1 christos
235 1.1 christos static int
236 1.1 christos conf_gethostport(const char *f, size_t l, bool local, struct conf *c,
237 1.1 christos const char *p)
238 1.1 christos {
239 1.1 christos char *d; // XXX: Ok to write to string.
240 1.1 christos in_port_t *port = NULL;
241 1.1 christos const char *pstr;
242 1.1 christos
243 1.1 christos if (strcmp(p, "*") == 0) {
244 1.1 christos c->c_port = FSTAR;
245 1.1 christos c->c_lmask = FSTAR;
246 1.1 christos return 0;
247 1.1 christos }
248 1.1 christos
249 1.1 christos if ((d = strchr(p, ']')) != NULL) {
250 1.1 christos *d++ = '\0';
251 1.1 christos pstr = d;
252 1.1 christos p++;
253 1.1 christos } else
254 1.1 christos pstr = p;
255 1.1 christos
256 1.1 christos if (conf_getmask(f, l, local, &pstr, &c->c_lmask) == -1)
257 1.1 christos goto out;
258 1.1 christos
259 1.1 christos if (d) {
260 1.1 christos struct sockaddr_in6 *sin6 = (void *)&c->c_ss;
261 1.1 christos if (debug)
262 1.1 christos (*lfun)(LOG_DEBUG, "%s: host6 %s", __func__, p);
263 1.1 christos if (strcmp(p, "*") != 0) {
264 1.1 christos if (inet_pton(AF_INET6, p, &sin6->sin6_addr) == -1)
265 1.1 christos goto out;
266 1.1 christos sin6->sin6_family = AF_INET6;
267 1.1 christos #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
268 1.1 christos sin6->sin6_len = sizeof(*sin6);
269 1.1 christos #endif
270 1.1 christos port = &sin6->sin6_port;
271 1.1 christos }
272 1.1 christos } else if (pstr != p || strchr(p, '.') || conf_is_interface(p)) {
273 1.1 christos if (pstr == p)
274 1.1 christos pstr = "*";
275 1.1 christos struct sockaddr_in *sin = (void *)&c->c_ss;
276 1.1 christos struct sockaddr_if *sif = (void *)&c->c_ss;
277 1.1 christos if (debug)
278 1.1 christos (*lfun)(LOG_DEBUG, "%s: host4 %s", __func__, p);
279 1.1 christos if (strcmp(p, "*") != 0) {
280 1.1 christos if (conf_is_interface(p)) {
281 1.1 christos if (!local)
282 1.1 christos goto out2;
283 1.1 christos if (debug)
284 1.1 christos (*lfun)(LOG_DEBUG, "%s: interface %s",
285 1.1 christos __func__, p);
286 1.1 christos if (c->c_lmask != FSTAR)
287 1.1 christos goto out1;
288 1.1 christos sif->sif_family = AF_MAX;
289 1.1 christos strlcpy(sif->sif_name, p,
290 1.1 christos sizeof(sif->sif_name));
291 1.1 christos #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
292 1.1 christos sif->sif_len = sizeof(*sif);
293 1.1 christos #endif
294 1.1 christos port = &sif->sif_port;
295 1.1 christos } else if (inet_pton(AF_INET, p, &sin->sin_addr) != -1)
296 1.1 christos {
297 1.1 christos sin->sin_family = AF_INET;
298 1.1 christos #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
299 1.1 christos sin->sin_len = sizeof(*sin);
300 1.1 christos #endif
301 1.1 christos port = &sin->sin_port;
302 1.1 christos } else
303 1.1 christos goto out;
304 1.1 christos }
305 1.1 christos }
306 1.1 christos
307 1.1 christos if (conf_getport(f, l, local, &c->c_port, pstr) == -1)
308 1.1 christos return -1;
309 1.1 christos
310 1.1 christos if (port && c->c_port != FSTAR && c->c_port != FEQUAL)
311 1.1 christos *port = htons((in_port_t)c->c_port);
312 1.1 christos return 0;
313 1.1 christos out:
314 1.1 christos (*lfun)(LOG_ERR, "%s: %s, %zu: Bad address [%s]", __func__, f, l, pstr);
315 1.1 christos return -1;
316 1.1 christos out1:
317 1.1 christos (*lfun)(LOG_ERR, "%s: %s, %zu: Can't specify mask %d with "
318 1.1 christos "interface [%s]", __func__, f, l, c->c_lmask, p);
319 1.1 christos return -1;
320 1.1 christos out2:
321 1.1 christos (*lfun)(LOG_ERR, "%s: %s, %zu: Interface spec does not make sense "
322 1.1 christos "with remote config [%s]", __func__, f, l, p);
323 1.1 christos return -1;
324 1.1 christos }
325 1.1 christos
326 1.1 christos static int
327 1.1 christos conf_getproto(const char *f, size_t l, bool local __unused, struct conf *c,
328 1.1 christos const char *p)
329 1.1 christos {
330 1.1 christos if (strcmp(p, "stream") == 0) {
331 1.1 christos c->c_proto = IPPROTO_TCP;
332 1.1 christos return 0;
333 1.1 christos }
334 1.1 christos if (strcmp(p, "dgram") == 0) {
335 1.1 christos c->c_proto = IPPROTO_UDP;
336 1.1 christos return 0;
337 1.1 christos }
338 1.1 christos return conf_getnum(f, l, local, &c->c_proto, "protocol", p);
339 1.1 christos }
340 1.1 christos
341 1.1 christos static int
342 1.1 christos conf_getfamily(const char *f, size_t l, bool local __unused, struct conf *c,
343 1.1 christos const char *p)
344 1.1 christos {
345 1.1 christos if (strncmp(p, "tcp", 3) == 0 || strncmp(p, "udp", 3) == 0) {
346 1.1 christos c->c_family = p[3] == '6' ? AF_INET6 : AF_INET;
347 1.1 christos return 0;
348 1.1 christos }
349 1.1 christos return conf_getnum(f, l, local, &c->c_family, "family", p);
350 1.1 christos }
351 1.1 christos
352 1.1 christos static int
353 1.1 christos conf_getuid(const char *f, size_t l, bool local __unused, struct conf *c,
354 1.1 christos const char *p)
355 1.1 christos {
356 1.1 christos struct passwd *pw;
357 1.1 christos
358 1.1 christos if ((pw = getpwnam(p)) != NULL) {
359 1.1 christos c->c_uid = (int)pw->pw_uid;
360 1.1 christos return 0;
361 1.1 christos }
362 1.1 christos
363 1.1 christos return conf_getnum(f, l, local, &c->c_uid, "user", p);
364 1.1 christos }
365 1.1 christos
366 1.1 christos
367 1.1 christos static int
368 1.1 christos conf_getname(const char *f, size_t l, bool local, struct conf *c,
369 1.1 christos const char *p)
370 1.1 christos {
371 1.1 christos if (conf_getmask(f, l, local, &p, &c->c_rmask) == -1)
372 1.1 christos return -1;
373 1.1 christos
374 1.1 christos if (strcmp(p, "*") == 0) {
375 1.1 christos strlcpy(c->c_name, rulename, CONFNAMESZ);
376 1.1 christos return 0;
377 1.1 christos }
378 1.1 christos
379 1.1 christos if (strcmp(p, "=") == 0) {
380 1.1 christos if (local)
381 1.1 christos goto out;
382 1.1 christos c->c_name[0] = '\0';
383 1.1 christos return 0;
384 1.1 christos }
385 1.1 christos
386 1.1 christos snprintf(c->c_name, CONFNAMESZ, "%s%s", *p == '-' ? rulename : "", p);
387 1.1 christos return 0;
388 1.1 christos out:
389 1.1 christos (*lfun)(LOG_ERR, "%s: %s, %zu: `=' name not allowed in local"
390 1.1 christos " config", __func__, f, l);
391 1.1 christos return -1;
392 1.1 christos }
393 1.1 christos
394 1.1 christos static int
395 1.1 christos getvalue(const char *f, size_t l, bool local, void *r, char **p,
396 1.1 christos int (*fun)(const char *, size_t, bool, struct conf *, const char *))
397 1.1 christos {
398 1.1 christos char *ep = *p;
399 1.1 christos
400 1.1 christos advance(p);
401 1.1 christos return (*fun)(f, l, local, r, ep);
402 1.1 christos }
403 1.1 christos
404 1.1 christos
405 1.1 christos static int
406 1.1 christos conf_parseline(const char *f, size_t l, char *p, struct conf *c, bool local)
407 1.1 christos {
408 1.1 christos int e;
409 1.1 christos
410 1.1 christos while (*p && isspace((unsigned char)*p))
411 1.1 christos p++;
412 1.1 christos
413 1.1 christos memset(c, 0, sizeof(*c));
414 1.1 christos e = getvalue(f, l, local, c, &p, conf_gethostport);
415 1.1 christos if (e) return -1;
416 1.1 christos e = getvalue(f, l, local, c, &p, conf_getproto);
417 1.1 christos if (e) return -1;
418 1.1 christos e = getvalue(f, l, local, c, &p, conf_getfamily);
419 1.1 christos if (e) return -1;
420 1.1 christos e = getvalue(f, l, local, c, &p, conf_getuid);
421 1.1 christos if (e) return -1;
422 1.1 christos e = getvalue(f, l, local, c, &p, conf_getname);
423 1.1 christos if (e) return -1;
424 1.1 christos e = getvalue(f, l, local, c, &p, conf_getnfail);
425 1.1 christos if (e) return -1;
426 1.1 christos e = getvalue(f, l, local, c, &p, conf_getsecs);
427 1.1 christos if (e) return -1;
428 1.1 christos
429 1.1 christos return 0;
430 1.1 christos }
431 1.1 christos
432 1.1 christos static int
433 1.1 christos conf_sort(const void *v1, const void *v2)
434 1.1 christos {
435 1.1 christos const struct conf *c1 = v1;
436 1.1 christos const struct conf *c2 = v2;
437 1.1 christos
438 1.1 christos #define CMP(a, b, f) \
439 1.1 christos if ((a)->f > (b)->f) return -1; \
440 1.1 christos else if ((a)->f < (b)->f) return 1
441 1.1 christos
442 1.1 christos CMP(c1, c2, c_ss.ss_family);
443 1.1 christos CMP(c1, c2, c_lmask);
444 1.1 christos CMP(c1, c2, c_port);
445 1.1 christos CMP(c1, c2, c_proto);
446 1.1 christos CMP(c1, c2, c_family);
447 1.1 christos CMP(c1, c2, c_rmask);
448 1.1 christos CMP(c1, c2, c_uid);
449 1.1 christos #undef CMP
450 1.1 christos return 0;
451 1.1 christos }
452 1.1 christos
453 1.1 christos static int
454 1.1 christos conf_is_interface(const char *name)
455 1.1 christos {
456 1.1 christos const struct ifaddrs *ifa;
457 1.1 christos
458 1.1 christos for (ifa = ifas; ifa; ifa = ifa->ifa_next)
459 1.1 christos if (strcmp(ifa->ifa_name, name) == 0)
460 1.1 christos return 1;
461 1.1 christos return 0;
462 1.1 christos }
463 1.1 christos
464 1.1 christos #define MASK(m) ((uint32_t)~((1 << (32 - (m))) - 1))
465 1.1 christos
466 1.1 christos static int
467 1.1 christos conf_amask_eq(const void *v1, const void *v2, size_t len, int mask)
468 1.1 christos {
469 1.1 christos const uint32_t *a1 = v1;
470 1.1 christos const uint32_t *a2 = v2;
471 1.1 christos uint32_t m;
472 1.1 christos int omask = mask;
473 1.1 christos
474 1.1 christos len >>= 2;
475 1.1 christos switch (mask) {
476 1.1 christos case FSTAR:
477 1.1 christos if (memcmp(v1, v2, len) == 0)
478 1.1 christos return 1;
479 1.1 christos goto out;
480 1.1 christos case FEQUAL:
481 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__,
482 1.1 christos mask);
483 1.1 christos abort();
484 1.1 christos default:
485 1.1 christos break;
486 1.1 christos }
487 1.1 christos
488 1.1 christos for (size_t i = 0; i < len; i++) {
489 1.1 christos if (mask > 32) {
490 1.1 christos m = htonl((uint32_t)~0);
491 1.1 christos mask -= 32;
492 1.1 christos } else if (mask) {
493 1.1 christos m = htonl(MASK(mask));
494 1.1 christos mask = 0;
495 1.1 christos } else
496 1.1 christos return 1;
497 1.1 christos if ((a1[i] & m) != (a2[i] & m))
498 1.1 christos goto out;
499 1.1 christos }
500 1.1 christos return 1;
501 1.1 christos out:
502 1.1 christos if (debug > 1) {
503 1.1 christos char b1[256], b2[256];
504 1.1 christos len <<= 2;
505 1.1 christos blhexdump(b1, sizeof(b1), "a1", v1, len);
506 1.1 christos blhexdump(b2, sizeof(b2), "a2", v2, len);
507 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s != %s [0x%x]", __func__,
508 1.1 christos b1, b2, omask);
509 1.1 christos }
510 1.1 christos return 0;
511 1.1 christos }
512 1.1 christos
513 1.1 christos /*
514 1.1 christos * Apply the mask to the given address
515 1.1 christos */
516 1.1 christos static void
517 1.1 christos conf_apply_mask(void *v, size_t len, int mask)
518 1.1 christos {
519 1.1 christos uint32_t *a = v;
520 1.1 christos uint32_t m;
521 1.1 christos
522 1.1 christos switch (mask) {
523 1.1 christos case FSTAR:
524 1.1 christos return;
525 1.1 christos case FEQUAL:
526 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__,
527 1.1 christos mask);
528 1.1 christos abort();
529 1.1 christos default:
530 1.1 christos break;
531 1.1 christos }
532 1.1 christos len >>= 2;
533 1.1 christos
534 1.1 christos for (size_t i = 0; i < len; i++) {
535 1.1 christos if (mask > 32) {
536 1.1 christos m = htonl((uint32_t)~0);
537 1.1 christos mask -= 32;
538 1.1 christos } else if (mask) {
539 1.1 christos m = htonl(MASK(mask));
540 1.1 christos mask = 0;
541 1.1 christos } else
542 1.1 christos m = 0;
543 1.1 christos a[i] &= m;
544 1.1 christos }
545 1.1 christos }
546 1.1 christos
547 1.1 christos /*
548 1.1 christos * apply the mask and the port to the address given
549 1.1 christos */
550 1.1 christos static void
551 1.1 christos conf_addr_set(struct conf *c, const struct sockaddr_storage *ss)
552 1.1 christos {
553 1.1 christos struct sockaddr_in *sin;
554 1.1 christos struct sockaddr_in6 *sin6;
555 1.1 christos in_port_t *port;
556 1.1 christos void *addr;
557 1.1 christos size_t alen;
558 1.1 christos
559 1.1 christos c->c_lmask = c->c_rmask;
560 1.1 christos c->c_ss = *ss;
561 1.1 christos
562 1.1 christos if (c->c_ss.ss_family != c->c_family) {
563 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: mismatched family "
564 1.1 christos "%u != %u", __func__, c->c_ss.ss_family, c->c_family);
565 1.1 christos abort();
566 1.1 christos }
567 1.1 christos
568 1.1 christos switch (c->c_ss.ss_family) {
569 1.1 christos case AF_INET:
570 1.1 christos sin = (void *)&c->c_ss;
571 1.1 christos port = &sin->sin_port;
572 1.1 christos addr = &sin->sin_addr;
573 1.1 christos alen = sizeof(sin->sin_addr);
574 1.1 christos break;
575 1.1 christos case AF_INET6:
576 1.1 christos sin6 = (void *)&c->c_ss;
577 1.1 christos port = &sin6->sin6_port;
578 1.1 christos addr = &sin6->sin6_addr;
579 1.1 christos alen = sizeof(sin6->sin6_addr);
580 1.1 christos break;
581 1.1 christos default:
582 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u",
583 1.1 christos __func__, c->c_ss.ss_family);
584 1.1 christos abort();
585 1.1 christos }
586 1.1 christos
587 1.1 christos *port = htons((in_port_t)c->c_port);
588 1.1 christos conf_apply_mask(addr, alen, c->c_lmask);
589 1.1 christos if (c->c_lmask == FSTAR)
590 1.1 christos c->c_lmask = (int)(alen * 8);
591 1.1 christos if (debug) {
592 1.1 christos char buf[128];
593 1.1 christos sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&c->c_ss);
594 1.1 christos (*lfun)(LOG_DEBUG, "Applied address %s", buf);
595 1.1 christos }
596 1.1 christos }
597 1.1 christos
598 1.1 christos /*
599 1.1 christos * Compared two addresses for equality applying the mask
600 1.1 christos */
601 1.1 christos static int
602 1.1 christos conf_inet_eq(const void *v1, const void *v2, int mask)
603 1.1 christos {
604 1.1 christos const struct sockaddr *sa1 = v1;
605 1.1 christos const struct sockaddr *sa2 = v2;
606 1.1 christos size_t size;
607 1.1 christos
608 1.1 christos if (sa1->sa_family != sa2->sa_family)
609 1.1 christos return 0;
610 1.1 christos
611 1.1 christos switch (sa1->sa_family) {
612 1.1 christos case AF_INET: {
613 1.1 christos const struct sockaddr_in *s1 = v1;
614 1.1 christos const struct sockaddr_in *s2 = v2;
615 1.1 christos size = sizeof(s1->sin_addr);
616 1.1 christos v1 = &s1->sin_addr;
617 1.1 christos v2 = &s2->sin_addr;
618 1.1 christos break;
619 1.1 christos }
620 1.1 christos
621 1.1 christos case AF_INET6: {
622 1.1 christos const struct sockaddr_in6 *s1 = v1;
623 1.1 christos const struct sockaddr_in6 *s2 = v2;
624 1.1 christos size = sizeof(s1->sin6_addr);
625 1.1 christos v1 = &s1->sin6_addr;
626 1.1 christos v2 = &s2->sin6_addr;
627 1.1 christos break;
628 1.1 christos }
629 1.1 christos
630 1.1 christos default:
631 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u",
632 1.1 christos __func__, sa1->sa_family);
633 1.1 christos abort();
634 1.1 christos }
635 1.1 christos
636 1.1 christos return conf_amask_eq(v1, v2, size, mask);
637 1.1 christos }
638 1.1 christos
639 1.1 christos static int
640 1.1 christos conf_addr_in_interface(const struct sockaddr_storage *s1,
641 1.1 christos const struct sockaddr_storage *s2, int mask)
642 1.1 christos {
643 1.1 christos const char *name = SIF_NAME(s2);
644 1.1 christos const struct ifaddrs *ifa;
645 1.1 christos
646 1.1 christos for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
647 1.1 christos if ((ifa->ifa_flags & IFF_UP) == 0)
648 1.1 christos continue;
649 1.1 christos
650 1.1 christos if (strcmp(ifa->ifa_name, name) != 0)
651 1.1 christos continue;
652 1.1 christos
653 1.1 christos if (s1->ss_family != ifa->ifa_addr->sa_family)
654 1.1 christos continue;
655 1.1 christos
656 1.1 christos bool eq;
657 1.1 christos switch (s1->ss_family) {
658 1.1 christos case AF_INET:
659 1.1 christos case AF_INET6:
660 1.1 christos eq = conf_inet_eq(ifa->ifa_addr, s1, mask);
661 1.1 christos break;
662 1.1 christos default:
663 1.1 christos (*lfun)(LOG_ERR, "Bad family %u", s1->ss_family);
664 1.1 christos continue;
665 1.1 christos }
666 1.1 christos if (eq)
667 1.1 christos return 1;
668 1.1 christos }
669 1.1 christos return 0;
670 1.1 christos }
671 1.1 christos
672 1.1 christos static int
673 1.1 christos conf_addr_eq(const struct sockaddr_storage *s1,
674 1.1 christos const struct sockaddr_storage *s2, int mask)
675 1.1 christos {
676 1.1 christos switch (s2->ss_family) {
677 1.1 christos case 0:
678 1.1 christos return 1;
679 1.1 christos case AF_MAX:
680 1.1 christos return conf_addr_in_interface(s1, s2, mask);
681 1.1 christos case AF_INET:
682 1.1 christos case AF_INET6:
683 1.1 christos return conf_inet_eq(s1, s2, mask);
684 1.1 christos default:
685 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u",
686 1.1 christos __func__, s1->ss_family);
687 1.1 christos abort();
688 1.1 christos }
689 1.1 christos }
690 1.1 christos
691 1.1 christos static int
692 1.1 christos conf_eq(const struct conf *c1, const struct conf *c2)
693 1.1 christos {
694 1.1 christos
695 1.1 christos if (!conf_addr_eq(&c1->c_ss, &c2->c_ss, c2->c_lmask))
696 1.1 christos return 0;
697 1.1 christos
698 1.1 christos #define CMP(a, b, f) \
699 1.1 christos if ((a)->f != (b)->f && (b)->f != FSTAR && (b)->f != FEQUAL) { \
700 1.1 christos if (debug > 1) \
701 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s fail %d != %d", __func__, \
702 1.1 christos __STRING(f), (a)->f, (b)->f); \
703 1.1 christos return 0; \
704 1.1 christos }
705 1.1 christos CMP(c1, c2, c_port);
706 1.1 christos CMP(c1, c2, c_proto);
707 1.1 christos CMP(c1, c2, c_family);
708 1.1 christos CMP(c1, c2, c_uid);
709 1.1 christos #undef CMP
710 1.1 christos return 1;
711 1.1 christos }
712 1.1 christos
713 1.1 christos static const char *
714 1.1 christos conf_num(char *b, size_t l, int n)
715 1.1 christos {
716 1.1 christos switch (n) {
717 1.1 christos case FSTAR:
718 1.1 christos return "*";
719 1.1 christos case FEQUAL:
720 1.1 christos return "=";
721 1.1 christos default:
722 1.1 christos snprintf(b, l, "%d", n);
723 1.1 christos return b;
724 1.1 christos }
725 1.1 christos }
726 1.1 christos
727 1.1 christos static const char *
728 1.1 christos fmtname(const char *n) {
729 1.1 christos size_t l = strlen(rulename);
730 1.1 christos if (l == 0)
731 1.1 christos return "*";
732 1.1 christos if (strncmp(n, rulename, l) == 0) {
733 1.1 christos if (n[l] != '\0')
734 1.1 christos return n + l;
735 1.1 christos else
736 1.1 christos return "*";
737 1.1 christos } else if (!*n)
738 1.1 christos return "=";
739 1.1 christos else
740 1.1 christos return n;
741 1.1 christos }
742 1.1 christos
743 1.1 christos static void
744 1.1 christos fmtport(char *b, size_t l, int port)
745 1.1 christos {
746 1.1 christos char buf[128];
747 1.1 christos
748 1.1 christos if (port == FSTAR)
749 1.1 christos return;
750 1.1 christos
751 1.1 christos if (b[0] == '\0' || strcmp(b, "*") == 0)
752 1.1 christos snprintf(b, l, "%d", port);
753 1.1 christos else {
754 1.1 christos snprintf(buf, sizeof(buf), ":%d", port);
755 1.1 christos strlcat(b, buf, l);
756 1.1 christos }
757 1.1 christos }
758 1.1 christos
759 1.1 christos static const char *
760 1.1 christos fmtmask(char *b, size_t l, int fam, int mask)
761 1.1 christos {
762 1.1 christos char buf[128];
763 1.1 christos
764 1.1 christos switch (mask) {
765 1.1 christos case FSTAR:
766 1.1 christos return "";
767 1.1 christos case FEQUAL:
768 1.1 christos if (strcmp(b, "=") == 0)
769 1.1 christos return "";
770 1.1 christos else {
771 1.1 christos strlcat(b, "/=", l);
772 1.1 christos return b;
773 1.1 christos }
774 1.1 christos default:
775 1.1 christos break;
776 1.1 christos }
777 1.1 christos
778 1.1 christos switch (fam) {
779 1.1 christos case AF_INET:
780 1.1 christos if (mask == 32)
781 1.1 christos return "";
782 1.1 christos break;
783 1.1 christos case AF_INET6:
784 1.1 christos if (mask == 128)
785 1.1 christos return "";
786 1.1 christos break;
787 1.1 christos default:
788 1.1 christos break;
789 1.1 christos }
790 1.1 christos
791 1.1 christos snprintf(buf, sizeof(buf), "/%d", mask);
792 1.1 christos strlcat(b, buf, l);
793 1.1 christos return b;
794 1.1 christos }
795 1.1 christos
796 1.1 christos static const char *
797 1.1 christos conf_namemask(char *b, size_t l, const struct conf *c)
798 1.1 christos {
799 1.1 christos strlcpy(b, fmtname(c->c_name), l);
800 1.1 christos fmtmask(b, l, c->c_family, c->c_rmask);
801 1.1 christos return b;
802 1.1 christos }
803 1.1 christos
804 1.1 christos const char *
805 1.1 christos conf_print(char *buf, size_t len, const char *pref, const char *delim,
806 1.1 christos const struct conf *c)
807 1.1 christos {
808 1.1 christos char ha[128], hb[32], b[5][64];
809 1.1 christos int sp;
810 1.1 christos
811 1.1 christos #define N(n, v) conf_num(b[n], sizeof(b[n]), (v))
812 1.1 christos
813 1.1 christos switch (c->c_ss.ss_family) {
814 1.1 christos case 0:
815 1.1 christos snprintf(ha, sizeof(ha), "*");
816 1.1 christos break;
817 1.1 christos case AF_MAX:
818 1.1 christos snprintf(ha, sizeof(ha), "%s", SIF_NAME(&c->c_ss));
819 1.1 christos break;
820 1.1 christos default:
821 1.1 christos sockaddr_snprintf(ha, sizeof(ha), "%a", (const void *)&c->c_ss);
822 1.1 christos break;
823 1.1 christos }
824 1.1 christos
825 1.1 christos fmtmask(ha, sizeof(ha), c->c_family, c->c_lmask);
826 1.1 christos fmtport(ha, sizeof(ha), c->c_port);
827 1.1 christos
828 1.1 christos sp = *delim == '\t' ? 20 : -1;
829 1.1 christos hb[0] = '\0';
830 1.1 christos if (*delim)
831 1.1 christos snprintf(buf, len, "%s%*.*s%s%s%s" "%s%s%s%s"
832 1.1 christos "%s%s" "%s%s%s",
833 1.1 christos pref, sp, sp, ha, delim, N(0, c->c_proto), delim,
834 1.1 christos N(1, c->c_family), delim, N(2, c->c_uid), delim,
835 1.1 christos conf_namemask(hb, sizeof(hb), c), delim,
836 1.1 christos N(3, c->c_nfail), delim, N(4, c->c_duration));
837 1.1 christos else
838 1.1 christos snprintf(buf, len, "%starget:%s, proto:%s, family:%s, "
839 1.1 christos "uid:%s, name:%s, nfail:%s, duration:%s", pref,
840 1.1 christos ha, N(0, c->c_proto), N(1, c->c_family), N(2, c->c_uid),
841 1.1 christos conf_namemask(hb, sizeof(hb), c),
842 1.1 christos N(3, c->c_nfail), N(4, c->c_duration));
843 1.1 christos return buf;
844 1.1 christos }
845 1.1 christos
846 1.1 christos /*
847 1.1 christos * Apply the local config match to the result
848 1.1 christos */
849 1.1 christos static void
850 1.1 christos conf_apply(struct conf *c, const struct conf *sc)
851 1.1 christos {
852 1.1 christos char buf[BUFSIZ];
853 1.1 christos
854 1.1 christos if (debug) {
855 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
856 1.1 christos conf_print(buf, sizeof(buf), "merge:\t", "", sc));
857 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
858 1.1 christos conf_print(buf, sizeof(buf), "to:\t", "", c));
859 1.1 christos }
860 1.1 christos memcpy(c->c_name, sc->c_name, CONFNAMESZ);
861 1.1 christos c->c_uid = sc->c_uid;
862 1.1 christos c->c_rmask = sc->c_rmask;
863 1.1 christos c->c_nfail = sc->c_nfail;
864 1.1 christos c->c_duration = sc->c_duration;
865 1.1 christos
866 1.1 christos if (debug)
867 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
868 1.1 christos conf_print(buf, sizeof(buf), "result:\t", "", c));
869 1.1 christos }
870 1.1 christos
871 1.1 christos /*
872 1.1 christos * Merge a remote configuration to the result
873 1.1 christos */
874 1.1 christos static void
875 1.1 christos conf_merge(struct conf *c, const struct conf *sc)
876 1.1 christos {
877 1.1 christos char buf[BUFSIZ];
878 1.1 christos
879 1.1 christos if (debug) {
880 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
881 1.1 christos conf_print(buf, sizeof(buf), "merge:\t", "", sc));
882 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
883 1.1 christos conf_print(buf, sizeof(buf), "to:\t", "", c));
884 1.1 christos }
885 1.1 christos
886 1.1 christos if (sc->c_name[0])
887 1.1 christos memcpy(c->c_name, sc->c_name, CONFNAMESZ);
888 1.1 christos if (sc->c_uid != FEQUAL)
889 1.1 christos c->c_uid = sc->c_uid;
890 1.1 christos if (sc->c_rmask != FEQUAL)
891 1.1 christos c->c_lmask = c->c_rmask = sc->c_rmask;
892 1.1 christos if (sc->c_nfail != FEQUAL)
893 1.1 christos c->c_nfail = sc->c_nfail;
894 1.1 christos if (sc->c_duration != FEQUAL)
895 1.1 christos c->c_duration = sc->c_duration;
896 1.1 christos if (debug)
897 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
898 1.1 christos conf_print(buf, sizeof(buf), "result:\t", "", c));
899 1.1 christos }
900 1.1 christos
901 1.1 christos static void
902 1.1 christos confset_init(struct confset *cs)
903 1.1 christos {
904 1.1 christos cs->cs_c = NULL;
905 1.1 christos cs->cs_n = 0;
906 1.1 christos cs->cs_m = 0;
907 1.1 christos }
908 1.1 christos
909 1.1 christos static int
910 1.1 christos confset_grow(struct confset *cs)
911 1.1 christos {
912 1.1 christos void *tc;
913 1.1 christos
914 1.1 christos cs->cs_m += 10;
915 1.1 christos tc = realloc(cs->cs_c, cs->cs_m * sizeof(*cs->cs_c));
916 1.1 christos if (tc == NULL) {
917 1.1 christos (*lfun)(LOG_ERR, "%s: Can't grow confset (%m)", __func__);
918 1.1 christos return -1;
919 1.1 christos }
920 1.1 christos cs->cs_c = tc;
921 1.1 christos return 0;
922 1.1 christos }
923 1.1 christos
924 1.1 christos static struct conf *
925 1.1 christos confset_get(struct confset *cs)
926 1.1 christos {
927 1.1 christos return &cs->cs_c[cs->cs_n];
928 1.1 christos }
929 1.1 christos
930 1.1 christos static bool
931 1.1 christos confset_full(const struct confset *cs)
932 1.1 christos {
933 1.1 christos return cs->cs_n == cs->cs_m;
934 1.1 christos }
935 1.1 christos
936 1.1 christos static void
937 1.1 christos confset_sort(struct confset *cs)
938 1.1 christos {
939 1.1 christos qsort(cs->cs_c, cs->cs_n, sizeof(*cs->cs_c), conf_sort);
940 1.1 christos }
941 1.1 christos
942 1.1 christos static void
943 1.1 christos confset_add(struct confset *cs)
944 1.1 christos {
945 1.1 christos cs->cs_n++;
946 1.1 christos }
947 1.1 christos
948 1.1 christos static void
949 1.1 christos confset_free(struct confset *cs)
950 1.1 christos {
951 1.1 christos free(cs->cs_c);
952 1.1 christos confset_init(cs);
953 1.1 christos }
954 1.1 christos
955 1.1 christos static void
956 1.1 christos confset_replace(struct confset *dc, struct confset *sc)
957 1.1 christos {
958 1.1 christos struct confset tc;
959 1.1 christos tc = *dc;
960 1.1 christos *dc = *sc;
961 1.1 christos confset_init(sc);
962 1.1 christos confset_free(&tc);
963 1.1 christos }
964 1.1 christos
965 1.1 christos static void
966 1.1 christos confset_list(const struct confset *cs, const char *msg, const char *where)
967 1.1 christos {
968 1.1 christos char buf[BUFSIZ];
969 1.1 christos
970 1.1 christos (*lfun)(LOG_DEBUG, "[%s]", msg);
971 1.1 christos (*lfun)(LOG_DEBUG, "%20.20s\ttype\tproto\towner\tname\tnfail\tduration",
972 1.1 christos where);
973 1.1 christos for (size_t i = 0; i < cs->cs_n; i++)
974 1.1 christos (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), "", "\t",
975 1.1 christos &cs->cs_c[i]));
976 1.1 christos }
977 1.1 christos
978 1.1 christos /*
979 1.1 christos * Match a configuration against the given list and apply the function
980 1.1 christos * to it, returning the matched entry number.
981 1.1 christos */
982 1.1 christos static size_t
983 1.1 christos confset_match(const struct confset *cs, struct conf *c,
984 1.1 christos void (*fun)(struct conf *, const struct conf *))
985 1.1 christos {
986 1.1 christos char buf[BUFSIZ];
987 1.1 christos size_t i;
988 1.1 christos
989 1.1 christos for (i = 0; i < cs->cs_n; i++) {
990 1.1 christos if (debug)
991 1.1 christos (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf),
992 1.1 christos "check:\t", "", &cs->cs_c[i]));
993 1.1 christos if (conf_eq(c, &cs->cs_c[i])) {
994 1.1 christos if (debug)
995 1.1 christos (*lfun)(LOG_DEBUG, "%s",
996 1.1 christos conf_print(buf, sizeof(buf),
997 1.1 christos "found:\t", "", &cs->cs_c[i]));
998 1.1 christos (*fun)(c, &cs->cs_c[i]);
999 1.1 christos break;
1000 1.1 christos }
1001 1.1 christos }
1002 1.1 christos return i;
1003 1.1 christos }
1004 1.1 christos
1005 1.1 christos #ifdef AF_ROUTE
1006 1.1 christos static int
1007 1.1 christos conf_route_perm(int fd) {
1008 1.1 christos /* Disable for now, the access check in the routing socket uses curlwp */
1009 1.1 christos #if defined(RTM_IFANNOUNCE) && defined(RT_ROUNDUP)
1010 1.1 christos /*
1011 1.1 christos * Send a routing message that is not supported to check for access
1012 1.1 christos * We expect EOPNOTSUPP for having access, since we are sending a
1013 1.1 christos * request the system does not understand and EACCES if we don't have
1014 1.1 christos * access.
1015 1.1 christos */
1016 1.1 christos static struct sockaddr_in sin = {
1017 1.1 christos #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1018 1.1 christos .sin_len = sizeof(sin),
1019 1.1 christos #endif
1020 1.1 christos .sin_family = AF_INET,
1021 1.1 christos };
1022 1.1 christos char buf[4096];
1023 1.1 christos struct rt_msghdr *rtm = (void *)buf;
1024 1.1 christos char *cp = (char *)(rtm + 1);
1025 1.1 christos size_t l;
1026 1.1 christos
1027 1.1 christos #define NEXTADDR(s) \
1028 1.1 christos l = RT_ROUNDUP(sizeof(*s)); memmove(cp, s, l); cp += l;
1029 1.1 christos memset(buf, 0, sizeof(buf));
1030 1.1 christos rtm->rtm_type = RTM_IFANNOUNCE;
1031 1.1 christos rtm->rtm_flags = 0;
1032 1.1 christos rtm->rtm_addrs = RTA_DST|RTA_GATEWAY;
1033 1.1 christos rtm->rtm_version = RTM_VERSION;
1034 1.1 christos rtm->rtm_seq = 666;
1035 1.1 christos NEXTADDR(&sin);
1036 1.1 christos NEXTADDR(&sin);
1037 1.1 christos rtm->rtm_msglen = (u_short)((char *)cp - (char *)rtm);
1038 1.1 christos if (write(fd, rtm, rtm->rtm_msglen) != -1) {
1039 1.1 christos (*lfun)(LOG_ERR, "Writing to routing socket succeeded!");
1040 1.1 christos return 0;
1041 1.1 christos }
1042 1.1 christos switch (errno) {
1043 1.1 christos case EACCES:
1044 1.1 christos return 0;
1045 1.1 christos case EOPNOTSUPP:
1046 1.1 christos return 1;
1047 1.1 christos default:
1048 1.1 christos (*lfun)(LOG_ERR,
1049 1.1 christos "Unexpected error writing to routing socket (%m)");
1050 1.1 christos return 0;
1051 1.1 christos }
1052 1.1 christos #else
1053 1.1 christos return 0;
1054 1.1 christos #endif
1055 1.1 christos }
1056 1.1 christos #endif
1057 1.1 christos
1058 1.1 christos static int
1059 1.1 christos conf_handle_inet(int fd, const void *lss, struct conf *cr)
1060 1.1 christos {
1061 1.1 christos char buf[BUFSIZ];
1062 1.1 christos int proto;
1063 1.1 christos socklen_t slen = sizeof(proto);
1064 1.1 christos
1065 1.1 christos if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &proto, &slen) == -1) {
1066 1.1 christos (*lfun)(LOG_ERR, "getsockopt failed (%m)");
1067 1.1 christos return -1;
1068 1.1 christos }
1069 1.1 christos
1070 1.1 christos if (debug) {
1071 1.1 christos sockaddr_snprintf(buf, sizeof(buf), "%a:%p", lss);
1072 1.1 christos (*lfun)(LOG_DEBUG, "listening socket: %s", buf);
1073 1.1 christos }
1074 1.1 christos
1075 1.1 christos switch (proto) {
1076 1.1 christos case SOCK_STREAM:
1077 1.1 christos cr->c_proto = IPPROTO_TCP;
1078 1.1 christos break;
1079 1.1 christos case SOCK_DGRAM:
1080 1.1 christos cr->c_proto = IPPROTO_UDP;
1081 1.1 christos break;
1082 1.1 christos default:
1083 1.1 christos (*lfun)(LOG_ERR, "unsupported protocol %d", proto);
1084 1.1 christos return -1;
1085 1.1 christos }
1086 1.1 christos return 0;
1087 1.1 christos }
1088 1.1 christos
1089 1.1 christos const struct conf *
1090 1.1 christos conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss,
1091 1.1 christos struct conf *cr)
1092 1.1 christos {
1093 1.1 christos socklen_t slen;
1094 1.1 christos struct sockaddr_storage lss;
1095 1.1 christos size_t i;
1096 1.1 christos char buf[BUFSIZ];
1097 1.1 christos
1098 1.1 christos memset(cr, 0, sizeof(*cr));
1099 1.1 christos slen = sizeof(lss);
1100 1.1 christos memset(&lss, 0, slen);
1101 1.1 christos if (getsockname(fd, (void *)&lss, &slen) == -1) {
1102 1.1 christos (*lfun)(LOG_ERR, "getsockname failed (%m)");
1103 1.1 christos return NULL;
1104 1.1 christos }
1105 1.1 christos
1106 1.1 christos switch (lss.ss_family) {
1107 1.1 christos case AF_INET:
1108 1.1 christos cr->c_port = ntohs(((struct sockaddr_in *)&lss)->sin_port);
1109 1.1 christos if (conf_handle_inet(fd, &lss, cr) == -1)
1110 1.1 christos return NULL;
1111 1.1 christos break;
1112 1.1 christos case AF_INET6:
1113 1.1 christos cr->c_port = ntohs(((struct sockaddr_in6 *)&lss)->sin6_port);
1114 1.1 christos if (conf_handle_inet(fd, &lss, cr) == -1)
1115 1.1 christos return NULL;
1116 1.1 christos break;
1117 1.1 christos #ifdef AF_ROUTE
1118 1.1 christos case AF_ROUTE:
1119 1.1 christos if (!conf_route_perm(fd)) {
1120 1.1 christos (*lfun)(LOG_ERR,
1121 1.1 christos "permission denied to routing socket (%m)");
1122 1.1 christos return NULL;
1123 1.1 christos }
1124 1.1 christos cr->c_proto = FSTAR;
1125 1.1 christos cr->c_port = FSTAR;
1126 1.1 christos memcpy(&lss, rss, sizeof(lss));
1127 1.1 christos break;
1128 1.1 christos #endif
1129 1.1 christos default:
1130 1.1 christos (*lfun)(LOG_ERR, "unsupported family %d", lss.ss_family);
1131 1.1 christos return NULL;
1132 1.1 christos }
1133 1.1 christos
1134 1.1 christos cr->c_ss = lss;
1135 1.1 christos cr->c_lmask = FSTAR;
1136 1.1 christos cr->c_uid = (int)uid;
1137 1.1 christos cr->c_family = lss.ss_family;
1138 1.1 christos cr->c_name[0] = '\0';
1139 1.1 christos cr->c_rmask = FSTAR;
1140 1.1 christos cr->c_nfail = FSTAR;
1141 1.1 christos cr->c_duration = FSTAR;
1142 1.1 christos
1143 1.1 christos if (debug)
1144 1.1 christos (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf),
1145 1.1 christos "look:\t", "", cr));
1146 1.1 christos
1147 1.1 christos /* match the local config */
1148 1.1 christos i = confset_match(&lconf, cr, conf_apply);
1149 1.1 christos if (i == lconf.cs_n) {
1150 1.1 christos if (debug)
1151 1.1 christos (*lfun)(LOG_DEBUG, "not found");
1152 1.1 christos return NULL;
1153 1.1 christos }
1154 1.1 christos
1155 1.1 christos conf_addr_set(cr, rss);
1156 1.1 christos /* match the remote config */
1157 1.1 christos confset_match(&rconf, cr, conf_merge);
1158 1.1 christos /* to apply the mask */
1159 1.1 christos conf_addr_set(cr, &cr->c_ss);
1160 1.1 christos
1161 1.1 christos return cr;
1162 1.1 christos }
1163 1.1 christos
1164 1.1 christos
1165 1.1 christos void
1166 1.1 christos conf_parse(const char *f)
1167 1.1 christos {
1168 1.1 christos FILE *fp;
1169 1.1 christos char *line;
1170 1.1 christos size_t lineno, len;
1171 1.1 christos struct confset lc, rc, *cs;
1172 1.1 christos
1173 1.1 christos if ((fp = fopen(f, "r")) == NULL) {
1174 1.1 christos (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__, f);
1175 1.1 christos return;
1176 1.1 christos }
1177 1.1 christos
1178 1.1 christos lineno = 1;
1179 1.1 christos
1180 1.1 christos confset_init(&rc);
1181 1.1 christos confset_init(&lc);
1182 1.1 christos cs = &lc;
1183 1.1 christos for (; (line = fparseln(fp, &len, &lineno, NULL, 0)) != NULL;
1184 1.1 christos free(line))
1185 1.1 christos {
1186 1.1 christos if (!*line)
1187 1.1 christos continue;
1188 1.1 christos if (strcmp(line, "[local]") == 0) {
1189 1.1 christos cs = &lc;
1190 1.1 christos continue;
1191 1.1 christos }
1192 1.1 christos if (strcmp(line, "[remote]") == 0) {
1193 1.1 christos cs = &rc;
1194 1.1 christos continue;
1195 1.1 christos }
1196 1.1 christos
1197 1.1 christos if (confset_full(cs)) {
1198 1.1 christos if (confset_grow(cs) == -1) {
1199 1.1 christos confset_free(&lc);
1200 1.1 christos confset_free(&rc);
1201 1.1 christos fclose(fp);
1202 1.1 christos free(line);
1203 1.1 christos return;
1204 1.1 christos }
1205 1.1 christos }
1206 1.1 christos if (conf_parseline(f, lineno, line, confset_get(cs),
1207 1.1 christos cs == &lc) == -1)
1208 1.1 christos continue;
1209 1.1 christos confset_add(cs);
1210 1.1 christos }
1211 1.1 christos
1212 1.1 christos fclose(fp);
1213 1.1 christos confset_sort(&lc);
1214 1.1 christos confset_sort(&rc);
1215 1.1 christos
1216 1.1 christos confset_replace(&rconf, &rc);
1217 1.1 christos confset_replace(&lconf, &lc);
1218 1.1 christos
1219 1.1 christos if (debug) {
1220 1.1 christos confset_list(&lconf, "local", "target");
1221 1.1 christos confset_list(&rconf, "remote", "source");
1222 1.1 christos }
1223 1.1 christos }
1224