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