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