1 /* $NetBSD: blacklistd.c,v 1.35 2016/09/26 19:43:43 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.35 2016/09/26 19:43:43 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 dbi.last = ts.tv_sec;
222 * We should not be getting this since the rule
223 * should have blocked the address. A possible
224 * explanation is that someone removed that rule,
225 * and another would be that we got another attempt
226 * before we added the rule. In anycase, we remove
227 * and re-add the rule because we don't want to add
228 * it twice, because then we'd lose track of it.
230 (*lfun)(LOG_DEBUG, "rule exists %s", dbi.id);
231 (void)run_change("rem", &c, dbi.id, 0);
234 if (c.c_nfail != -1 && dbi.count >= c.c_nfail) {
235 int res = run_change("add", &c, dbi.id, sizeof(dbi.id));
238 sockaddr_snprintf(rbuf, sizeof(rbuf), "%a",
241 "blocked %s/%d:%d for %d seconds",
242 rbuf, c.c_lmask, c.c_port, c.c_duration);
253 (*lfun)(LOG_ERR, "unknown message %d", bi->bi_type);
255 state_put(state, &c, &dbi);
261 char b1[128], b2[128];
262 (*lfun)(LOG_DEBUG, "%s: final db state for %s: count=%d/%d "
263 "last=%s now=%s", __func__, rbuf, dbi.count, c.c_nfail,
264 fmttime(b1, sizeof(b1), dbi.last),
265 fmttime(b2, sizeof(b2), ts.tv_sec));
270 update_interfaces(void)
272 struct ifaddrs *oifas, *nifas;
274 if (getifaddrs(&nifas) == -1)
294 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
295 (*lfun)(LOG_ERR, "clock_gettime failed (%m)");
300 for (n = 0, f = 1; state_iterate(state, &c, &dbi, f) == 1;
303 time_t when = c.c_duration + dbi.last;
306 sockaddr_snprintf(buf, sizeof(buf), "%a:%p", ss);
307 (*lfun)(LOG_DEBUG, "%s:[%u] %s count=%d duration=%d "
308 "last=%s " "now=%s", __func__, n, buf, dbi.count,
309 c.c_duration, fmttime(b1, sizeof(b1), dbi.last),
310 fmttime(b2, sizeof(b2), ts.tv_sec));
312 if (c.c_duration == -1 || when >= ts.tv_sec)
315 run_change("rem", &c, dbi.id, 0);
316 sockaddr_snprintf(buf, sizeof(buf), "%a", ss);
317 syslog(LOG_INFO, "released %s/%d:%d after %d seconds",
318 buf, c.c_lmask, c.c_port, c.c_duration);
320 state_del(state, &c);
326 addfd(struct pollfd **pfdp, bl_t **blp, size_t *nfd, size_t *maxfd,
329 bl_t bl = bl_create(true, path, vflag ? vdlog : vsyslog);
330 if (bl == NULL || !bl_isconnected(bl))
332 if (*nfd >= *maxfd) {
334 *blp = realloc(*blp, sizeof(**blp) * *maxfd);
336 err(EXIT_FAILURE, "malloc");
337 *pfdp = realloc(*pfdp, sizeof(**pfdp) * *maxfd);
339 err(EXIT_FAILURE, "malloc");
342 (*pfdp)[*nfd].fd = bl_getfd(bl);
343 (*pfdp)[*nfd].events = POLLIN;
349 uniqueadd(struct conf ***listp, size_t *nlist, size_t *mlist, struct conf *c)
351 struct conf **list = *listp;
353 if (c->c_name[0] == '\0')
355 for (size_t i = 0; i < *nlist; i++) {
356 if (strcmp(list[i]->c_name, c->c_name) == 0)
359 if (*nlist == *mlist) {
361 void *p = realloc(*listp, *mlist * sizeof(*list));
363 err(EXIT_FAILURE, "Can't allocate for rule list");
366 list[(*nlist)++] = c;
377 for (size_t i = 0; i < rconf.cs_n; i++)
378 uniqueadd(&list, &nlist, &mlist, &rconf.cs_c[i]);
379 for (size_t i = 0; i < lconf.cs_n; i++)
380 uniqueadd(&list, &nlist, &mlist, &lconf.cs_c[i]);
382 for (size_t i = 0; i < nlist; i++)
394 for (f = 1; state_iterate(state, &c, &dbi, f) == 1; f = 0) {
395 if (dbi.id[0] == '\0')
397 (void)run_change("rem", &c, dbi.id, 0);
398 (void)run_change("add", &c, dbi.id, sizeof(dbi.id));
403 main(int argc, char *argv[])
405 int c, tout, flags, flush, restore, ret;
406 const char *spath, *blsock;
408 setprogname(argv[0]);
411 blsock = _PATH_BLSOCK;
415 flags = O_RDWR|O_EXCL|O_CLOEXEC;
416 while ((c = getopt(argc, argv, "C:c:D:dfP:rR:s:t:v")) != -1) {
419 controlprog = optarg;
446 tout = atoi(optarg) * 1000;
460 signal(SIGHUP, sighup);
461 signal(SIGINT, sigdone);
462 signal(SIGQUIT, sigdone);
463 signal(SIGTERM, sigdone);
464 signal(SIGUSR1, sigusr1);
465 signal(SIGUSR2, sigusr2);
467 openlog(getprogname(), LOG_PID, LOG_DAEMON);
479 conf_parse(configfile);
485 struct pollfd *pfd = NULL;
491 addfd(&pfd, &bl, &nfd, &maxfd, blsock);
493 FILE *fp = fopen(spath, "r");
496 err(EXIT_FAILURE, "Can't open `%s'", spath);
497 for (; (line = fparseln(fp, NULL, NULL, NULL, 0)) != NULL;
499 addfd(&pfd, &bl, &nfd, &maxfd, line);
503 state = state_open(dbfile, flags, 0600);
505 state = state_open(dbfile, flags | O_CREAT, 0600);
513 if (daemon(0, 0) == -1)
514 err(EXIT_FAILURE, "daemon failed");
515 if (pidfile(NULL) == -1)
516 err(EXIT_FAILURE, "Can't create pidfile");
519 for (size_t t = 0; !done; t++) {
522 conf_parse(configfile);
524 ret = poll(pfd, (nfds_t)nfd, tout);
526 (*lfun)(LOG_DEBUG, "received %d from poll()", ret);
531 (*lfun)(LOG_ERR, "poll (%m)");
537 for (size_t i = 0; i < nfd; i++)
538 if (pfd[i].revents & POLLIN)