1 /* $NetBSD: conf.c,v 1.23 2015/06/03 15:11:40 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.23 2015/06/03 15:11:40 christos Exp $");
52 #include <arpa/inet.h>
53 #include <netinet/in.h>
55 #include <sys/socket.h>
65 sa_family_t sif_family
;
71 ((const struct sockaddr_if *)(const void *)(a))->sif_name
73 static int conf_is_interface(const char *);
82 while (*ep
&& !isspace((unsigned char)*ep
))
84 while (*ep
&& isspace((unsigned char)*ep
))
90 getnum(const char *f
, size_t l
, bool local
, void *rp
, const char *name
,
97 if (strcmp(p
, "*") == 0) {
101 if (strcmp(p
, "=") == 0) {
108 im
= strtoi(p
, NULL
, 0, 0, INT_MAX
, &e
);
116 (*lfun
)(LOG_ERR
, "%s: %s, %zu: Bad number for %s [%s]", __func__
, f
, l
,
120 (*lfun
)(LOG_ERR
, "%s: %s, %zu: `=' for %s not allowed in local config",
121 __func__
, f
, l
, name
);
127 getnfail(const char *f
, size_t l
, bool local
, struct conf
*c
, const char *p
)
129 return getnum(f
, l
, local
, &c
->c_nfail
, "nfail", p
);
133 getsecs(const char *f
, size_t l
, bool local
, struct conf
*c
, const char *p
)
140 if (strcmp(p
, "*") == 0) {
141 c
->c_duration
= FSTAR
;
144 if (strcmp(p
, "=") == 0) {
147 c
->c_duration
= FEQUAL
;
151 im
= strtoi(p
, &ep
, 0, 0, INT_MAX
, &e
);
177 c
->c_duration
= (int)tot
;
183 (*lfun
)(LOG_ERR
, "%s: %s, %zu: Bad number [%s]", __func__
, f
, l
, p
);
186 (*lfun
)(LOG_ERR
, "%s: %s, %zu: `=' duration not allowed in local"
187 " config", __func__
, f
, l
);
193 getport(const char *f
, size_t l
, bool local
, void *r
, const char *p
)
197 // XXX: Pass in the proto instead
198 if ((sv
= getservbyname(p
, "tcp")) != NULL
) {
199 *(int *)r
= ntohs(sv
->s_port
);
202 if ((sv
= getservbyname(p
, "udp")) != NULL
) {
203 *(int *)r
= ntohs(sv
->s_port
);
207 return getnum(f
, l
, local
, r
, "service", p
);
211 getmask(const char *f
, size_t l
, bool local
, const char **p
, int *mask
)
216 if ((d
= strchr(s
, ':')) != NULL
) {
220 if ((d
= strchr(s
, '/')) == NULL
) {
226 return getnum(f
, l
, local
, mask
, "mask", d
);
230 gethostport(const char *f
, size_t l
, bool local
, struct conf
*c
, const char *p
)
232 char *d
; // XXX: Ok to write to string.
233 in_port_t
*port
= NULL
;
236 if (strcmp(p
, "*") == 0) {
242 if ((d
= strchr(p
, ']')) != NULL
) {
249 if (getmask(f
, l
, local
, &pstr
, &c
->c_lmask
) == -1)
253 struct sockaddr_in6
*sin6
= (void *)&c
->c_ss
;
255 (*lfun
)(LOG_DEBUG
, "%s: host6 %s", __func__
, p
);
256 if (strcmp(p
, "*") != 0) {
257 if (inet_pton(AF_INET6
, p
, &sin6
->sin6_addr
) == -1)
259 sin6
->sin6_family
= AF_INET6
;
260 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
261 sin6
->sin6_len
= sizeof(*sin6
);
263 port
= &sin6
->sin6_port
;
265 } else if (pstr
!= p
|| strchr(p
, '.') || conf_is_interface(p
)) {
268 struct sockaddr_in
*sin
= (void *)&c
->c_ss
;
269 struct sockaddr_if
*sif
= (void *)&c
->c_ss
;
271 (*lfun
)(LOG_DEBUG
, "%s: host4 %s", __func__
, p
);
272 if (strcmp(p
, "*") != 0) {
273 if (conf_is_interface(p
)) {
277 (*lfun
)(LOG_DEBUG
, "%s: interface %s",
279 if (c
->c_lmask
!= FSTAR
)
281 sif
->sif_family
= AF_MAX
;
282 strlcpy(sif
->sif_name
, p
,
283 sizeof(sif
->sif_name
));
284 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
285 sif
->sif_len
= sizeof(*sif
);
287 port
= &sif
->sif_port
;
288 } else if (inet_pton(AF_INET
, p
, &sin
->sin_addr
) != -1)
290 sin
->sin_family
= AF_INET
;
291 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
292 sin
->sin_len
= sizeof(*sin
);
294 port
= &sin
->sin_port
;
300 if (getport(f
, l
, local
, &c
->c_port
, pstr
) == -1)
303 if (port
&& c
->c_port
!= FSTAR
&& c
->c_port
!= FEQUAL
)
304 *port
= htons((in_port_t
)c
->c_port
);
307 (*lfun
)(LOG_ERR
, "%s: %s, %zu: Bad address [%s]", __func__
, f
, l
, pstr
);
310 (*lfun
)(LOG_ERR
, "%s: %s, %zu: Can't specify mask %d with "
311 "interface [%s]", __func__
, f
, l
, c
->c_lmask
, p
);
314 (*lfun
)(LOG_ERR
, "%s: %s, %zu: Interface spec does not make sense "
315 "with remote config [%s]", __func__
, f
, l
, p
);
320 getproto(const char *f
, size_t l
, bool local __unused
, struct conf
*c
,
323 if (strcmp(p
, "stream") == 0) {
324 c
->c_proto
= IPPROTO_TCP
;
327 if (strcmp(p
, "dgram") == 0) {
328 c
->c_proto
= IPPROTO_UDP
;
331 return getnum(f
, l
, local
, &c
->c_proto
, "protocol", p
);
335 getfamily(const char *f
, size_t l
, bool local __unused
, struct conf
*c
,
338 if (strncmp(p
, "tcp", 3) == 0 || strncmp(p
, "udp", 3) == 0) {
339 c
->c_family
= p
[3] == '6' ? AF_INET6
: AF_INET
;
342 return getnum(f
, l
, local
, &c
->c_family
, "family", p
);
346 getuid(const char *f
, size_t l
, bool local __unused
, struct conf
*c
,
351 if ((pw
= getpwnam(p
)) != NULL
) {
352 c
->c_uid
= (int)pw
->pw_uid
;
356 return getnum(f
, l
, local
, &c
->c_uid
, "user", p
);
361 getname(const char *f
, size_t l
, bool local
, struct conf
*c
,
364 if (getmask(f
, l
, local
, &p
, &c
->c_rmask
) == -1)
367 if (strcmp(p
, "*") == 0) {
368 strlcpy(c
->c_name
, rulename
, CONFNAMESZ
);
371 if (strcmp(p
, "=") == 0) {
378 snprintf(c
->c_name
, CONFNAMESZ
, "%s%s", *p
== '-' ? rulename
: "", p
);
381 (*lfun
)(LOG_ERR
, "%s: %s, %zu: `=' name not allowed in local"
382 " config", __func__
, f
, l
);
387 getvalue(const char *f
, size_t l
, bool local
, void *r
, char **p
,
388 int (*fun
)(const char *, size_t, bool, struct conf
*, const char *))
393 return (*fun
)(f
, l
, local
, r
, ep
);
398 conf_parseline(const char *f
, size_t l
, char *p
, struct conf
*c
, bool local
)
402 while (*p
&& isspace((unsigned char)*p
))
405 memset(c
, 0, sizeof(*c
));
406 e
= getvalue(f
, l
, local
, c
, &p
, gethostport
);
408 e
= getvalue(f
, l
, local
, c
, &p
, getproto
);
410 e
= getvalue(f
, l
, local
, c
, &p
, getfamily
);
412 e
= getvalue(f
, l
, local
, c
, &p
, getuid
);
414 e
= getvalue(f
, l
, local
, c
, &p
, getname
);
416 e
= getvalue(f
, l
, local
, c
, &p
, getnfail
);
418 e
= getvalue(f
, l
, local
, c
, &p
, getsecs
);
425 conf_sort(const void *v1
, const void *v2
)
427 const struct conf
*c1
= v1
;
428 const struct conf
*c2
= v2
;
430 #define CMP(a, b, f) \
431 if ((a)->f > (b)->f) return -1; \
432 else if ((a)->f < (b)->f) return 1
434 CMP(c1
, c2
, c_ss
.ss_family
);
435 CMP(c1
, c2
, c_lmask
);
437 CMP(c1
, c2
, c_proto
);
438 CMP(c1
, c2
, c_family
);
439 CMP(c1
, c2
, c_rmask
);
446 conf_is_interface(const char *name
)
448 const struct ifaddrs
*ifa
;
450 for (ifa
= ifas
; ifa
; ifa
= ifa
->ifa_next
)
451 if (strcmp(ifa
->ifa_name
, name
) == 0)
456 #define MASK(m) ((uint32_t)~((1 << (32 - (m))) - 1))
459 conf_amask_eq(const void *v1
, const void *v2
, size_t len
, int mask
)
461 const uint32_t *a1
= v1
;
462 const uint32_t *a2
= v2
;
469 if (memcmp(v1
, v2
, len
) == 0)
474 (*lfun
)(LOG_CRIT
, "%s: Internal error: bad mask %d", __func__
,
481 for (size_t i
= 0; i
< len
; i
++) {
483 m
= htonl((uint32_t)~0);
486 m
= htonl(MASK(mask
));
490 if ((a1
[i
] & m
) != (a2
[i
] & m
))
496 char b1
[256], b2
[256];
498 hexdump(b1
, sizeof(b1
), "a1", v1
, len
);
499 hexdump(b2
, sizeof(b2
), "a2", v2
, len
);
500 (*lfun
)(LOG_DEBUG
, "%s: %s != %s [0x%x]", __func__
,
507 * Apply the mask to the given address
510 conf_apply_mask(void *v
, size_t len
, int mask
)
519 (*lfun
)(LOG_CRIT
, "%s: Internal error: bad mask %d", __func__
,
527 for (size_t i
= 0; i
< len
; i
++) {
529 m
= htonl((uint32_t)~0);
532 m
= htonl(MASK(mask
));
541 * apply the mask and the port to the address given
544 conf_addr_set(struct conf
*c
, const struct sockaddr_storage
*ss
)
546 struct sockaddr_in
*sin
;
547 struct sockaddr_in6
*sin6
;
552 c
->c_lmask
= c
->c_rmask
;
555 if (c
->c_ss
.ss_family
!= c
->c_family
) {
556 (*lfun
)(LOG_CRIT
, "%s: Internal error: mismatched family "
557 "%u != %u", __func__
, c
->c_ss
.ss_family
, c
->c_family
);
561 switch (c
->c_ss
.ss_family
) {
563 sin
= (void *)&c
->c_ss
;
564 port
= &sin
->sin_port
;
565 addr
= &sin
->sin_addr
;
566 alen
= sizeof(sin
->sin_addr
);
569 sin6
= (void *)&c
->c_ss
;
570 port
= &sin6
->sin6_port
;
571 addr
= &sin6
->sin6_addr
;
572 alen
= sizeof(sin6
->sin6_addr
);
575 (*lfun
)(LOG_CRIT
, "%s: Internal error: bad family %u",
576 __func__
, c
->c_ss
.ss_family
);
580 *port
= htons((in_port_t
)c
->c_port
);
581 conf_apply_mask(addr
, alen
, c
->c_lmask
);
582 if (c
->c_lmask
== FSTAR
)
583 c
->c_lmask
= (int)(alen
* 8);
586 sockaddr_snprintf(buf
, sizeof(buf
), "%a:%p", (void *)&c
->c_ss
);
587 (*lfun
)(LOG_DEBUG
, "Applied address %s", buf
);
592 * Compared two addresses for equality applying the mask
595 conf_inet_eq(const void *v1
, const void *v2
, int mask
)
597 const struct sockaddr
*sa1
= v1
;
598 const struct sockaddr
*sa2
= v2
;
601 if (sa1
->sa_family
!= sa2
->sa_family
)
604 switch (sa1
->sa_family
) {
606 const struct sockaddr_in
*s1
= v1
;
607 const struct sockaddr_in
*s2
= v2
;
608 size
= sizeof(s1
->sin_addr
);
615 const struct sockaddr_in6
*s1
= v1
;
616 const struct sockaddr_in6
*s2
= v2
;
617 size
= sizeof(s1
->sin6_addr
);
624 (*lfun
)(LOG_CRIT
, "%s: Internal error: bad family %u",
625 __func__
, sa1
->sa_family
);
629 return conf_amask_eq(v1
, v2
, size
, mask
);
633 conf_addr_in_interface(const struct sockaddr_storage
*s1
,
634 const struct sockaddr_storage
*s2
, int mask
)
636 const char *name
= SIF_NAME(s2
);
637 const struct ifaddrs
*ifa
;
639 for (ifa
= ifas
; ifa
; ifa
= ifa
->ifa_next
) {
640 if ((ifa
->ifa_flags
& IFF_UP
) == 0)
643 if (strcmp(ifa
->ifa_name
, name
) != 0)
646 if (s1
->ss_family
!= ifa
->ifa_addr
->sa_family
)
650 switch (s1
->ss_family
) {
653 eq
= conf_inet_eq(ifa
->ifa_addr
, s1
, mask
);
656 (*lfun
)(LOG_ERR
, "Bad family %u", s1
->ss_family
);
666 conf_addr_eq(const struct sockaddr_storage
*s1
,
667 const struct sockaddr_storage
*s2
, int mask
)
669 switch (s2
->ss_family
) {
673 return conf_addr_in_interface(s1
, s2
, mask
);
676 return conf_inet_eq(s1
, s2
, mask
);
678 (*lfun
)(LOG_CRIT
, "%s: Internal error: bad family %u",
679 __func__
, s1
->ss_family
);
685 conf_eq(const struct conf
*c1
, const struct conf
*c2
)
688 if (!conf_addr_eq(&c1
->c_ss
, &c2
->c_ss
, c2
->c_lmask
))
691 #define CMP(a, b, f) \
692 if ((a)->f != (b)->f && (b)->f != FSTAR && (b)->f != FEQUAL) { \
694 (*lfun)(LOG_DEBUG, "%s: %s fail %d != %d", __func__, \
695 __STRING(f), (a)->f, (b)->f); \
699 CMP(c1
, c2
, c_proto
);
700 CMP(c1
, c2
, c_family
);
707 conf_num(char *b
, size_t l
, int n
)
715 snprintf(b
, l
, "%d", n
);
721 fmtname(const char *n
) {
722 size_t l
= strlen(rulename
);
725 if (strncmp(n
, rulename
, l
) == 0) {
737 fmtport(char *b
, size_t l
, int port
)
744 if (b
[0] == '\0' || strcmp(b
, "*") == 0)
745 snprintf(b
, l
, "%d", port
);
747 snprintf(buf
, sizeof(buf
), ":%d", port
);
753 fmtmask(char *b
, size_t l
, int fam
, int mask
)
761 if (strcmp(b
, "=") == 0)
784 snprintf(buf
, sizeof(buf
), "/%d", mask
);
790 conf_namemask(char *b
, size_t l
, const struct conf
*c
)
792 strlcpy(b
, fmtname(c
->c_name
), l
);
793 fmtmask(b
, l
, c
->c_family
, c
->c_rmask
);
798 conf_print(char *buf
, size_t len
, const char *pref
, const char *delim
,
799 const struct conf
*c
)
801 char ha
[128], hb
[32], b
[5][64];
804 #define N(n, v) conf_num(b[n], sizeof(b[n]), (v))
806 switch (c
->c_ss
.ss_family
) {
808 snprintf(ha
, sizeof(ha
), "*");
811 snprintf(ha
, sizeof(ha
), "%s", SIF_NAME(&c
->c_ss
));
814 sockaddr_snprintf(ha
, sizeof(ha
), "%a", (const void *)&c
->c_ss
);
818 fmtmask(ha
, sizeof(ha
), c
->c_family
, c
->c_lmask
);
819 fmtport(ha
, sizeof(ha
), c
->c_port
);
821 sp
= *delim
== '\t' ? 20 : -1;
824 snprintf(buf
, len
, "%s%*.*s%s%s%s" "%s%s%s%s"
826 pref
, sp
, sp
, ha
, delim
, N(0, c
->c_proto
), delim
,
827 N(1, c
->c_family
), delim
, N(2, c
->c_uid
), delim
,
828 conf_namemask(hb
, sizeof(hb
), c
), delim
,
829 N(3, c
->c_nfail
), delim
, N(4, c
->c_duration
));
831 snprintf(buf
, len
, "%starget:%s, proto:%s, family:%s, "
832 "uid:%s, name:%s, nfail:%s, duration:%s", pref
,
833 ha
, N(0, c
->c_proto
), N(1, c
->c_family
), N(2, c
->c_uid
),
834 conf_namemask(hb
, sizeof(hb
), c
),
835 N(3, c
->c_nfail
), N(4, c
->c_duration
));
840 * Apply the local config match to the result
843 conf_apply(struct conf
*c
, const struct conf
*sc
)
848 (*lfun
)(LOG_DEBUG
, "%s: %s", __func__
,
849 conf_print(buf
, sizeof(buf
), "merge:\t", "", sc
));
850 (*lfun
)(LOG_DEBUG
, "%s: %s", __func__
,
851 conf_print(buf
, sizeof(buf
), "to:\t", "", c
));
853 memcpy(c
->c_name
, sc
->c_name
, CONFNAMESZ
);
854 c
->c_uid
= sc
->c_uid
;
855 c
->c_rmask
= sc
->c_rmask
;
856 c
->c_nfail
= sc
->c_nfail
;
857 c
->c_duration
= sc
->c_duration
;
860 (*lfun
)(LOG_DEBUG
, "%s: %s", __func__
,
861 conf_print(buf
, sizeof(buf
), "result:\t", "", c
));
865 * Merge a remote configuration to the result
868 conf_merge(struct conf
*c
, const struct conf
*sc
)
873 (*lfun
)(LOG_DEBUG
, "%s: %s", __func__
,
874 conf_print(buf
, sizeof(buf
), "merge:\t", "", sc
));
875 (*lfun
)(LOG_DEBUG
, "%s: %s", __func__
,
876 conf_print(buf
, sizeof(buf
), "to:\t", "", c
));
880 memcpy(c
->c_name
, sc
->c_name
, CONFNAMESZ
);
881 if (sc
->c_uid
!= FEQUAL
)
882 c
->c_uid
= sc
->c_uid
;
883 if (sc
->c_rmask
!= FEQUAL
)
884 c
->c_lmask
= c
->c_rmask
= sc
->c_rmask
;
885 if (sc
->c_nfail
!= FEQUAL
)
886 c
->c_nfail
= sc
->c_nfail
;
887 if (sc
->c_duration
!= FEQUAL
)
888 c
->c_duration
= sc
->c_duration
;
890 (*lfun
)(LOG_DEBUG
, "%s: %s", __func__
,
891 conf_print(buf
, sizeof(buf
), "result:\t", "", c
));
895 confset_init(struct confset
*cs
)
903 confset_grow(struct confset
*cs
)
908 tc
= realloc(cs
->cs_c
, cs
->cs_m
* sizeof(*cs
->cs_c
));
910 (*lfun
)(LOG_ERR
, "%s: Can't grow confset (%m)", __func__
);
918 confset_get(struct confset
*cs
)
920 return &cs
->cs_c
[cs
->cs_n
];
924 confset_full(const struct confset
*cs
)
926 return cs
->cs_n
== cs
->cs_m
;
930 confset_sort(struct confset
*cs
)
932 qsort(cs
->cs_c
, cs
->cs_n
, sizeof(*cs
->cs_c
), conf_sort
);
936 confset_add(struct confset
*cs
)
942 confset_free(struct confset
*cs
)
949 confset_replace(struct confset
*dc
, struct confset
*sc
)
959 confset_list(const struct confset
*cs
, const char *msg
, const char *where
)
963 (*lfun
)(LOG_DEBUG
, "[%s]", msg
);
964 (*lfun
)(LOG_DEBUG
, "%20.20s\ttype\tproto\towner\tname\tnfail\tduration",
966 for (size_t i
= 0; i
< cs
->cs_n
; i
++)
967 (*lfun
)(LOG_DEBUG
, "%s", conf_print(buf
, sizeof(buf
), "", "\t",
972 * Match a configuration against the given list and apply the function
973 * to it, returning the matched entry number.
976 confset_match(const struct confset
*cs
, struct conf
*c
,
977 void (*fun
)(struct conf
*, const struct conf
*))
982 for (i
= 0; i
< cs
->cs_n
; i
++) {
984 (*lfun
)(LOG_DEBUG
, "%s", conf_print(buf
, sizeof(buf
),
985 "check:\t", "", &cs
->cs_c
[i
]));
986 if (conf_eq(c
, &cs
->cs_c
[i
])) {
988 (*lfun
)(LOG_DEBUG
, "%s",
989 conf_print(buf
, sizeof(buf
),
990 "found:\t", "", &cs
->cs_c
[i
]));
991 (*fun
)(c
, &cs
->cs_c
[i
]);
999 conf_find(int fd
, uid_t uid
, const struct sockaddr_storage
*rss
,
1004 struct sockaddr_storage lss
;
1008 memset(cr
, 0, sizeof(*cr
));
1010 memset(&lss
, 0, slen
);
1011 if (getsockname(fd
, (void *)&lss
, &slen
) == -1) {
1012 (*lfun
)(LOG_ERR
, "getsockname failed (%m)");
1016 slen
= sizeof(proto
);
1017 if (getsockopt(fd
, SOL_SOCKET
, SO_TYPE
, &proto
, &slen
) == -1) {
1018 (*lfun
)(LOG_ERR
, "getsockopt failed (%m)");
1023 sockaddr_snprintf(buf
, sizeof(buf
), "%a:%p", (void *)&lss
);
1024 (*lfun
)(LOG_DEBUG
, "listening socket: %s", buf
);
1029 cr
->c_proto
= IPPROTO_TCP
;
1032 cr
->c_proto
= IPPROTO_UDP
;
1035 (*lfun
)(LOG_ERR
, "unsupported protocol %d", proto
);
1039 switch (lss
.ss_family
) {
1041 cr
->c_port
= ntohs(((struct sockaddr_in
*)&lss
)->sin_port
);
1044 cr
->c_port
= ntohs(((struct sockaddr_in6
*)&lss
)->sin6_port
);
1047 (*lfun
)(LOG_ERR
, "unsupported family %d", lss
.ss_family
);
1052 cr
->c_lmask
= FSTAR
;
1053 cr
->c_uid
= (int)uid
;
1054 cr
->c_family
= lss
.ss_family
;
1055 cr
->c_name
[0] = '\0';
1056 cr
->c_rmask
= FSTAR
;
1057 cr
->c_nfail
= FSTAR
;
1058 cr
->c_duration
= FSTAR
;
1061 (*lfun
)(LOG_DEBUG
, "%s", conf_print(buf
, sizeof(buf
),
1062 "look:\t", "", cr
));
1064 /* match the local config */
1065 i
= confset_match(&lconf
, cr
, conf_apply
);
1066 if (i
== lconf
.cs_n
) {
1068 (*lfun
)(LOG_DEBUG
, "not found");
1072 conf_addr_set(cr
, rss
);
1073 /* match the remote config */
1074 confset_match(&rconf
, cr
, conf_merge
);
1075 /* to apply the mask */
1076 conf_addr_set(cr
, &cr
->c_ss
);
1083 conf_parse(const char *f
)
1088 struct confset lc
, rc
, *cs
;
1090 if ((fp
= fopen(f
, "r")) == NULL
) {
1091 (*lfun
)(LOG_ERR
, "%s: Cannot open `%s' (%m)", __func__
, f
);
1100 for (; (line
= fparseln(fp
, &len
, &lineno
, NULL
, 0)) != NULL
;
1105 if (strcmp(line
, "[local]") == 0) {
1109 if (strcmp(line
, "[remote]") == 0) {
1114 if (confset_full(cs
)) {
1115 if (confset_grow(cs
) == -1) {
1122 if (conf_parseline(f
, lineno
, line
, confset_get(cs
),
1132 confset_replace(&rconf
, &rc
);
1133 confset_replace(&lconf
, &lc
);
1136 confset_list(&lconf
, "local", "target");
1137 confset_list(&rconf
, "remote", "source");