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