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