1 /* $NetBSD: conf.c,v 1.24 2016/04/04 15:52:56 christos Exp $ */
4 * Copyright (c) 2015 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
35 #include <sys/cdefs.h>
36 __RCSID("$NetBSD: conf.c,v 1.24 2016/04/04 15:52:56 christos Exp $");
55 #include <arpa/inet.h>
56 #include <netinet/in.h>
58 #include <sys/socket.h>
68 sa_family_t sif_family;
74 ((const struct sockaddr_if *)(const void *)(a))->sif_name
76 static int conf_is_interface(const char *);
85 while (*ep && !isspace((unsigned char)*ep))
87 while (*ep && isspace((unsigned char)*ep))
93 conf_getnum(const char *f, size_t l, bool local, void *rp, const char *name,
100 if (strcmp(p, "*") == 0) {
104 if (strcmp(p, "=") == 0) {
111 im = strtoi(p, NULL, 0, 0, INT_MAX, &e);
119 (*lfun)(LOG_ERR, "%s: %s, %zu: Bad number for %s [%s]", __func__, f, l,
123 (*lfun)(LOG_ERR, "%s: %s, %zu: `=' for %s not allowed in local config",
124 __func__, f, l, name);
130 conf_getnfail(const char *f, size_t l, bool local, struct conf *c,
133 return conf_getnum(f, l, local, &c->c_nfail, "nfail", p);
137 conf_getsecs(const char *f, size_t l, bool local, struct conf *c, const char *p)
144 if (strcmp(p, "*") == 0) {
145 c->c_duration = FSTAR;
148 if (strcmp(p, "=") == 0) {
151 c->c_duration = FEQUAL;
155 im = strtoi(p, &ep, 0, 0, INT_MAX, &e);
181 c->c_duration = (int)tot;
187 (*lfun)(LOG_ERR, "%s: %s, %zu: Bad number [%s]", __func__, f, l, p);
190 (*lfun)(LOG_ERR, "%s: %s, %zu: `=' duration not allowed in local"
191 " config", __func__, f, l);
197 conf_getport(const char *f, size_t l, bool local, void *r, const char *p)
201 // XXX: Pass in the proto instead
202 if ((sv = getservbyname(p, "tcp")) != NULL) {
203 *(int *)r = ntohs(sv->s_port);
206 if ((sv = getservbyname(p, "udp")) != NULL) {
207 *(int *)r = ntohs(sv->s_port);
211 return conf_getnum(f, l, local, r, "service", p);
215 conf_getmask(const char *f, size_t l, bool local, const char **p, int *mask)
220 if ((d = strchr(s, ':')) != NULL) {
224 if ((d = strchr(s, '/')) == NULL) {
230 return conf_getnum(f, l, local, mask, "mask", d);
234 conf_gethostport(const char *f, size_t l, bool local, struct conf *c,
237 char *d; // XXX: Ok to write to string.
238 in_port_t *port = NULL;
241 if (strcmp(p, "*") == 0) {
247 if ((d = strchr(p, ']')) != NULL) {
254 if (conf_getmask(f, l, local, &pstr, &c->c_lmask) == -1)
258 struct sockaddr_in6 *sin6 = (void *)&c->c_ss;
260 (*lfun)(LOG_DEBUG, "%s: host6 %s", __func__, p);
261 if (strcmp(p, "*") != 0) {
262 if (inet_pton(AF_INET6, p, &sin6->sin6_addr) == -1)
264 sin6->sin6_family = AF_INET6;
265 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
266 sin6->sin6_len = sizeof(*sin6);
268 port = &sin6->sin6_port;
270 } else if (pstr != p || strchr(p, '.') || conf_is_interface(p)) {
273 struct sockaddr_in *sin = (void *)&c->c_ss;
274 struct sockaddr_if *sif = (void *)&c->c_ss;
276 (*lfun)(LOG_DEBUG, "%s: host4 %s", __func__, p);
277 if (strcmp(p, "*") != 0) {
278 if (conf_is_interface(p)) {
282 (*lfun)(LOG_DEBUG, "%s: interface %s",
284 if (c->c_lmask != FSTAR)
286 sif->sif_family = AF_MAX;
287 strlcpy(sif->sif_name, p,
288 sizeof(sif->sif_name));
289 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
290 sif->sif_len = sizeof(*sif);
292 port = &sif->sif_port;
293 } else if (inet_pton(AF_INET, p, &sin->sin_addr) != -1)
295 sin->sin_family = AF_INET;
296 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
297 sin->sin_len = sizeof(*sin);
299 port = &sin->sin_port;
305 if (conf_getport(f, l, local, &c->c_port, pstr) == -1)
308 if (port && c->c_port != FSTAR && c->c_port != FEQUAL)
309 *port = htons((in_port_t)c->c_port);
312 (*lfun)(LOG_ERR, "%s: %s, %zu: Bad address [%s]", __func__, f, l, pstr);
315 (*lfun)(LOG_ERR, "%s: %s, %zu: Can't specify mask %d with "
316 "interface [%s]", __func__, f, l, c->c_lmask, p);
319 (*lfun)(LOG_ERR, "%s: %s, %zu: Interface spec does not make sense "
320 "with remote config [%s]", __func__, f, l, p);
325 conf_getproto(const char *f, size_t l, bool local __unused, struct conf *c,
328 if (strcmp(p, "stream") == 0) {
329 c->c_proto = IPPROTO_TCP;
332 if (strcmp(p, "dgram") == 0) {
333 c->c_proto = IPPROTO_UDP;
336 return conf_getnum(f, l, local, &c->c_proto, "protocol", p);
340 conf_getfamily(const char *f, size_t l, bool local __unused, struct conf *c,
343 if (strncmp(p, "tcp", 3) == 0 || strncmp(p, "udp", 3) == 0) {
344 c->c_family = p[3] == '6' ? AF_INET6 : AF_INET;
347 return conf_getnum(f, l, local, &c->c_family, "family", p);
351 conf_getuid(const char *f, size_t l, bool local __unused, struct conf *c,
356 if ((pw = getpwnam(p)) != NULL) {
357 c->c_uid = (int)pw->pw_uid;
361 return conf_getnum(f, l, local, &c->c_uid, "user", p);
366 conf_getname(const char *f, size_t l, bool local, struct conf *c,
369 if (conf_getmask(f, l, local, &p, &c->c_rmask) == -1)
372 if (strcmp(p, "*") == 0) {
373 strlcpy(c->c_name, rulename, CONFNAMESZ);
377 if (strcmp(p, "=") == 0) {
384 snprintf(c->c_name, CONFNAMESZ, "%s%s", *p == '-' ? rulename : "", p);
387 (*lfun)(LOG_ERR, "%s: %s, %zu: `=' name not allowed in local"
388 " config", __func__, f, l);
393 getvalue(const char *f, size_t l, bool local, void *r, char **p,
394 int (*fun)(const char *, size_t, bool, struct conf *, const char *))
399 return (*fun)(f, l, local, r, ep);
404 conf_parseline(const char *f, size_t l, char *p, struct conf *c, bool local)
408 while (*p && isspace((unsigned char)*p))
411 memset(c, 0, sizeof(*c));
412 e = getvalue(f, l, local, c, &p, conf_gethostport);
414 e = getvalue(f, l, local, c, &p, conf_getproto);
416 e = getvalue(f, l, local, c, &p, conf_getfamily);
418 e = getvalue(f, l, local, c, &p, conf_getuid);
420 e = getvalue(f, l, local, c, &p, conf_getname);
422 e = getvalue(f, l, local, c, &p, conf_getnfail);
424 e = getvalue(f, l, local, c, &p, conf_getsecs);
431 conf_sort(const void *v1, const void *v2)
433 const struct conf *c1 = v1;
434 const struct conf *c2 = v2;
436 #define CMP(a, b, f) \
437 if ((a)->f > (b)->f) return -1; \
438 else if ((a)->f < (b)->f) return 1
440 CMP(c1, c2, c_ss.ss_family);
441 CMP(c1, c2, c_lmask);
443 CMP(c1, c2, c_proto);
444 CMP(c1, c2, c_family);
445 CMP(c1, c2, c_rmask);
452 conf_is_interface(const char *name)
454 const struct ifaddrs *ifa;
456 for (ifa = ifas; ifa; ifa = ifa->ifa_next)
457 if (strcmp(ifa->ifa_name, name) == 0)
462 #define MASK(m) ((uint32_t)~((1 << (32 - (m))) - 1))
465 conf_amask_eq(const void *v1, const void *v2, size_t len, int mask)
467 const uint32_t *a1 = v1;
468 const uint32_t *a2 = v2;
475 if (memcmp(v1, v2, len) == 0)
479 (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__,
486 for (size_t i = 0; i < len; i++) {
488 m = htonl((uint32_t)~0);
491 m = htonl(MASK(mask));
495 if ((a1[i] & m) != (a2[i] & m))
501 char b1[256], b2[256];
503 blhexdump(b1, sizeof(b1), "a1", v1, len);
504 blhexdump(b2, sizeof(b2), "a2", v2, len);
505 (*lfun)(LOG_DEBUG, "%s: %s != %s [0x%x]", __func__,
512 * Apply the mask to the given address
515 conf_apply_mask(void *v, size_t len, int mask)
524 (*lfun)(LOG_CRIT, "%s: Internal error: bad mask %d", __func__,
532 for (size_t i = 0; i < len; i++) {
534 m = htonl((uint32_t)~0);
537 m = htonl(MASK(mask));
546 * apply the mask and the port to the address given
549 conf_addr_set(struct conf *c, const struct sockaddr_storage *ss)
551 struct sockaddr_in *sin;
552 struct sockaddr_in6 *sin6;
557 c->c_lmask = c->c_rmask;
560 if (c->c_ss.ss_family != c->c_family) {
561 (*lfun)(LOG_CRIT, "%s: Internal error: mismatched family "
562 "%u != %u", __func__, c->c_ss.ss_family, c->c_family);
566 switch (c->c_ss.ss_family) {
568 sin = (void *)&c->c_ss;
569 port = &sin->sin_port;
570 addr = &sin->sin_addr;
571 alen = sizeof(sin->sin_addr);
574 sin6 = (void *)&c->c_ss;
575 port = &sin6->sin6_port;
576 addr = &sin6->sin6_addr;
577 alen = sizeof(sin6->sin6_addr);
580 (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u",
581 __func__, c->c_ss.ss_family);
585 *port = htons((in_port_t)c->c_port);
586 conf_apply_mask(addr, alen, c->c_lmask);
587 if (c->c_lmask == FSTAR)
588 c->c_lmask = (int)(alen * 8);
591 sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&c->c_ss);
592 (*lfun)(LOG_DEBUG, "Applied address %s", buf);
597 * Compared two addresses for equality applying the mask
600 conf_inet_eq(const void *v1, const void *v2, int mask)
602 const struct sockaddr *sa1 = v1;
603 const struct sockaddr *sa2 = v2;
606 if (sa1->sa_family != sa2->sa_family)
609 switch (sa1->sa_family) {
611 const struct sockaddr_in *s1 = v1;
612 const struct sockaddr_in *s2 = v2;
613 size = sizeof(s1->sin_addr);
620 const struct sockaddr_in6 *s1 = v1;
621 const struct sockaddr_in6 *s2 = v2;
622 size = sizeof(s1->sin6_addr);
629 (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u",
630 __func__, sa1->sa_family);
634 return conf_amask_eq(v1, v2, size, mask);
638 conf_addr_in_interface(const struct sockaddr_storage *s1,
639 const struct sockaddr_storage *s2, int mask)
641 const char *name = SIF_NAME(s2);
642 const struct ifaddrs *ifa;
644 for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
645 if ((ifa->ifa_flags & IFF_UP) == 0)
648 if (strcmp(ifa->ifa_name, name) != 0)
651 if (s1->ss_family != ifa->ifa_addr->sa_family)
655 switch (s1->ss_family) {
658 eq = conf_inet_eq(ifa->ifa_addr, s1, mask);
661 (*lfun)(LOG_ERR, "Bad family %u", s1->ss_family);
671 conf_addr_eq(const struct sockaddr_storage *s1,
672 const struct sockaddr_storage *s2, int mask)
674 switch (s2->ss_family) {
678 return conf_addr_in_interface(s1, s2, mask);
681 return conf_inet_eq(s1, s2, mask);
683 (*lfun)(LOG_CRIT, "%s: Internal error: bad family %u",
684 __func__, s1->ss_family);
690 conf_eq(const struct conf *c1, const struct conf *c2)
693 if (!conf_addr_eq(&c1->c_ss, &c2->c_ss, c2->c_lmask))
696 #define CMP(a, b, f) \
697 if ((a)->f != (b)->f && (b)->f != FSTAR && (b)->f != FEQUAL) { \
699 (*lfun)(LOG_DEBUG, "%s: %s fail %d != %d", __func__, \
700 __STRING(f), (a)->f, (b)->f); \
704 CMP(c1, c2, c_proto);
705 CMP(c1, c2, c_family);
712 conf_num(char *b, size_t l, int n)
720 snprintf(b, l, "%d", n);
726 fmtname(const char *n) {
727 size_t l = strlen(rulename);
730 if (strncmp(n, rulename, l) == 0) {
742 fmtport(char *b, size_t l, int port)
749 if (b[0] == '\0' || strcmp(b, "*") == 0)
750 snprintf(b, l, "%d", port);
752 snprintf(buf, sizeof(buf), ":%d", port);
758 fmtmask(char *b, size_t l, int fam, int mask)
766 if (strcmp(b, "=") == 0)
789 snprintf(buf, sizeof(buf), "/%d", mask);
795 conf_namemask(char *b, size_t l, const struct conf *c)
797 strlcpy(b, fmtname(c->c_name), l);
798 fmtmask(b, l, c->c_family, c->c_rmask);
803 conf_print(char *buf, size_t len, const char *pref, const char *delim,
804 const struct conf *c)
806 char ha[128], hb[32], b[5][64];
809 #define N(n, v) conf_num(b[n], sizeof(b[n]), (v))
811 switch (c->c_ss.ss_family) {
813 snprintf(ha, sizeof(ha), "*");
816 snprintf(ha, sizeof(ha), "%s", SIF_NAME(&c->c_ss));
819 sockaddr_snprintf(ha, sizeof(ha), "%a", (const void *)&c->c_ss);
823 fmtmask(ha, sizeof(ha), c->c_family, c->c_lmask);
824 fmtport(ha, sizeof(ha), c->c_port);
826 sp = *delim == '\t' ? 20 : -1;
829 snprintf(buf, len, "%s%*.*s%s%s%s" "%s%s%s%s"
831 pref, sp, sp, ha, delim, N(0, c->c_proto), delim,
832 N(1, c->c_family), delim, N(2, c->c_uid), delim,
833 conf_namemask(hb, sizeof(hb), c), delim,
834 N(3, c->c_nfail), delim, N(4, c->c_duration));
836 snprintf(buf, len, "%starget:%s, proto:%s, family:%s, "
837 "uid:%s, name:%s, nfail:%s, duration:%s", pref,
838 ha, N(0, c->c_proto), N(1, c->c_family), N(2, c->c_uid),
839 conf_namemask(hb, sizeof(hb), c),
840 N(3, c->c_nfail), N(4, c->c_duration));
845 * Apply the local config match to the result
848 conf_apply(struct conf *c, const struct conf *sc)
853 (*lfun)(LOG_DEBUG, "%s: %s", __func__,
854 conf_print(buf, sizeof(buf), "merge:\t", "", sc));
855 (*lfun)(LOG_DEBUG, "%s: %s", __func__,
856 conf_print(buf, sizeof(buf), "to:\t", "", c));
858 memcpy(c->c_name, sc->c_name, CONFNAMESZ);
859 c->c_uid = sc->c_uid;
860 c->c_rmask = sc->c_rmask;
861 c->c_nfail = sc->c_nfail;
862 c->c_duration = sc->c_duration;
865 (*lfun)(LOG_DEBUG, "%s: %s", __func__,
866 conf_print(buf, sizeof(buf), "result:\t", "", c));
870 * Merge a remote configuration to the result
873 conf_merge(struct conf *c, const struct conf *sc)
878 (*lfun)(LOG_DEBUG, "%s: %s", __func__,
879 conf_print(buf, sizeof(buf), "merge:\t", "", sc));
880 (*lfun)(LOG_DEBUG, "%s: %s", __func__,
881 conf_print(buf, sizeof(buf), "to:\t", "", c));
885 memcpy(c->c_name, sc->c_name, CONFNAMESZ);
886 if (sc->c_uid != FEQUAL)
887 c->c_uid = sc->c_uid;
888 if (sc->c_rmask != FEQUAL)
889 c->c_lmask = c->c_rmask = sc->c_rmask;
890 if (sc->c_nfail != FEQUAL)
891 c->c_nfail = sc->c_nfail;
892 if (sc->c_duration != FEQUAL)
893 c->c_duration = sc->c_duration;
895 (*lfun)(LOG_DEBUG, "%s: %s", __func__,
896 conf_print(buf, sizeof(buf), "result:\t", "", c));
900 confset_init(struct confset *cs)
908 confset_grow(struct confset *cs)
913 tc = realloc(cs->cs_c, cs->cs_m * sizeof(*cs->cs_c));
915 (*lfun)(LOG_ERR, "%s: Can't grow confset (%m)", __func__);
923 confset_get(struct confset *cs)
925 return &cs->cs_c[cs->cs_n];
929 confset_full(const struct confset *cs)
931 return cs->cs_n == cs->cs_m;
935 confset_sort(struct confset *cs)
937 qsort(cs->cs_c, cs->cs_n, sizeof(*cs->cs_c), conf_sort);
941 confset_add(struct confset *cs)
947 confset_free(struct confset *cs)
954 confset_replace(struct confset *dc, struct confset *sc)
964 confset_list(const struct confset *cs, const char *msg, const char *where)
968 (*lfun)(LOG_DEBUG, "[%s]", msg);
969 (*lfun)(LOG_DEBUG, "%20.20s\ttype\tproto\towner\tname\tnfail\tduration",
971 for (size_t i = 0; i < cs->cs_n; i++)
972 (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf), "", "\t",
977 * Match a configuration against the given list and apply the function
978 * to it, returning the matched entry number.
981 confset_match(const struct confset *cs, struct conf *c,
982 void (*fun)(struct conf *, const struct conf *))
987 for (i = 0; i < cs->cs_n; i++) {
989 (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf),
990 "check:\t", "", &cs->cs_c[i]));
991 if (conf_eq(c, &cs->cs_c[i])) {
993 (*lfun)(LOG_DEBUG, "%s",
994 conf_print(buf, sizeof(buf),
995 "found:\t", "", &cs->cs_c[i]));
996 (*fun)(c, &cs->cs_c[i]);
1004 conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss,
1009 struct sockaddr_storage lss;
1013 memset(cr, 0, sizeof(*cr));
1015 memset(&lss, 0, slen);
1016 if (getsockname(fd, (void *)&lss, &slen) == -1) {
1017 (*lfun)(LOG_ERR, "getsockname failed (%m)");
1021 slen = sizeof(proto);
1022 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &proto, &slen) == -1) {
1023 (*lfun)(LOG_ERR, "getsockopt failed (%m)");
1028 sockaddr_snprintf(buf, sizeof(buf), "%a:%p", (void *)&lss);
1029 (*lfun)(LOG_DEBUG, "listening socket: %s", buf);
1034 cr->c_proto = IPPROTO_TCP;
1037 cr->c_proto = IPPROTO_UDP;
1040 (*lfun)(LOG_ERR, "unsupported protocol %d", proto);
1044 switch (lss.ss_family) {
1046 cr->c_port = ntohs(((struct sockaddr_in *)&lss)->sin_port);
1049 cr->c_port = ntohs(((struct sockaddr_in6 *)&lss)->sin6_port);
1052 (*lfun)(LOG_ERR, "unsupported family %d", lss.ss_family);
1057 cr->c_lmask = FSTAR;
1058 cr->c_uid = (int)uid;
1059 cr->c_family = lss.ss_family;
1060 cr->c_name[0] = '\0';
1061 cr->c_rmask = FSTAR;
1062 cr->c_nfail = FSTAR;
1063 cr->c_duration = FSTAR;
1066 (*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf),
1067 "look:\t", "", cr));
1069 /* match the local config */
1070 i = confset_match(&lconf, cr, conf_apply);
1071 if (i == lconf.cs_n) {
1073 (*lfun)(LOG_DEBUG, "not found");
1077 conf_addr_set(cr, rss);
1078 /* match the remote config */
1079 confset_match(&rconf, cr, conf_merge);
1080 /* to apply the mask */
1081 conf_addr_set(cr, &cr->c_ss);
1088 conf_parse(const char *f)
1093 struct confset lc, rc, *cs;
1095 if ((fp = fopen(f, "r")) == NULL) {
1096 (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__, f);
1105 for (; (line = fparseln(fp, &len, &lineno, NULL, 0)) != NULL;
1110 if (strcmp(line, "[local]") == 0) {
1114 if (strcmp(line, "[remote]") == 0) {
1119 if (confset_full(cs)) {
1120 if (confset_grow(cs) == -1) {
1128 if (conf_parseline(f, lineno, line, confset_get(cs),
1138 confset_replace(&rconf, &rc);
1139 confset_replace(&lconf, &lc);
1142 confset_list(&lconf, "local", "target");
1143 confset_list(&rconf, "remote", "source");