xref: /freebsd/contrib/blocklist/bin/conf.c (revision 5f4c09dd85bff675e0ca63c55ea3c517e0fddfcc)
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