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