conf.c revision 1.7 1 1.7 christos /* $NetBSD: conf.c,v 1.7 2025/02/05 20:09:33 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.7 christos __RCSID("$NetBSD: conf.c,v 1.7 2025/02/05 20:09:33 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.4 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.6 christos if (!*pstr)
273 1.6 christos pstr = "*";
274 1.1 christos } else if (pstr != p || strchr(p, '.') || conf_is_interface(p)) {
275 1.1 christos if (pstr == p)
276 1.1 christos pstr = "*";
277 1.1 christos struct sockaddr_in *sin = (void *)&c->c_ss;
278 1.1 christos struct sockaddr_if *sif = (void *)&c->c_ss;
279 1.1 christos if (debug)
280 1.1 christos (*lfun)(LOG_DEBUG, "%s: host4 %s", __func__, p);
281 1.1 christos if (strcmp(p, "*") != 0) {
282 1.1 christos if (conf_is_interface(p)) {
283 1.1 christos if (!local)
284 1.1 christos goto out2;
285 1.1 christos if (debug)
286 1.1 christos (*lfun)(LOG_DEBUG, "%s: interface %s",
287 1.1 christos __func__, p);
288 1.1 christos if (c->c_lmask != FSTAR)
289 1.1 christos goto out1;
290 1.1 christos sif->sif_family = AF_MAX;
291 1.1 christos strlcpy(sif->sif_name, p,
292 1.1 christos sizeof(sif->sif_name));
293 1.1 christos #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
294 1.1 christos sif->sif_len = sizeof(*sif);
295 1.1 christos #endif
296 1.1 christos port = &sif->sif_port;
297 1.1 christos } else if (inet_pton(AF_INET, p, &sin->sin_addr) != -1)
298 1.1 christos {
299 1.1 christos sin->sin_family = AF_INET;
300 1.1 christos #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
301 1.1 christos sin->sin_len = sizeof(*sin);
302 1.1 christos #endif
303 1.1 christos port = &sin->sin_port;
304 1.1 christos } else
305 1.1 christos goto out;
306 1.1 christos }
307 1.1 christos }
308 1.1 christos
309 1.1 christos if (conf_getport(f, l, local, &c->c_port, pstr) == -1)
310 1.1 christos return -1;
311 1.1 christos
312 1.1 christos if (port && c->c_port != FSTAR && c->c_port != FEQUAL)
313 1.5 christos *port = htons((in_port_t)c->c_port);
314 1.1 christos return 0;
315 1.1 christos out:
316 1.4 christos (*lfun)(LOG_ERR, "%s: %s, %zu: Bad address [%s]", __func__, f, l, p);
317 1.1 christos return -1;
318 1.1 christos out1:
319 1.1 christos (*lfun)(LOG_ERR, "%s: %s, %zu: Can't specify mask %d with "
320 1.1 christos "interface [%s]", __func__, f, l, c->c_lmask, p);
321 1.1 christos return -1;
322 1.1 christos out2:
323 1.1 christos (*lfun)(LOG_ERR, "%s: %s, %zu: Interface spec does not make sense "
324 1.1 christos "with remote config [%s]", __func__, f, l, p);
325 1.1 christos return -1;
326 1.1 christos }
327 1.1 christos
328 1.1 christos static int
329 1.1 christos conf_getproto(const char *f, size_t l, bool local __unused, struct conf *c,
330 1.1 christos const char *p)
331 1.1 christos {
332 1.1 christos if (strcmp(p, "stream") == 0) {
333 1.1 christos c->c_proto = IPPROTO_TCP;
334 1.1 christos return 0;
335 1.1 christos }
336 1.1 christos if (strcmp(p, "dgram") == 0) {
337 1.1 christos c->c_proto = IPPROTO_UDP;
338 1.1 christos return 0;
339 1.1 christos }
340 1.1 christos return conf_getnum(f, l, local, &c->c_proto, "protocol", p);
341 1.1 christos }
342 1.1 christos
343 1.1 christos static int
344 1.1 christos conf_getfamily(const char *f, size_t l, bool local __unused, struct conf *c,
345 1.1 christos const char *p)
346 1.1 christos {
347 1.1 christos if (strncmp(p, "tcp", 3) == 0 || strncmp(p, "udp", 3) == 0) {
348 1.1 christos c->c_family = p[3] == '6' ? AF_INET6 : AF_INET;
349 1.1 christos return 0;
350 1.1 christos }
351 1.1 christos return conf_getnum(f, l, local, &c->c_family, "family", p);
352 1.1 christos }
353 1.1 christos
354 1.1 christos static int
355 1.1 christos conf_getuid(const char *f, size_t l, bool local __unused, struct conf *c,
356 1.1 christos const char *p)
357 1.1 christos {
358 1.1 christos struct passwd *pw;
359 1.1 christos
360 1.1 christos if ((pw = getpwnam(p)) != NULL) {
361 1.1 christos c->c_uid = (int)pw->pw_uid;
362 1.1 christos return 0;
363 1.1 christos }
364 1.1 christos
365 1.1 christos return conf_getnum(f, l, local, &c->c_uid, "user", p);
366 1.1 christos }
367 1.1 christos
368 1.1 christos
369 1.1 christos static int
370 1.1 christos conf_getname(const char *f, size_t l, bool local, struct conf *c,
371 1.1 christos const char *p)
372 1.1 christos {
373 1.1 christos if (conf_getmask(f, l, local, &p, &c->c_rmask) == -1)
374 1.1 christos return -1;
375 1.1 christos
376 1.1 christos if (strcmp(p, "*") == 0) {
377 1.1 christos strlcpy(c->c_name, rulename, CONFNAMESZ);
378 1.1 christos return 0;
379 1.1 christos }
380 1.1 christos
381 1.1 christos if (strcmp(p, "=") == 0) {
382 1.1 christos if (local)
383 1.1 christos goto out;
384 1.1 christos c->c_name[0] = '\0';
385 1.1 christos return 0;
386 1.1 christos }
387 1.1 christos
388 1.1 christos snprintf(c->c_name, CONFNAMESZ, "%s%s", *p == '-' ? rulename : "", p);
389 1.1 christos return 0;
390 1.1 christos out:
391 1.1 christos (*lfun)(LOG_ERR, "%s: %s, %zu: `=' name not allowed in local"
392 1.1 christos " config", __func__, f, l);
393 1.1 christos return -1;
394 1.1 christos }
395 1.1 christos
396 1.1 christos static int
397 1.1 christos getvalue(const char *f, size_t l, bool local, void *r, char **p,
398 1.1 christos int (*fun)(const char *, size_t, bool, struct conf *, const char *))
399 1.1 christos {
400 1.1 christos char *ep = *p;
401 1.1 christos
402 1.1 christos advance(p);
403 1.1 christos return (*fun)(f, l, local, r, ep);
404 1.1 christos }
405 1.1 christos
406 1.1 christos
407 1.1 christos static int
408 1.1 christos conf_parseline(const char *f, size_t l, char *p, struct conf *c, bool local)
409 1.1 christos {
410 1.1 christos int e;
411 1.1 christos
412 1.7 christos c->c_lineno = l;
413 1.7 christos
414 1.1 christos while (*p && isspace((unsigned char)*p))
415 1.1 christos p++;
416 1.1 christos
417 1.1 christos memset(c, 0, sizeof(*c));
418 1.1 christos e = getvalue(f, l, local, c, &p, conf_gethostport);
419 1.1 christos if (e) return -1;
420 1.1 christos e = getvalue(f, l, local, c, &p, conf_getproto);
421 1.1 christos if (e) return -1;
422 1.1 christos e = getvalue(f, l, local, c, &p, conf_getfamily);
423 1.1 christos if (e) return -1;
424 1.1 christos e = getvalue(f, l, local, c, &p, conf_getuid);
425 1.1 christos if (e) return -1;
426 1.1 christos e = getvalue(f, l, local, c, &p, conf_getname);
427 1.1 christos if (e) return -1;
428 1.1 christos e = getvalue(f, l, local, c, &p, conf_getnfail);
429 1.1 christos if (e) return -1;
430 1.1 christos e = getvalue(f, l, local, c, &p, conf_getsecs);
431 1.1 christos if (e) return -1;
432 1.1 christos
433 1.1 christos return 0;
434 1.1 christos }
435 1.1 christos
436 1.1 christos static int
437 1.1 christos conf_sort(const void *v1, const void *v2)
438 1.1 christos {
439 1.1 christos const struct conf *c1 = v1;
440 1.1 christos const struct conf *c2 = v2;
441 1.1 christos
442 1.1 christos #define CMP(a, b, f) \
443 1.1 christos if ((a)->f > (b)->f) return -1; \
444 1.1 christos else if ((a)->f < (b)->f) return 1
445 1.1 christos
446 1.1 christos CMP(c1, c2, c_ss.ss_family);
447 1.1 christos CMP(c1, c2, c_lmask);
448 1.1 christos CMP(c1, c2, c_port);
449 1.1 christos CMP(c1, c2, c_proto);
450 1.1 christos CMP(c1, c2, c_family);
451 1.1 christos CMP(c1, c2, c_rmask);
452 1.1 christos CMP(c1, c2, c_uid);
453 1.1 christos #undef CMP
454 1.1 christos return 0;
455 1.1 christos }
456 1.1 christos
457 1.1 christos static int
458 1.1 christos conf_is_interface(const char *name)
459 1.1 christos {
460 1.1 christos const struct ifaddrs *ifa;
461 1.1 christos
462 1.1 christos for (ifa = ifas; ifa; ifa = ifa->ifa_next)
463 1.1 christos if (strcmp(ifa->ifa_name, name) == 0)
464 1.1 christos return 1;
465 1.1 christos return 0;
466 1.1 christos }
467 1.1 christos
468 1.1 christos #define MASK(m) ((uint32_t)~((1 << (32 - (m))) - 1))
469 1.1 christos
470 1.1 christos static int
471 1.1 christos conf_amask_eq(const void *v1, const void *v2, size_t len, int mask)
472 1.1 christos {
473 1.1 christos const uint32_t *a1 = v1;
474 1.1 christos const uint32_t *a2 = v2;
475 1.1 christos uint32_t m;
476 1.1 christos int omask = mask;
477 1.1 christos
478 1.1 christos switch (mask) {
479 1.1 christos case FSTAR:
480 1.1 christos if (memcmp(v1, v2, len) == 0)
481 1.1 christos return 1;
482 1.1 christos goto out;
483 1.1 christos case FEQUAL:
484 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__,
485 1.1 christos mask);
486 1.1 christos abort();
487 1.1 christos default:
488 1.1 christos break;
489 1.1 christos }
490 1.1 christos
491 1.3 christos for (size_t i = 0; i < (len >> 2); i++) {
492 1.1 christos if (mask > 32) {
493 1.1 christos m = htonl((uint32_t)~0);
494 1.1 christos mask -= 32;
495 1.1 christos } else if (mask) {
496 1.1 christos m = htonl(MASK(mask));
497 1.1 christos mask = 0;
498 1.1 christos } else
499 1.1 christos return 1;
500 1.1 christos if ((a1[i] & m) != (a2[i] & m))
501 1.1 christos goto out;
502 1.1 christos }
503 1.1 christos return 1;
504 1.1 christos out:
505 1.1 christos if (debug > 1) {
506 1.1 christos char b1[256], b2[256];
507 1.1 christos blhexdump(b1, sizeof(b1), "a1", v1, len);
508 1.1 christos blhexdump(b2, sizeof(b2), "a2", v2, len);
509 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s != %s [0x%x]", __func__,
510 1.1 christos b1, b2, omask);
511 1.1 christos }
512 1.1 christos return 0;
513 1.1 christos }
514 1.1 christos
515 1.1 christos /*
516 1.1 christos * Apply the mask to the given address
517 1.1 christos */
518 1.1 christos static void
519 1.1 christos conf_apply_mask(void *v, size_t len, int mask)
520 1.1 christos {
521 1.1 christos uint32_t *a = v;
522 1.1 christos uint32_t m;
523 1.1 christos
524 1.1 christos switch (mask) {
525 1.1 christos case FSTAR:
526 1.1 christos return;
527 1.1 christos case FEQUAL:
528 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__,
529 1.1 christos mask);
530 1.1 christos abort();
531 1.1 christos default:
532 1.1 christos break;
533 1.1 christos }
534 1.1 christos len >>= 2;
535 1.1 christos
536 1.1 christos for (size_t i = 0; i < len; i++) {
537 1.1 christos if (mask > 32) {
538 1.1 christos m = htonl((uint32_t)~0);
539 1.1 christos mask -= 32;
540 1.1 christos } else if (mask) {
541 1.1 christos m = htonl(MASK(mask));
542 1.1 christos mask = 0;
543 1.1 christos } else
544 1.1 christos m = 0;
545 1.1 christos a[i] &= m;
546 1.1 christos }
547 1.1 christos }
548 1.1 christos
549 1.1 christos /*
550 1.1 christos * apply the mask and the port to the address given
551 1.1 christos */
552 1.1 christos static void
553 1.1 christos conf_addr_set(struct conf *c, const struct sockaddr_storage *ss)
554 1.1 christos {
555 1.1 christos struct sockaddr_in *sin;
556 1.1 christos struct sockaddr_in6 *sin6;
557 1.1 christos in_port_t *port;
558 1.1 christos void *addr;
559 1.1 christos size_t alen;
560 1.1 christos
561 1.1 christos c->c_lmask = c->c_rmask;
562 1.1 christos c->c_ss = *ss;
563 1.1 christos
564 1.1 christos if (c->c_ss.ss_family != c->c_family) {
565 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: mismatched family "
566 1.1 christos "%u != %u", __func__, c->c_ss.ss_family, c->c_family);
567 1.1 christos abort();
568 1.1 christos }
569 1.1 christos
570 1.1 christos switch (c->c_ss.ss_family) {
571 1.1 christos case AF_INET:
572 1.1 christos sin = (void *)&c->c_ss;
573 1.1 christos port = &sin->sin_port;
574 1.1 christos addr = &sin->sin_addr;
575 1.1 christos alen = sizeof(sin->sin_addr);
576 1.1 christos break;
577 1.1 christos case AF_INET6:
578 1.1 christos sin6 = (void *)&c->c_ss;
579 1.1 christos port = &sin6->sin6_port;
580 1.1 christos addr = &sin6->sin6_addr;
581 1.1 christos alen = sizeof(sin6->sin6_addr);
582 1.1 christos break;
583 1.1 christos default:
584 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u",
585 1.1 christos __func__, c->c_ss.ss_family);
586 1.1 christos abort();
587 1.1 christos }
588 1.1 christos
589 1.1 christos *port = htons((in_port_t)c->c_port);
590 1.1 christos conf_apply_mask(addr, alen, c->c_lmask);
591 1.1 christos if (c->c_lmask == FSTAR)
592 1.1 christos c->c_lmask = (int)(alen * 8);
593 1.1 christos if (debug) {
594 1.1 christos char buf[128];
595 1.1 christos sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&c->c_ss);
596 1.1 christos (*lfun)(LOG_DEBUG, "Applied address %s", buf);
597 1.1 christos }
598 1.1 christos }
599 1.1 christos
600 1.1 christos /*
601 1.1 christos * Compared two addresses for equality applying the mask
602 1.1 christos */
603 1.1 christos static int
604 1.1 christos conf_inet_eq(const void *v1, const void *v2, int mask)
605 1.1 christos {
606 1.1 christos const struct sockaddr *sa1 = v1;
607 1.1 christos const struct sockaddr *sa2 = v2;
608 1.1 christos size_t size;
609 1.1 christos
610 1.1 christos if (sa1->sa_family != sa2->sa_family)
611 1.1 christos return 0;
612 1.1 christos
613 1.1 christos switch (sa1->sa_family) {
614 1.1 christos case AF_INET: {
615 1.1 christos const struct sockaddr_in *s1 = v1;
616 1.1 christos const struct sockaddr_in *s2 = v2;
617 1.1 christos size = sizeof(s1->sin_addr);
618 1.1 christos v1 = &s1->sin_addr;
619 1.1 christos v2 = &s2->sin_addr;
620 1.1 christos break;
621 1.1 christos }
622 1.1 christos
623 1.1 christos case AF_INET6: {
624 1.1 christos const struct sockaddr_in6 *s1 = v1;
625 1.1 christos const struct sockaddr_in6 *s2 = v2;
626 1.1 christos size = sizeof(s1->sin6_addr);
627 1.1 christos v1 = &s1->sin6_addr;
628 1.1 christos v2 = &s2->sin6_addr;
629 1.1 christos break;
630 1.1 christos }
631 1.1 christos
632 1.1 christos default:
633 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u",
634 1.1 christos __func__, sa1->sa_family);
635 1.1 christos abort();
636 1.1 christos }
637 1.1 christos
638 1.1 christos return conf_amask_eq(v1, v2, size, mask);
639 1.1 christos }
640 1.1 christos
641 1.1 christos static int
642 1.1 christos conf_addr_in_interface(const struct sockaddr_storage *s1,
643 1.1 christos const struct sockaddr_storage *s2, int mask)
644 1.1 christos {
645 1.1 christos const char *name = SIF_NAME(s2);
646 1.1 christos const struct ifaddrs *ifa;
647 1.1 christos
648 1.1 christos for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
649 1.1 christos if ((ifa->ifa_flags & IFF_UP) == 0)
650 1.1 christos continue;
651 1.1 christos
652 1.1 christos if (strcmp(ifa->ifa_name, name) != 0)
653 1.1 christos continue;
654 1.1 christos
655 1.1 christos if (s1->ss_family != ifa->ifa_addr->sa_family)
656 1.1 christos continue;
657 1.1 christos
658 1.1 christos bool eq;
659 1.1 christos switch (s1->ss_family) {
660 1.1 christos case AF_INET:
661 1.1 christos case AF_INET6:
662 1.1 christos eq = conf_inet_eq(ifa->ifa_addr, s1, mask);
663 1.1 christos break;
664 1.1 christos default:
665 1.1 christos (*lfun)(LOG_ERR, "Bad family %u", s1->ss_family);
666 1.1 christos continue;
667 1.1 christos }
668 1.1 christos if (eq)
669 1.1 christos return 1;
670 1.1 christos }
671 1.1 christos return 0;
672 1.1 christos }
673 1.1 christos
674 1.1 christos static int
675 1.1 christos conf_addr_eq(const struct sockaddr_storage *s1,
676 1.1 christos const struct sockaddr_storage *s2, int mask)
677 1.1 christos {
678 1.1 christos switch (s2->ss_family) {
679 1.1 christos case 0:
680 1.1 christos return 1;
681 1.1 christos case AF_MAX:
682 1.1 christos return conf_addr_in_interface(s1, s2, mask);
683 1.1 christos case AF_INET:
684 1.1 christos case AF_INET6:
685 1.1 christos return conf_inet_eq(s1, s2, mask);
686 1.1 christos default:
687 1.1 christos (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u",
688 1.1 christos __func__, s1->ss_family);
689 1.1 christos abort();
690 1.1 christos }
691 1.1 christos }
692 1.1 christos
693 1.1 christos static int
694 1.1 christos conf_eq(const struct conf *c1, const struct conf *c2)
695 1.1 christos {
696 1.1 christos
697 1.1 christos if (!conf_addr_eq(&c1->c_ss, &c2->c_ss, c2->c_lmask))
698 1.1 christos return 0;
699 1.1 christos
700 1.1 christos #define CMP(a, b, f) \
701 1.1 christos if ((a)->f != (b)->f && (b)->f != FSTAR && (b)->f != FEQUAL) { \
702 1.1 christos if (debug > 1) \
703 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s fail %d != %d", __func__, \
704 1.1 christos __STRING(f), (a)->f, (b)->f); \
705 1.1 christos return 0; \
706 1.1 christos }
707 1.1 christos CMP(c1, c2, c_port);
708 1.1 christos CMP(c1, c2, c_proto);
709 1.1 christos CMP(c1, c2, c_family);
710 1.1 christos CMP(c1, c2, c_uid);
711 1.1 christos #undef CMP
712 1.1 christos return 1;
713 1.1 christos }
714 1.1 christos
715 1.1 christos static const char *
716 1.1 christos conf_num(char *b, size_t l, int n)
717 1.1 christos {
718 1.1 christos switch (n) {
719 1.1 christos case FSTAR:
720 1.1 christos return "*";
721 1.1 christos case FEQUAL:
722 1.1 christos return "=";
723 1.1 christos default:
724 1.1 christos snprintf(b, l, "%d", n);
725 1.1 christos return b;
726 1.1 christos }
727 1.1 christos }
728 1.1 christos
729 1.1 christos static const char *
730 1.1 christos fmtname(const char *n) {
731 1.1 christos size_t l = strlen(rulename);
732 1.1 christos if (l == 0)
733 1.1 christos return "*";
734 1.1 christos if (strncmp(n, rulename, l) == 0) {
735 1.1 christos if (n[l] != '\0')
736 1.1 christos return n + l;
737 1.1 christos else
738 1.1 christos return "*";
739 1.1 christos } else if (!*n)
740 1.1 christos return "=";
741 1.1 christos else
742 1.1 christos return n;
743 1.1 christos }
744 1.1 christos
745 1.1 christos static void
746 1.1 christos fmtport(char *b, size_t l, int port)
747 1.1 christos {
748 1.1 christos char buf[128];
749 1.1 christos
750 1.1 christos if (port == FSTAR)
751 1.1 christos return;
752 1.1 christos
753 1.1 christos if (b[0] == '\0' || strcmp(b, "*") == 0)
754 1.1 christos snprintf(b, l, "%d", port);
755 1.1 christos else {
756 1.1 christos snprintf(buf, sizeof(buf), ":%d", port);
757 1.1 christos strlcat(b, buf, l);
758 1.1 christos }
759 1.1 christos }
760 1.1 christos
761 1.1 christos static const char *
762 1.1 christos fmtmask(char *b, size_t l, int fam, int mask)
763 1.1 christos {
764 1.1 christos char buf[128];
765 1.1 christos
766 1.1 christos switch (mask) {
767 1.1 christos case FSTAR:
768 1.1 christos return "";
769 1.1 christos case FEQUAL:
770 1.1 christos if (strcmp(b, "=") == 0)
771 1.1 christos return "";
772 1.1 christos else {
773 1.1 christos strlcat(b, "/=", l);
774 1.1 christos return b;
775 1.1 christos }
776 1.1 christos default:
777 1.1 christos break;
778 1.1 christos }
779 1.1 christos
780 1.1 christos switch (fam) {
781 1.1 christos case AF_INET:
782 1.1 christos if (mask == 32)
783 1.1 christos return "";
784 1.1 christos break;
785 1.1 christos case AF_INET6:
786 1.1 christos if (mask == 128)
787 1.1 christos return "";
788 1.1 christos break;
789 1.1 christos default:
790 1.1 christos break;
791 1.1 christos }
792 1.1 christos
793 1.1 christos snprintf(buf, sizeof(buf), "/%d", mask);
794 1.1 christos strlcat(b, buf, l);
795 1.1 christos return b;
796 1.1 christos }
797 1.1 christos
798 1.1 christos static const char *
799 1.1 christos conf_namemask(char *b, size_t l, const struct conf *c)
800 1.1 christos {
801 1.1 christos strlcpy(b, fmtname(c->c_name), l);
802 1.1 christos fmtmask(b, l, c->c_family, c->c_rmask);
803 1.1 christos return b;
804 1.1 christos }
805 1.1 christos
806 1.1 christos const char *
807 1.1 christos conf_print(char *buf, size_t len, const char *pref, const char *delim,
808 1.1 christos const struct conf *c)
809 1.1 christos {
810 1.1 christos char ha[128], hb[32], b[5][64];
811 1.1 christos int sp;
812 1.1 christos
813 1.1 christos #define N(n, v) conf_num(b[n], sizeof(b[n]), (v))
814 1.1 christos
815 1.1 christos switch (c->c_ss.ss_family) {
816 1.1 christos case 0:
817 1.1 christos snprintf(ha, sizeof(ha), "*");
818 1.1 christos break;
819 1.1 christos case AF_MAX:
820 1.1 christos snprintf(ha, sizeof(ha), "%s", SIF_NAME(&c->c_ss));
821 1.1 christos break;
822 1.1 christos default:
823 1.1 christos sockaddr_snprintf(ha, sizeof(ha), "%a", (const void *)&c->c_ss);
824 1.1 christos break;
825 1.1 christos }
826 1.1 christos
827 1.1 christos fmtmask(ha, sizeof(ha), c->c_family, c->c_lmask);
828 1.1 christos fmtport(ha, sizeof(ha), c->c_port);
829 1.1 christos
830 1.1 christos sp = *delim == '\t' ? 20 : -1;
831 1.1 christos hb[0] = '\0';
832 1.1 christos if (*delim)
833 1.1 christos snprintf(buf, len, "%s%*.*s%s%s%s" "%s%s%s%s"
834 1.1 christos "%s%s" "%s%s%s",
835 1.1 christos pref, sp, sp, ha, delim, N(0, c->c_proto), delim,
836 1.1 christos N(1, c->c_family), delim, N(2, c->c_uid), delim,
837 1.1 christos conf_namemask(hb, sizeof(hb), c), delim,
838 1.1 christos N(3, c->c_nfail), delim, N(4, c->c_duration));
839 1.1 christos else
840 1.1 christos snprintf(buf, len, "%starget:%s, proto:%s, family:%s, "
841 1.1 christos "uid:%s, name:%s, nfail:%s, duration:%s", pref,
842 1.1 christos ha, N(0, c->c_proto), N(1, c->c_family), N(2, c->c_uid),
843 1.1 christos conf_namemask(hb, sizeof(hb), c),
844 1.1 christos N(3, c->c_nfail), N(4, c->c_duration));
845 1.1 christos return buf;
846 1.1 christos }
847 1.1 christos
848 1.1 christos /*
849 1.1 christos * Apply the local config match to the result
850 1.1 christos */
851 1.1 christos static void
852 1.1 christos conf_apply(struct conf *c, const struct conf *sc)
853 1.1 christos {
854 1.1 christos char buf[BUFSIZ];
855 1.1 christos
856 1.1 christos if (debug) {
857 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
858 1.1 christos conf_print(buf, sizeof(buf), "merge:\t", "", sc));
859 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
860 1.1 christos conf_print(buf, sizeof(buf), "to:\t", "", c));
861 1.1 christos }
862 1.1 christos memcpy(c->c_name, sc->c_name, CONFNAMESZ);
863 1.1 christos c->c_uid = sc->c_uid;
864 1.1 christos c->c_rmask = sc->c_rmask;
865 1.1 christos c->c_nfail = sc->c_nfail;
866 1.1 christos c->c_duration = sc->c_duration;
867 1.1 christos
868 1.1 christos if (debug)
869 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
870 1.1 christos conf_print(buf, sizeof(buf), "result:\t", "", c));
871 1.1 christos }
872 1.1 christos
873 1.1 christos /*
874 1.1 christos * Merge a remote configuration to the result
875 1.1 christos */
876 1.1 christos static void
877 1.1 christos conf_merge(struct conf *c, const struct conf *sc)
878 1.1 christos {
879 1.1 christos char buf[BUFSIZ];
880 1.1 christos
881 1.1 christos if (debug) {
882 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
883 1.1 christos conf_print(buf, sizeof(buf), "merge:\t", "", sc));
884 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
885 1.1 christos conf_print(buf, sizeof(buf), "to:\t", "", c));
886 1.1 christos }
887 1.1 christos
888 1.1 christos if (sc->c_name[0])
889 1.1 christos memcpy(c->c_name, sc->c_name, CONFNAMESZ);
890 1.1 christos if (sc->c_uid != FEQUAL)
891 1.1 christos c->c_uid = sc->c_uid;
892 1.1 christos if (sc->c_rmask != FEQUAL)
893 1.1 christos c->c_lmask = c->c_rmask = sc->c_rmask;
894 1.1 christos if (sc->c_nfail != FEQUAL)
895 1.1 christos c->c_nfail = sc->c_nfail;
896 1.1 christos if (sc->c_duration != FEQUAL)
897 1.1 christos c->c_duration = sc->c_duration;
898 1.1 christos if (debug)
899 1.1 christos (*lfun)(LOG_DEBUG, "%s: %s", __func__,
900 1.1 christos conf_print(buf, sizeof(buf), "result:\t", "", c));
901 1.1 christos }
902 1.1 christos
903 1.1 christos static void
904 1.1 christos confset_init(struct confset *cs)
905 1.1 christos {
906 1.1 christos cs->cs_c = NULL;
907 1.1 christos cs->cs_n = 0;
908 1.1 christos cs->cs_m = 0;
909 1.1 christos }
910 1.1 christos
911 1.1 christos static int
912 1.1 christos confset_grow(struct confset *cs)
913 1.1 christos {
914 1.1 christos void *tc;
915 1.1 christos
916 1.1 christos cs->cs_m += 10;
917 1.1 christos tc = realloc(cs->cs_c, cs->cs_m * sizeof(*cs->cs_c));
918 1.1 christos if (tc == NULL) {
919 1.1 christos (*lfun)(LOG_ERR, "%s: Can't grow confset (%m)", __func__);
920 1.1 christos return -1;
921 1.1 christos }
922 1.1 christos cs->cs_c = tc;
923 1.1 christos return 0;
924 1.1 christos }
925 1.1 christos
926 1.1 christos static struct conf *
927 1.1 christos confset_get(struct confset *cs)
928 1.1 christos {
929 1.1 christos return &cs->cs_c[cs->cs_n];
930 1.1 christos }
931 1.1 christos
932 1.1 christos static bool
933 1.1 christos confset_full(const struct confset *cs)
934 1.1 christos {
935 1.1 christos return cs->cs_n == cs->cs_m;
936 1.1 christos }
937 1.1 christos
938 1.1 christos static void
939 1.1 christos confset_sort(struct confset *cs)
940 1.1 christos {
941 1.1 christos qsort(cs->cs_c, cs->cs_n, sizeof(*cs->cs_c), conf_sort);
942 1.1 christos }
943 1.1 christos
944 1.1 christos static void
945 1.1 christos confset_add(struct confset *cs)
946 1.1 christos {
947 1.1 christos cs->cs_n++;
948 1.1 christos }
949 1.1 christos
950 1.1 christos static void
951 1.1 christos confset_free(struct confset *cs)
952 1.1 christos {
953 1.1 christos free(cs->cs_c);
954 1.1 christos confset_init(cs);
955 1.1 christos }
956 1.1 christos
957 1.1 christos static void
958 1.1 christos confset_replace(struct confset *dc, struct confset *sc)
959 1.1 christos {
960 1.1 christos struct confset tc;
961 1.1 christos tc = *dc;
962 1.1 christos *dc = *sc;
963 1.1 christos confset_init(sc);
964 1.1 christos confset_free(&tc);
965 1.1 christos }
966 1.1 christos
967 1.1 christos static void
968 1.1 christos confset_list(const struct confset *cs, const char *msg, const char *where)
969 1.1 christos {
970 1.1 christos char buf[BUFSIZ];
971 1.1 christos
972 1.1 christos (*lfun)(LOG_DEBUG, "[%s]", msg);
973 1.1 christos (*lfun)(LOG_DEBUG, "%20.20s\ttype\tproto\towner\tname\tnfail\tduration",
974 1.1 christos where);
975 1.1 christos for (size_t i = 0; i < cs->cs_n; i++)
976 1.1 christos (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), "", "\t",
977 1.1 christos &cs->cs_c[i]));
978 1.1 christos }
979 1.1 christos
980 1.1 christos /*
981 1.1 christos * Match a configuration against the given list and apply the function
982 1.1 christos * to it, returning the matched entry number.
983 1.1 christos */
984 1.1 christos static size_t
985 1.1 christos confset_match(const struct confset *cs, struct conf *c,
986 1.1 christos void (*fun)(struct conf *, const struct conf *))
987 1.1 christos {
988 1.1 christos char buf[BUFSIZ];
989 1.1 christos size_t i;
990 1.1 christos
991 1.1 christos for (i = 0; i < cs->cs_n; i++) {
992 1.1 christos if (debug)
993 1.1 christos (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf),
994 1.1 christos "check:\t", "", &cs->cs_c[i]));
995 1.1 christos if (conf_eq(c, &cs->cs_c[i])) {
996 1.1 christos if (debug)
997 1.1 christos (*lfun)(LOG_DEBUG, "%s",
998 1.1 christos conf_print(buf, sizeof(buf),
999 1.1 christos "found:\t", "", &cs->cs_c[i]));
1000 1.1 christos (*fun)(c, &cs->cs_c[i]);
1001 1.1 christos break;
1002 1.1 christos }
1003 1.1 christos }
1004 1.1 christos return i;
1005 1.1 christos }
1006 1.1 christos
1007 1.1 christos #ifdef AF_ROUTE
1008 1.1 christos static int
1009 1.1 christos conf_route_perm(int fd) {
1010 1.1 christos #if defined(RTM_IFANNOUNCE) && defined(RT_ROUNDUP)
1011 1.1 christos /*
1012 1.1 christos * Send a routing message that is not supported to check for access
1013 1.1 christos * We expect EOPNOTSUPP for having access, since we are sending a
1014 1.1 christos * request the system does not understand and EACCES if we don't have
1015 1.1 christos * access.
1016 1.1 christos */
1017 1.1 christos static struct sockaddr_in sin = {
1018 1.1 christos #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1019 1.1 christos .sin_len = sizeof(sin),
1020 1.1 christos #endif
1021 1.1 christos .sin_family = AF_INET,
1022 1.1 christos };
1023 1.1 christos char buf[4096];
1024 1.1 christos struct rt_msghdr *rtm = (void *)buf;
1025 1.1 christos char *cp = (char *)(rtm + 1);
1026 1.1 christos size_t l;
1027 1.1 christos
1028 1.1 christos #define NEXTADDR(s) \
1029 1.1 christos l = RT_ROUNDUP(sizeof(*s)); memmove(cp, s, l); cp += l;
1030 1.1 christos memset(buf, 0, sizeof(buf));
1031 1.1 christos rtm->rtm_type = RTM_IFANNOUNCE;
1032 1.1 christos rtm->rtm_flags = 0;
1033 1.1 christos rtm->rtm_addrs = RTA_DST|RTA_GATEWAY;
1034 1.1 christos rtm->rtm_version = RTM_VERSION;
1035 1.1 christos rtm->rtm_seq = 666;
1036 1.1 christos NEXTADDR(&sin);
1037 1.1 christos NEXTADDR(&sin);
1038 1.1 christos rtm->rtm_msglen = (u_short)((char *)cp - (char *)rtm);
1039 1.1 christos if (write(fd, rtm, rtm->rtm_msglen) != -1) {
1040 1.1 christos (*lfun)(LOG_ERR, "Writing to routing socket succeeded!");
1041 1.1 christos return 0;
1042 1.1 christos }
1043 1.1 christos switch (errno) {
1044 1.1 christos case EACCES:
1045 1.1 christos return 0;
1046 1.1 christos case EOPNOTSUPP:
1047 1.1 christos return 1;
1048 1.1 christos default:
1049 1.1 christos (*lfun)(LOG_ERR,
1050 1.1 christos "Unexpected error writing to routing socket (%m)");
1051 1.1 christos return 0;
1052 1.1 christos }
1053 1.1 christos #else
1054 1.1 christos return 0;
1055 1.1 christos #endif
1056 1.1 christos }
1057 1.1 christos #endif
1058 1.1 christos
1059 1.1 christos static int
1060 1.1 christos conf_handle_inet(int fd, const void *lss, struct conf *cr)
1061 1.1 christos {
1062 1.1 christos char buf[BUFSIZ];
1063 1.1 christos int proto;
1064 1.1 christos socklen_t slen = sizeof(proto);
1065 1.1 christos
1066 1.1 christos if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &proto, &slen) == -1) {
1067 1.1 christos (*lfun)(LOG_ERR, "getsockopt failed (%m)");
1068 1.1 christos return -1;
1069 1.1 christos }
1070 1.1 christos
1071 1.1 christos if (debug) {
1072 1.1 christos sockaddr_snprintf(buf, sizeof(buf), "%a:%p", lss);
1073 1.1 christos (*lfun)(LOG_DEBUG, "listening socket: %s", buf);
1074 1.1 christos }
1075 1.1 christos
1076 1.1 christos switch (proto) {
1077 1.1 christos case SOCK_STREAM:
1078 1.1 christos cr->c_proto = IPPROTO_TCP;
1079 1.1 christos break;
1080 1.1 christos case SOCK_DGRAM:
1081 1.1 christos cr->c_proto = IPPROTO_UDP;
1082 1.1 christos break;
1083 1.1 christos default:
1084 1.1 christos (*lfun)(LOG_ERR, "unsupported protocol %d", proto);
1085 1.1 christos return -1;
1086 1.1 christos }
1087 1.1 christos return 0;
1088 1.1 christos }
1089 1.1 christos
1090 1.1 christos const struct conf *
1091 1.1 christos conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss,
1092 1.1 christos struct conf *cr)
1093 1.1 christos {
1094 1.1 christos socklen_t slen;
1095 1.1 christos struct sockaddr_storage lss;
1096 1.1 christos size_t i;
1097 1.1 christos char buf[BUFSIZ];
1098 1.1 christos
1099 1.1 christos memset(cr, 0, sizeof(*cr));
1100 1.1 christos slen = sizeof(lss);
1101 1.1 christos memset(&lss, 0, slen);
1102 1.1 christos if (getsockname(fd, (void *)&lss, &slen) == -1) {
1103 1.1 christos (*lfun)(LOG_ERR, "getsockname failed (%m)");
1104 1.1 christos return NULL;
1105 1.1 christos }
1106 1.1 christos
1107 1.1 christos switch (lss.ss_family) {
1108 1.1 christos case AF_INET:
1109 1.1 christos cr->c_port = ntohs(((struct sockaddr_in *)&lss)->sin_port);
1110 1.1 christos if (conf_handle_inet(fd, &lss, cr) == -1)
1111 1.1 christos return NULL;
1112 1.1 christos break;
1113 1.1 christos case AF_INET6:
1114 1.1 christos cr->c_port = ntohs(((struct sockaddr_in6 *)&lss)->sin6_port);
1115 1.1 christos if (conf_handle_inet(fd, &lss, cr) == -1)
1116 1.1 christos return NULL;
1117 1.1 christos break;
1118 1.1 christos #ifdef AF_ROUTE
1119 1.1 christos case AF_ROUTE:
1120 1.1 christos if (!conf_route_perm(fd)) {
1121 1.1 christos (*lfun)(LOG_ERR,
1122 1.1 christos "permission denied to routing socket (%m)");
1123 1.1 christos return NULL;
1124 1.1 christos }
1125 1.1 christos cr->c_proto = FSTAR;
1126 1.1 christos cr->c_port = FSTAR;
1127 1.1 christos memcpy(&lss, rss, sizeof(lss));
1128 1.1 christos break;
1129 1.1 christos #endif
1130 1.1 christos default:
1131 1.1 christos (*lfun)(LOG_ERR, "unsupported family %d", lss.ss_family);
1132 1.1 christos return NULL;
1133 1.1 christos }
1134 1.1 christos
1135 1.1 christos cr->c_ss = lss;
1136 1.1 christos cr->c_lmask = FSTAR;
1137 1.1 christos cr->c_uid = (int)uid;
1138 1.1 christos cr->c_family = lss.ss_family;
1139 1.1 christos cr->c_name[0] = '\0';
1140 1.1 christos cr->c_rmask = FSTAR;
1141 1.1 christos cr->c_nfail = FSTAR;
1142 1.1 christos cr->c_duration = FSTAR;
1143 1.1 christos
1144 1.1 christos if (debug)
1145 1.1 christos (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf),
1146 1.1 christos "look:\t", "", cr));
1147 1.1 christos
1148 1.1 christos /* match the local config */
1149 1.1 christos i = confset_match(&lconf, cr, conf_apply);
1150 1.1 christos if (i == lconf.cs_n) {
1151 1.1 christos if (debug)
1152 1.1 christos (*lfun)(LOG_DEBUG, "not found");
1153 1.1 christos return NULL;
1154 1.1 christos }
1155 1.1 christos
1156 1.1 christos conf_addr_set(cr, rss);
1157 1.1 christos /* match the remote config */
1158 1.1 christos confset_match(&rconf, cr, conf_merge);
1159 1.1 christos /* to apply the mask */
1160 1.1 christos conf_addr_set(cr, &cr->c_ss);
1161 1.1 christos
1162 1.1 christos return cr;
1163 1.1 christos }
1164 1.1 christos
1165 1.1 christos
1166 1.1 christos void
1167 1.1 christos conf_parse(const char *f)
1168 1.1 christos {
1169 1.1 christos FILE *fp;
1170 1.1 christos char *line;
1171 1.1 christos size_t lineno, len;
1172 1.1 christos struct confset lc, rc, *cs;
1173 1.1 christos
1174 1.1 christos if ((fp = fopen(f, "r")) == NULL) {
1175 1.1 christos (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__, f);
1176 1.1 christos return;
1177 1.1 christos }
1178 1.1 christos
1179 1.4 christos lineno = 0;
1180 1.1 christos
1181 1.1 christos confset_init(&rc);
1182 1.1 christos confset_init(&lc);
1183 1.1 christos cs = &lc;
1184 1.1 christos for (; (line = fparseln(fp, &len, &lineno, NULL, 0)) != NULL;
1185 1.1 christos free(line))
1186 1.1 christos {
1187 1.1 christos if (!*line)
1188 1.1 christos continue;
1189 1.1 christos if (strcmp(line, "[local]") == 0) {
1190 1.1 christos cs = &lc;
1191 1.1 christos continue;
1192 1.1 christos }
1193 1.1 christos if (strcmp(line, "[remote]") == 0) {
1194 1.1 christos cs = &rc;
1195 1.1 christos continue;
1196 1.1 christos }
1197 1.1 christos
1198 1.1 christos if (confset_full(cs)) {
1199 1.1 christos if (confset_grow(cs) == -1) {
1200 1.1 christos confset_free(&lc);
1201 1.1 christos confset_free(&rc);
1202 1.1 christos fclose(fp);
1203 1.1 christos free(line);
1204 1.1 christos return;
1205 1.1 christos }
1206 1.1 christos }
1207 1.1 christos if (conf_parseline(f, lineno, line, confset_get(cs),
1208 1.1 christos cs == &lc) == -1)
1209 1.1 christos continue;
1210 1.1 christos confset_add(cs);
1211 1.1 christos }
1212 1.1 christos
1213 1.1 christos fclose(fp);
1214 1.1 christos confset_sort(&lc);
1215 1.1 christos confset_sort(&rc);
1216 1.1 christos
1217 1.1 christos confset_replace(&rconf, &rc);
1218 1.1 christos confset_replace(&lconf, &lc);
1219 1.1 christos
1220 1.1 christos if (debug) {
1221 1.1 christos confset_list(&lconf, "local", "target");
1222 1.1 christos confset_list(&rconf, "remote", "source");
1223 1.1 christos }
1224 1.1 christos }
1225