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