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