Home | History | Annotate | Line # | Download | only in bin
conf.c revision 1.1
      1 /*	$NetBSD: conf.c,v 1.1 2020/06/15 01:52:53 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.1 2020/06/15 01:52:53 christos Exp $");
     37 
     38 #include <stdio.h>
     39 #ifdef HAVE_LIBUTIL_H
     40 #include <libutil.h>
     41 #endif
     42 #ifdef HAVE_UTIL_H
     43 #include <util.h>
     44 #endif
     45 #include <string.h>
     46 #include <ctype.h>
     47 #include <inttypes.h>
     48 #include <netdb.h>
     49 #include <unistd.h>
     50 #include <pwd.h>
     51 #include <syslog.h>
     52 #include <errno.h>
     53 #include <stdlib.h>
     54 #include <limits.h>
     55 #include <ifaddrs.h>
     56 #include <arpa/inet.h>
     57 #include <netinet/in.h>
     58 #include <net/if.h>
     59 #include <net/route.h>
     60 #include <sys/socket.h>
     61 
     62 #include "bl.h"
     63 #include "internal.h"
     64 #include "support.h"
     65 #include "conf.h"
     66 
     67 
     68 struct sockaddr_if {
     69 	uint8_t		sif_len;
     70 	sa_family_t	sif_family;
     71 	in_port_t	sif_port;
     72 	char		sif_name[16];
     73 };
     74 
     75 #define SIF_NAME(a) \
     76     ((const struct sockaddr_if *)(const void *)(a))->sif_name
     77 
     78 static int conf_is_interface(const char *);
     79 
     80 #define FSTAR	-1
     81 #define FEQUAL	-2
     82 
     83 static void
     84 advance(char **p)
     85 {
     86 	char *ep = *p;
     87 	while (*ep && !isspace((unsigned char)*ep))
     88 		ep++;
     89 	while (*ep && isspace((unsigned char)*ep))
     90 		*ep++ = '\0';
     91 	*p = ep;
     92 }
     93 
     94 static int
     95 conf_getnum(const char *f, size_t l, bool local, void *rp, const char *name,
     96     const char *p)
     97 {
     98 	int e;
     99 	intmax_t im;
    100 	int *r = rp;
    101 
    102 	if (strcmp(p, "*") == 0) {
    103 		*r = FSTAR;
    104 		return 0;
    105 	}
    106 	if (strcmp(p, "=") == 0) {
    107 		if (local)
    108 			goto out;
    109 		*r = FEQUAL;
    110 		return 0;
    111 	}
    112 
    113 	im = strtoi(p, NULL, 0, 0, INT_MAX, &e);
    114 	if (e == 0) {
    115 		*r = (int)im;
    116 		return 0;
    117 	}
    118 
    119 	if (f == NULL)
    120 		return -1;
    121 	(*lfun)(LOG_ERR, "%s: %s, %zu: Bad number for %s [%s]", __func__, f, l,
    122 	   name,  p);
    123 	return -1;
    124 out:
    125 	(*lfun)(LOG_ERR, "%s: %s, %zu: `=' for %s not allowed in local config",
    126 	    __func__, f, l, name);
    127 	return -1;
    128 
    129 }
    130 
    131 static int
    132 conf_getnfail(const char *f, size_t l, bool local, struct conf *c,
    133     const char *p)
    134 {
    135 	return conf_getnum(f, l, local, &c->c_nfail, "nfail", p);
    136 }
    137 
    138 static int
    139 conf_getsecs(const char *f, size_t l, bool local, struct conf *c, const char *p)
    140 {
    141 	int e;
    142 	char *ep;
    143 	intmax_t tot, im;
    144 
    145 	tot = 0;
    146 	if (strcmp(p, "*") == 0) {
    147 		c->c_duration = FSTAR;
    148 		return 0;
    149 	}
    150 	if (strcmp(p, "=") == 0) {
    151 		if (local)
    152 			goto out;
    153 		c->c_duration = FEQUAL;
    154 		return 0;
    155 	}
    156 again:
    157 	im = strtoi(p, &ep, 0, 0, INT_MAX, &e);
    158 
    159 	if (e == ENOTSUP) {
    160 		switch (*ep) {
    161 		case 'd':
    162 			im *= 24;
    163 			/*FALLTHROUGH*/
    164 		case 'h':
    165 			im *= 60;
    166 			/*FALLTHROUGH*/
    167 		case 'm':
    168 			im *= 60;
    169 			/*FALLTHROUGH*/
    170 		case 's':
    171 			e = 0;
    172 			tot += im;
    173 			if (ep[1] != '\0') {
    174 				p = ep + 2;
    175 				goto again;
    176 			}
    177 			break;
    178 		}
    179 	} else
    180 		tot = im;
    181 
    182 	if (e == 0) {
    183 		c->c_duration = (int)tot;
    184 		return 0;
    185 	}
    186 
    187 	if (f == NULL)
    188 		return -1;
    189 	(*lfun)(LOG_ERR, "%s: %s, %zu: Bad number [%s]", __func__, f, l, p);
    190 	return -1;
    191 out:
    192 	(*lfun)(LOG_ERR, "%s: %s, %zu: `=' duration not allowed in local"
    193 	    " config", __func__, f, l);
    194 	return -1;
    195 
    196 }
    197 
    198 static int
    199 conf_getport(const char *f, size_t l, bool local, void *r, const char *p)
    200 {
    201 	struct servent *sv;
    202 
    203 	// XXX: Pass in the proto instead
    204 	if ((sv = getservbyname(p, "tcp")) != NULL) {
    205 		*(int *)r = ntohs(sv->s_port);
    206 		return 0;
    207 	}
    208 	if ((sv = getservbyname(p, "udp")) != NULL) {
    209 		*(int *)r = ntohs(sv->s_port);
    210 		return 0;
    211 	}
    212 
    213 	return conf_getnum(f, l, local, r, "service", p);
    214 }
    215 
    216 static int
    217 conf_getmask(const char *f, size_t l, bool local, const char **p, int *mask)
    218 {
    219 	char *d;
    220 	const char *s = *p;
    221 
    222 	if ((d = strchr(s, ':')) != NULL) {
    223 		*d++ = '\0';
    224 		*p = d;
    225 	}
    226 	if ((d = strchr(s, '/')) == NULL) {
    227 		*mask = FSTAR;
    228 		return 0;
    229 	}
    230 
    231 	*d++ = '\0';
    232 	return conf_getnum(f, l, local, mask, "mask", d);
    233 }
    234 
    235 static int
    236 conf_gethostport(const char *f, size_t l, bool local, struct conf *c,
    237     const char *p)
    238 {
    239 	char *d;	// XXX: Ok to write to string.
    240 	in_port_t *port = NULL;
    241 	const char *pstr;
    242 
    243 	if (strcmp(p, "*") == 0) {
    244 		c->c_port = FSTAR;
    245 		c->c_lmask = FSTAR;
    246 		return 0;
    247 	}
    248 
    249 	if ((d = strchr(p, ']')) != NULL) {
    250 		*d++ = '\0';
    251 		pstr = d;
    252 		p++;
    253 	} else
    254 		pstr = p;
    255 
    256 	if (conf_getmask(f, l, local, &pstr, &c->c_lmask) == -1)
    257 		goto out;
    258 
    259 	if (d) {
    260 		struct sockaddr_in6 *sin6 = (void *)&c->c_ss;
    261 		if (debug)
    262 			(*lfun)(LOG_DEBUG, "%s: host6 %s", __func__, p);
    263 		if (strcmp(p, "*") != 0) {
    264 			if (inet_pton(AF_INET6, p, &sin6->sin6_addr) == -1)
    265 				goto out;
    266 			sin6->sin6_family = AF_INET6;
    267 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
    268 			sin6->sin6_len = sizeof(*sin6);
    269 #endif
    270 			port = &sin6->sin6_port;
    271 		}
    272 	} 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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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 *
    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
    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 *
    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 *
    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 *
    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
    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
    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
    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
    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 *
    925 confset_get(struct confset *cs)
    926 {
    927 	return &cs->cs_c[cs->cs_n];
    928 }
    929 
    930 static bool
    931 confset_full(const struct confset *cs)
    932 {
    933 	return cs->cs_n == cs->cs_m;
    934 }
    935 
    936 static void
    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
    943 confset_add(struct confset *cs)
    944 {
    945 	cs->cs_n++;
    946 }
    947 
    948 static void
    949 confset_free(struct confset *cs)
    950 {
    951 	free(cs->cs_c);
    952 	confset_init(cs);
    953 }
    954 
    955 static void
    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
    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
    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
   1007 conf_route_perm(int fd) {
   1008 /* Disable for now, the access check in the routing socket uses curlwp */
   1009 #if defined(RTM_IFANNOUNCE) && defined(RT_ROUNDUP)
   1010 	/*
   1011 	 * Send a routing message that is not supported to check for access
   1012 	 * We expect EOPNOTSUPP for having access, since we are sending a
   1013 	 * request the system does not understand and EACCES if we don't have
   1014 	 * access.
   1015 	 */
   1016 	static struct sockaddr_in sin = {
   1017 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
   1018 		.sin_len = sizeof(sin),
   1019 #endif
   1020 		.sin_family = AF_INET,
   1021 	};
   1022 	char buf[4096];
   1023 	struct rt_msghdr *rtm = (void *)buf;
   1024 	char *cp = (char *)(rtm + 1);
   1025 	size_t l;
   1026 
   1027 #define NEXTADDR(s) \
   1028 	l = RT_ROUNDUP(sizeof(*s)); memmove(cp, s, l); cp += l;
   1029 	memset(buf, 0, sizeof(buf));
   1030 	rtm->rtm_type = RTM_IFANNOUNCE;
   1031 	rtm->rtm_flags = 0;
   1032 	rtm->rtm_addrs = RTA_DST|RTA_GATEWAY;
   1033 	rtm->rtm_version = RTM_VERSION;
   1034 	rtm->rtm_seq = 666;
   1035 	NEXTADDR(&sin);
   1036 	NEXTADDR(&sin);
   1037 	rtm->rtm_msglen = (u_short)((char *)cp - (char *)rtm);
   1038 	if (write(fd, rtm, rtm->rtm_msglen) != -1) {
   1039 		(*lfun)(LOG_ERR, "Writing to routing socket succeeded!");
   1040 		return 0;
   1041 	}
   1042 	switch (errno) {
   1043 	case EACCES:
   1044 		return 0;
   1045 	case EOPNOTSUPP:
   1046 		return 1;
   1047 	default:
   1048 		(*lfun)(LOG_ERR,
   1049 		    "Unexpected error writing to routing socket (%m)");
   1050 		return 0;
   1051 	}
   1052 #else
   1053 	return 0;
   1054 #endif
   1055 }
   1056 #endif
   1057 
   1058 static int
   1059 conf_handle_inet(int fd, const void *lss, struct conf *cr)
   1060 {
   1061 	char buf[BUFSIZ];
   1062 	int proto;
   1063 	socklen_t slen = sizeof(proto);
   1064 
   1065 	if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &proto, &slen) == -1) {
   1066 		(*lfun)(LOG_ERR, "getsockopt failed (%m)");
   1067 		return -1;
   1068 	}
   1069 
   1070 	if (debug) {
   1071 		sockaddr_snprintf(buf, sizeof(buf), "%a:%p", lss);
   1072 		(*lfun)(LOG_DEBUG, "listening socket: %s", buf);
   1073 	}
   1074 
   1075 	switch (proto) {
   1076 	case SOCK_STREAM:
   1077 		cr->c_proto = IPPROTO_TCP;
   1078 		break;
   1079 	case SOCK_DGRAM:
   1080 		cr->c_proto = IPPROTO_UDP;
   1081 		break;
   1082 	default:
   1083 		(*lfun)(LOG_ERR, "unsupported protocol %d", proto);
   1084 		return -1;
   1085 	}
   1086 	return 0;
   1087 }
   1088 
   1089 const struct conf *
   1090 conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss,
   1091     struct conf *cr)
   1092 {
   1093 	socklen_t slen;
   1094 	struct sockaddr_storage lss;
   1095 	size_t i;
   1096 	char buf[BUFSIZ];
   1097 
   1098 	memset(cr, 0, sizeof(*cr));
   1099 	slen = sizeof(lss);
   1100 	memset(&lss, 0, slen);
   1101 	if (getsockname(fd, (void *)&lss, &slen) == -1) {
   1102 		(*lfun)(LOG_ERR, "getsockname failed (%m)");
   1103 		return NULL;
   1104 	}
   1105 
   1106 	switch (lss.ss_family) {
   1107 	case AF_INET:
   1108 		cr->c_port = ntohs(((struct sockaddr_in *)&lss)->sin_port);
   1109 		if (conf_handle_inet(fd, &lss, cr) == -1)
   1110 			return NULL;
   1111 		break;
   1112 	case AF_INET6:
   1113 		cr->c_port = ntohs(((struct sockaddr_in6 *)&lss)->sin6_port);
   1114 		if (conf_handle_inet(fd, &lss, cr) == -1)
   1115 			return NULL;
   1116 		break;
   1117 #ifdef AF_ROUTE
   1118 	case AF_ROUTE:
   1119 		if (!conf_route_perm(fd)) {
   1120 			(*lfun)(LOG_ERR,
   1121 			    "permission denied to routing socket (%m)");
   1122 			return NULL;
   1123 		}
   1124 		cr->c_proto = FSTAR;
   1125 		cr->c_port = FSTAR;
   1126 		memcpy(&lss, rss, sizeof(lss));
   1127 		break;
   1128 #endif
   1129 	default:
   1130 		(*lfun)(LOG_ERR, "unsupported family %d", lss.ss_family);
   1131 		return NULL;
   1132 	}
   1133 
   1134 	cr->c_ss = lss;
   1135 	cr->c_lmask = FSTAR;
   1136 	cr->c_uid = (int)uid;
   1137 	cr->c_family = lss.ss_family;
   1138 	cr->c_name[0] = '\0';
   1139 	cr->c_rmask = FSTAR;
   1140 	cr->c_nfail = FSTAR;
   1141 	cr->c_duration = FSTAR;
   1142 
   1143 	if (debug)
   1144 		(*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf),
   1145 		    "look:\t", "", cr));
   1146 
   1147 	/* match the local config */
   1148 	i = confset_match(&lconf, cr, conf_apply);
   1149 	if (i == lconf.cs_n) {
   1150 		if (debug)
   1151 			(*lfun)(LOG_DEBUG, "not found");
   1152 		return NULL;
   1153 	}
   1154 
   1155 	conf_addr_set(cr, rss);
   1156 	/* match the remote config */
   1157 	confset_match(&rconf, cr, conf_merge);
   1158 	/* to apply the mask */
   1159 	conf_addr_set(cr, &cr->c_ss);
   1160 
   1161 	return cr;
   1162 }
   1163 
   1164 
   1165 void
   1166 conf_parse(const char *f)
   1167 {
   1168 	FILE *fp;
   1169 	char *line;
   1170 	size_t lineno, len;
   1171 	struct confset lc, rc, *cs;
   1172 
   1173 	if ((fp = fopen(f, "r")) == NULL) {
   1174 		(*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__, f);
   1175 		return;
   1176 	}
   1177 
   1178 	lineno = 1;
   1179 
   1180 	confset_init(&rc);
   1181 	confset_init(&lc);
   1182 	cs = &lc;
   1183 	for (; (line = fparseln(fp, &len, &lineno, NULL, 0)) != NULL;
   1184 	    free(line))
   1185 	{
   1186 		if (!*line)
   1187 			continue;
   1188 		if (strcmp(line, "[local]") == 0) {
   1189 			cs = &lc;
   1190 			continue;
   1191 		}
   1192 		if (strcmp(line, "[remote]") == 0) {
   1193 			cs = &rc;
   1194 			continue;
   1195 		}
   1196 
   1197 		if (confset_full(cs)) {
   1198 			if (confset_grow(cs) == -1) {
   1199 				confset_free(&lc);
   1200 				confset_free(&rc);
   1201 				fclose(fp);
   1202 				free(line);
   1203 				return;
   1204 			}
   1205 		}
   1206 		if (conf_parseline(f, lineno, line, confset_get(cs),
   1207 		    cs == &lc) == -1)
   1208 			continue;
   1209 		confset_add(cs);
   1210 	}
   1211 
   1212 	fclose(fp);
   1213 	confset_sort(&lc);
   1214 	confset_sort(&rc);
   1215 
   1216 	confset_replace(&rconf, &rc);
   1217 	confset_replace(&lconf, &lc);
   1218 
   1219 	if (debug) {
   1220 		confset_list(&lconf, "local", "target");
   1221 		confset_list(&rconf, "remote", "source");
   1222 	}
   1223 }
   1224