1 /* $NetBSD: blacklistd.c,v 1.38 2019/02/27 02:20:18 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.
34 #include <sys/cdefs.h>
35 __RCSID("$NetBSD: blacklistd.c,v 1.38 2019/02/27 02:20:18 christos Exp $");
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/queue.h>
65 #include <netinet/in.h>
74 static const char *configfile = _PATH_BLCONF;
76 static const char *dbfile = _PATH_BLSTATE;
77 static sig_atomic_t readconf;
78 static sig_atomic_t done;
82 sigusr1(int n __unused)
88 sigusr2(int n __unused)
94 sighup(int n __unused)
100 sigdone(int n __unused)
109 warnx("Unknown option `%c'", (char)c);
110 fprintf(stderr, "Usage: %s [-vdfr] [-c <config>] [-R <rulename>] "
111 "[-P <sockpathsfile>] [-C <controlprog>] [-D <dbfile>] "
112 "[-s <sockpath>] [-t <timeout>]\n", getprogname());
117 getremoteaddress(bl_info_t *bi, struct sockaddr_storage *rss, socklen_t *rsl)
120 memset(rss, 0, *rsl);
122 if (getpeername(bi->bi_fd, (void *)rss, rsl) != -1)
125 if (errno != ENOTCONN) {
126 (*lfun)(LOG_ERR, "getpeername failed (%m)");
130 if (bi->bi_slen == 0) {
131 (*lfun)(LOG_ERR, "unconnected socket with no peer in message");
135 switch (bi->bi_ss.ss_family) {
137 *rsl = sizeof(struct sockaddr_in);
140 *rsl = sizeof(struct sockaddr_in6);
143 (*lfun)(LOG_ERR, "bad client passed socket family %u",
144 (unsigned)bi->bi_ss.ss_family);
148 if (*rsl != bi->bi_slen) {
149 (*lfun)(LOG_ERR, "bad client passed socket length %u != %u",
150 (unsigned)*rsl, (unsigned)bi->bi_slen);
154 memcpy(rss, &bi->bi_ss, *rsl);
156 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
157 if (*rsl != rss->ss_len) {
159 "bad client passed socket internal length %u != %u",
160 (unsigned)*rsl, (unsigned)rss->ss_len);
170 struct sockaddr_storage rss;
178 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
179 (*lfun)(LOG_ERR, "clock_gettime failed (%m)");
183 if ((bi = bl_recv(bl)) == NULL) {
184 (*lfun)(LOG_ERR, "no message (%m)");
188 if (getremoteaddress(bi, &rss, &rsl) == -1)
192 sockaddr_snprintf(rbuf, sizeof(rbuf), "%a:%p", (void *)&rss);
193 (*lfun)(LOG_DEBUG, "processing type=%d fd=%d remote=%s msg=%s"
194 " uid=%lu gid=%lu", bi->bi_type, bi->bi_fd, rbuf,
195 bi->bi_msg, (unsigned long)bi->bi_uid,
196 (unsigned long)bi->bi_gid);
199 if (conf_find(bi->bi_fd, bi->bi_uid, &rss, &c) == NULL) {
200 (*lfun)(LOG_DEBUG, "no rule matched");
205 if (state_get(state, &c, &dbi) == -1)
209 char b1[128], b2[128];
210 (*lfun)(LOG_DEBUG, "%s: initial db state for %s: count=%d/%d "
211 "last=%s now=%s", __func__, rbuf, dbi.count, c.c_nfail,
212 fmttime(b1, sizeof(b1), dbi.last),
213 fmttime(b2, sizeof(b2), ts.tv_sec));
216 switch (bi->bi_type) {
219 * If the application has signaled abusive behavior,
220 * set the number of fails to be one less than the
221 * configured limit. Fallthrough to the normal BL_ADD
222 * processing, which will increment the failure count
223 * to the threshhold, and block the abusive address.
226 dbi.count = c.c_nfail - 1;
230 dbi.last = ts.tv_sec;
233 * We should not be getting this since the rule
234 * should have blocked the address. A possible
235 * explanation is that someone removed that rule,
236 * and another would be that we got another attempt
237 * before we added the rule. In anycase, we remove
238 * and re-add the rule because we don't want to add
239 * it twice, because then we'd lose track of it.
241 (*lfun)(LOG_DEBUG, "rule exists %s", dbi.id);
242 (void)run_change("rem", &c, dbi.id, 0);
245 if (c.c_nfail != -1 && dbi.count >= c.c_nfail) {
246 int res = run_change("add", &c, dbi.id, sizeof(dbi.id));
249 sockaddr_snprintf(rbuf, sizeof(rbuf), "%a",
252 "blocked %s/%d:%d for %d seconds",
253 rbuf, c.c_lmask, c.c_port, c.c_duration);
267 (*lfun)(LOG_ERR, "unknown message %d", bi->bi_type);
269 state_put(state, &c, &dbi);
275 char b1[128], b2[128];
276 (*lfun)(LOG_DEBUG, "%s: final db state for %s: count=%d/%d "
277 "last=%s now=%s", __func__, rbuf, dbi.count, c.c_nfail,
278 fmttime(b1, sizeof(b1), dbi.last),
279 fmttime(b2, sizeof(b2), ts.tv_sec));
284 update_interfaces(void)
286 struct ifaddrs *oifas, *nifas;
288 if (getifaddrs(&nifas) == -1)
308 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
309 (*lfun)(LOG_ERR, "clock_gettime failed (%m)");
314 for (n = 0, f = 1; state_iterate(state, &c, &dbi, f) == 1;
317 time_t when = c.c_duration + dbi.last;
320 sockaddr_snprintf(buf, sizeof(buf), "%a:%p", ss);
321 (*lfun)(LOG_DEBUG, "%s:[%u] %s count=%d duration=%d "
322 "last=%s " "now=%s", __func__, n, buf, dbi.count,
323 c.c_duration, fmttime(b1, sizeof(b1), dbi.last),
324 fmttime(b2, sizeof(b2), ts.tv_sec));
326 if (c.c_duration == -1 || when >= ts.tv_sec)
329 run_change("rem", &c, dbi.id, 0);
330 sockaddr_snprintf(buf, sizeof(buf), "%a", ss);
331 (*lfun)(LOG_INFO, "released %s/%d:%d after %d seconds",
332 buf, c.c_lmask, c.c_port, c.c_duration);
334 state_del(state, &c);
340 addfd(struct pollfd **pfdp, bl_t **blp, size_t *nfd, size_t *maxfd,
343 bl_t bl = bl_create(true, path, vflag ? vdlog : vsyslog);
344 if (bl == NULL || !bl_isconnected(bl))
346 if (*nfd >= *maxfd) {
348 *blp = realloc(*blp, sizeof(**blp) * *maxfd);
350 err(EXIT_FAILURE, "malloc");
351 *pfdp = realloc(*pfdp, sizeof(**pfdp) * *maxfd);
353 err(EXIT_FAILURE, "malloc");
356 (*pfdp)[*nfd].fd = bl_getfd(bl);
357 (*pfdp)[*nfd].events = POLLIN;
363 uniqueadd(struct conf ***listp, size_t *nlist, size_t *mlist, struct conf *c)
365 struct conf **list = *listp;
367 if (c->c_name[0] == '\0')
369 for (size_t i = 0; i < *nlist; i++) {
370 if (strcmp(list[i]->c_name, c->c_name) == 0)
373 if (*nlist == *mlist) {
375 void *p = realloc(*listp, *mlist * sizeof(*list));
377 err(EXIT_FAILURE, "Can't allocate for rule list");
380 list[(*nlist)++] = c;
391 for (size_t i = 0; i < rconf.cs_n; i++)
392 uniqueadd(&list, &nlist, &mlist, &rconf.cs_c[i]);
393 for (size_t i = 0; i < lconf.cs_n; i++)
394 uniqueadd(&list, &nlist, &mlist, &lconf.cs_c[i]);
396 for (size_t i = 0; i < nlist; i++)
408 for (f = 1; state_iterate(state, &c, &dbi, f) == 1; f = 0) {
409 if (dbi.id[0] == '\0')
411 (void)run_change("add", &c, dbi.id, sizeof(dbi.id));
416 main(int argc, char *argv[])
418 int c, tout, flags, flush, restore, ret;
419 const char *spath, **blsock;
420 size_t nblsock, maxblsock;
422 setprogname(argv[0]);
426 maxblsock = nblsock = 0;
430 flags = O_RDWR|O_EXCL|O_CLOEXEC;
431 while ((c = getopt(argc, argv, "C:c:D:dfP:rR:s:t:v")) != -1) {
434 controlprog = optarg;
458 if (nblsock >= maxblsock) {
460 void *p = realloc(blsock,
461 sizeof(*blsock) * maxblsock);
464 "Can't allocate memory for %zu sockets",
468 blsock[nblsock++] = optarg;
471 tout = atoi(optarg) * 1000;
485 signal(SIGHUP, sighup);
486 signal(SIGINT, sigdone);
487 signal(SIGQUIT, sigdone);
488 signal(SIGTERM, sigdone);
489 signal(SIGUSR1, sigusr1);
490 signal(SIGUSR2, sigusr2);
492 openlog(getprogname(), LOG_PID, LOG_DAEMON);
504 conf_parse(configfile);
511 struct pollfd *pfd = NULL;
516 for (size_t i = 0; i < nblsock; i++)
517 addfd(&pfd, &bl, &nfd, &maxfd, blsock[i]);
521 FILE *fp = fopen(spath, "r");
524 err(EXIT_FAILURE, "Can't open `%s'", spath);
525 for (; (line = fparseln(fp, NULL, NULL, NULL, 0)) != NULL;
527 addfd(&pfd, &bl, &nfd, &maxfd, line);
531 addfd(&pfd, &bl, &nfd, &maxfd, _PATH_BLSOCK);
533 state = state_open(dbfile, flags, 0600);
535 state = state_open(dbfile, flags | O_CREAT, 0600);
546 if (daemon(0, 0) == -1)
547 err(EXIT_FAILURE, "daemon failed");
548 if (pidfile(NULL) == -1)
549 err(EXIT_FAILURE, "Can't create pidfile");
552 for (size_t t = 0; !done; t++) {
555 conf_parse(configfile);
557 ret = poll(pfd, (nfds_t)nfd, tout);
559 (*lfun)(LOG_DEBUG, "received %d from poll()", ret);
564 (*lfun)(LOG_ERR, "poll (%m)");
570 for (size_t i = 0; i < nfd; i++)
571 if (pfd[i].revents & POLLIN)