etc/services - sync with NetBSD-8
[minix.git] / external / bsd / blacklist / bin / blacklistd.c
blob9849cf570c33023b937b0f677e1e24aca474b7c2
1 /* $NetBSD: blacklistd.c,v 1.33 2015/06/21 01:13:21 christos Exp $ */
3 /*-
4 * Copyright (c) 2015 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Christos Zoulas.
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.
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.
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 #include <sys/cdefs.h>
35 __RCSID("$NetBSD: blacklistd.c,v 1.33 2015/06/21 01:13:21 christos Exp $");
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/queue.h>
41 #ifdef HAVE_UTIL_H
42 #include <util.h>
43 #endif
44 #include <string.h>
45 #include <signal.h>
46 #include <netdb.h>
47 #include <stdio.h>
48 #include <stdbool.h>
49 #include <string.h>
50 #include <inttypes.h>
51 #include <syslog.h>
52 #include <ctype.h>
53 #include <limits.h>
54 #include <errno.h>
55 #include <poll.h>
56 #include <fcntl.h>
57 #include <err.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <time.h>
61 #include <ifaddrs.h>
62 #include <netinet/in.h>
64 #include "bl.h"
65 #include "internal.h"
66 #include "conf.h"
67 #include "run.h"
68 #include "state.h"
69 #include "support.h"
71 static const char *configfile = _PATH_BLCONF;
72 static DB *state;
73 static const char *dbfile = _PATH_BLSTATE;
74 static sig_atomic_t readconf;
75 static sig_atomic_t done;
76 static int vflag;
78 static void
79 sigusr1(int n __unused)
81 debug++;
84 static void
85 sigusr2(int n __unused)
87 debug--;
90 static void
91 sighup(int n __unused)
93 readconf++;
96 static void
97 sigdone(int n __unused)
99 done++;
102 static __dead void
103 usage(int c)
105 if (c)
106 warnx("Unknown option `%c'", (char)c);
107 fprintf(stderr, "Usage: %s [-vdfr] [-c <config>] [-R <rulename>] "
108 "[-P <sockpathsfile>] [-C <controlprog>] [-D <dbfile>] "
109 "[-s <sockpath>] [-t <timeout>]\n", getprogname());
110 exit(EXIT_FAILURE);
113 static int
114 getremoteaddress(bl_info_t *bi, struct sockaddr_storage *rss, socklen_t *rsl)
116 *rsl = sizeof(*rss);
117 memset(rss, 0, *rsl);
119 if (getpeername(bi->bi_fd, (void *)rss, rsl) != -1)
120 return 0;
122 if (errno != ENOTCONN) {
123 (*lfun)(LOG_ERR, "getpeername failed (%m)");
124 return -1;
127 if (bi->bi_slen == 0) {
128 (*lfun)(LOG_ERR, "unconnected socket with no peer in message");
129 return -1;
132 switch (bi->bi_ss.ss_family) {
133 case AF_INET:
134 *rsl = sizeof(struct sockaddr_in);
135 break;
136 case AF_INET6:
137 *rsl = sizeof(struct sockaddr_in6);
138 break;
139 default:
140 (*lfun)(LOG_ERR, "bad client passed socket family %u",
141 (unsigned)bi->bi_ss.ss_family);
142 return -1;
145 if (*rsl != bi->bi_slen) {
146 (*lfun)(LOG_ERR, "bad client passed socket length %u != %u",
147 (unsigned)*rsl, (unsigned)bi->bi_slen);
148 return -1;
151 memcpy(rss, &bi->bi_ss, *rsl);
153 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
154 if (*rsl != rss->ss_len) {
155 (*lfun)(LOG_ERR,
156 "bad client passed socket internal length %u != %u",
157 (unsigned)*rsl, (unsigned)rss->ss_len);
158 return -1;
160 #endif
161 return 0;
164 static void
165 process(bl_t bl)
167 struct sockaddr_storage rss;
168 socklen_t rsl;
169 char rbuf[BUFSIZ];
170 bl_info_t *bi;
171 struct conf c;
172 struct dbinfo dbi;
173 struct timespec ts;
175 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
176 (*lfun)(LOG_ERR, "clock_gettime failed (%m)");
177 return;
180 if ((bi = bl_recv(bl)) == NULL) {
181 (*lfun)(LOG_ERR, "no message (%m)");
182 return;
185 if (getremoteaddress(bi, &rss, &rsl) == -1)
186 goto out;
188 if (debug) {
189 sockaddr_snprintf(rbuf, sizeof(rbuf), "%a:%p", (void *)&rss);
190 (*lfun)(LOG_DEBUG, "processing type=%d fd=%d remote=%s msg=%s"
191 " uid=%lu gid=%lu", bi->bi_type, bi->bi_fd, rbuf,
192 bi->bi_msg, (unsigned long)bi->bi_uid,
193 (unsigned long)bi->bi_gid);
196 if (conf_find(bi->bi_fd, bi->bi_uid, &rss, &c) == NULL) {
197 (*lfun)(LOG_DEBUG, "no rule matched");
198 goto out;
202 if (state_get(state, &c, &dbi) == -1)
203 goto out;
205 if (debug) {
206 char b1[128], b2[128];
207 (*lfun)(LOG_DEBUG, "%s: db state info for %s: count=%d/%d "
208 "last=%s now=%s", __func__, rbuf, dbi.count, c.c_nfail,
209 fmttime(b1, sizeof(b1), dbi.last),
210 fmttime(b2, sizeof(b2), ts.tv_sec));
213 switch (bi->bi_type) {
214 case BL_ADD:
215 dbi.count++;
216 dbi.last = ts.tv_sec;
217 if (dbi.id[0]) {
219 * We should not be getting this since the rule
220 * should have blocked the address. A possible
221 * explanation is that someone removed that rule,
222 * and another would be that we got another attempt
223 * before we added the rule. In anycase, we remove
224 * and re-add the rule because we don't want to add
225 * it twice, because then we'd lose track of it.
227 (*lfun)(LOG_DEBUG, "rule exists %s", dbi.id);
228 (void)run_change("rem", &c, dbi.id, 0);
229 dbi.id[0] = '\0';
231 if (c.c_nfail != -1 && dbi.count >= c.c_nfail) {
232 int res = run_change("add", &c, dbi.id, sizeof(dbi.id));
233 if (res == -1)
234 goto out;
235 sockaddr_snprintf(rbuf, sizeof(rbuf), "%a",
236 (void *)&rss);
237 (*lfun)(LOG_INFO,
238 "blocked %s/%d:%d for %d seconds",
239 rbuf, c.c_lmask, c.c_port, c.c_duration);
242 break;
243 case BL_DELETE:
244 if (dbi.last == 0)
245 goto out;
246 dbi.last = 0;
247 break;
248 default:
249 (*lfun)(LOG_ERR, "unknown message %d", bi->bi_type);
251 if (state_put(state, &c, &dbi) == -1)
252 goto out;
253 out:
254 close(bi->bi_fd);
257 static void
258 update_interfaces(void)
260 struct ifaddrs *oifas, *nifas;
262 if (getifaddrs(&nifas) == -1)
263 return;
265 oifas = ifas;
266 ifas = nifas;
268 if (oifas)
269 freeifaddrs(oifas);
272 static void
273 update(void)
275 struct timespec ts;
276 struct conf c;
277 struct dbinfo dbi;
278 unsigned int f, n;
279 char buf[128];
280 void *ss = &c.c_ss;
282 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
283 (*lfun)(LOG_ERR, "clock_gettime failed (%m)");
284 return;
287 again:
288 for (n = 0, f = 1; state_iterate(state, &c, &dbi, f) == 1;
289 f = 0, n++)
291 time_t when = c.c_duration + dbi.last;
292 if (debug > 1) {
293 char b1[64], b2[64];
294 sockaddr_snprintf(buf, sizeof(buf), "%a:%p", ss);
295 (*lfun)(LOG_DEBUG, "%s:[%u] %s count=%d duration=%d "
296 "last=%s " "now=%s", __func__, n, buf, dbi.count,
297 c.c_duration, fmttime(b1, sizeof(b1), dbi.last),
298 fmttime(b2, sizeof(b2), ts.tv_sec));
300 if (c.c_duration == -1 || when >= ts.tv_sec)
301 continue;
302 if (dbi.id[0]) {
303 run_change("rem", &c, dbi.id, 0);
304 sockaddr_snprintf(buf, sizeof(buf), "%a", ss);
305 syslog(LOG_INFO, "released %s/%d:%d after %d seconds",
306 buf, c.c_lmask, c.c_port, c.c_duration);
308 state_del(state, &c);
309 goto again;
313 static void
314 addfd(struct pollfd **pfdp, bl_t **blp, size_t *nfd, size_t *maxfd,
315 const char *path)
317 bl_t bl = bl_create(true, path, vflag ? vdlog : vsyslog);
318 if (bl == NULL || !bl_isconnected(bl))
319 exit(EXIT_FAILURE);
320 if (*nfd >= *maxfd) {
321 *maxfd += 10;
322 *blp = realloc(*blp, sizeof(**blp) * *maxfd);
323 if (*blp == NULL)
324 err(EXIT_FAILURE, "malloc");
325 *pfdp = realloc(*pfdp, sizeof(**pfdp) * *maxfd);
326 if (*pfdp == NULL)
327 err(EXIT_FAILURE, "malloc");
330 (*pfdp)[*nfd].fd = bl_getfd(bl);
331 (*pfdp)[*nfd].events = POLLIN;
332 (*blp)[*nfd] = bl;
333 *nfd += 1;
336 static void
337 uniqueadd(struct conf ***listp, size_t *nlist, size_t *mlist, struct conf *c)
339 struct conf **list = *listp;
341 if (c->c_name[0] == '\0')
342 return;
343 for (size_t i = 0; i < *nlist; i++) {
344 if (strcmp(list[i]->c_name, c->c_name) == 0)
345 return;
347 if (*nlist == *mlist) {
348 *mlist += 10;
349 void *p = realloc(*listp, *mlist * sizeof(*list));
350 if (p == NULL)
351 err(EXIT_FAILURE, "Can't allocate for rule list");
352 list = *listp = p;
354 list[(*nlist)++] = c;
357 static void
358 rules_flush(void)
360 struct conf **list;
361 size_t nlist, mlist;
363 list = NULL;
364 mlist = nlist = 0;
365 for (size_t i = 0; i < rconf.cs_n; i++)
366 uniqueadd(&list, &nlist, &mlist, &rconf.cs_c[i]);
367 for (size_t i = 0; i < lconf.cs_n; i++)
368 uniqueadd(&list, &nlist, &mlist, &lconf.cs_c[i]);
370 for (size_t i = 0; i < nlist; i++)
371 run_flush(list[i]);
372 free(list);
375 static void
376 rules_restore(void)
378 struct conf c;
379 struct dbinfo dbi;
380 unsigned int f;
382 for (f = 1; state_iterate(state, &c, &dbi, f) == 1; f = 0) {
383 if (dbi.id[0] == '\0')
384 continue;
385 (void)run_change("rem", &c, dbi.id, 0);
386 (void)run_change("add", &c, dbi.id, sizeof(dbi.id));
391 main(int argc, char *argv[])
393 int c, tout, flags, flush, restore;
394 const char *spath, *blsock;
396 setprogname(argv[0]);
398 spath = NULL;
399 blsock = _PATH_BLSOCK;
400 flush = 0;
401 restore = 0;
402 tout = 0;
403 flags = O_RDWR|O_EXCL|O_CLOEXEC;
404 while ((c = getopt(argc, argv, "C:c:D:dfP:rR:s:t:v")) != -1) {
405 switch (c) {
406 case 'C':
407 controlprog = optarg;
408 break;
409 case 'c':
410 configfile = optarg;
411 break;
412 case 'D':
413 dbfile = optarg;
414 break;
415 case 'd':
416 debug++;
417 break;
418 case 'f':
419 flush++;
420 break;
421 case 'P':
422 spath = optarg;
423 break;
424 case 'R':
425 rulename = optarg;
426 break;
427 case 'r':
428 restore++;
429 break;
430 case 's':
431 blsock = optarg;
432 break;
433 case 't':
434 tout = atoi(optarg) * 1000;
435 break;
436 case 'v':
437 vflag++;
438 break;
439 default:
440 usage(c);
444 argc -= optind;
445 if (argc)
446 usage(0);
448 signal(SIGHUP, sighup);
449 signal(SIGINT, sigdone);
450 signal(SIGQUIT, sigdone);
451 signal(SIGTERM, sigdone);
452 signal(SIGUSR1, sigusr1);
453 signal(SIGUSR2, sigusr2);
455 openlog(getprogname(), LOG_PID, LOG_DAEMON);
457 if (debug) {
458 lfun = dlog;
459 if (tout == 0)
460 tout = 5000;
461 } else {
462 if (tout == 0)
463 tout = 15000;
466 update_interfaces();
467 conf_parse(configfile);
468 if (flush) {
469 rules_flush();
470 flags |= O_TRUNC;
473 if (restore)
474 rules_restore();
476 struct pollfd *pfd = NULL;
477 bl_t *bl = NULL;
478 size_t nfd = 0;
479 size_t maxfd = 0;
481 if (spath == NULL)
482 addfd(&pfd, &bl, &nfd, &maxfd, blsock);
483 else {
484 FILE *fp = fopen(spath, "r");
485 char *line;
486 if (fp == NULL)
487 err(EXIT_FAILURE, "Can't open `%s'", spath);
488 for (; (line = fparseln(fp, NULL, NULL, NULL, 0)) != NULL;
489 free(line))
490 addfd(&pfd, &bl, &nfd, &maxfd, line);
491 fclose(fp);
494 state = state_open(dbfile, flags, 0600);
495 if (state == NULL)
496 state = state_open(dbfile, flags | O_CREAT, 0600);
497 if (state == NULL)
498 return EXIT_FAILURE;
500 if (!debug) {
501 if (daemon(0, 0) == -1)
502 err(EXIT_FAILURE, "daemon failed");
503 if (pidfile(NULL) == -1)
504 err(EXIT_FAILURE, "Can't create pidfile");
507 for (size_t t = 0; !done; t++) {
508 if (readconf) {
509 readconf = 0;
510 conf_parse(configfile);
512 switch (poll(pfd, (nfds_t)nfd, tout)) {
513 case -1:
514 if (errno == EINTR)
515 continue;
516 (*lfun)(LOG_ERR, "poll (%m)");
517 return EXIT_FAILURE;
518 case 0:
519 state_sync(state);
520 break;
521 default:
522 for (size_t i = 0; i < nfd; i++)
523 if (pfd[i].revents & POLLIN)
524 process(bl[i]);
526 if (t % 100 == 0)
527 state_sync(state);
528 if (t % 10000 == 0)
529 update_interfaces();
530 update();
532 state_close(state);
533 return 0;