1 /* $NetBSD: blacklistd.c,v 1.34 2016/04/04 15:52:56 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.34 2016/04/04 15:52:56 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: db state info 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);
252 (*lfun)(LOG_ERR, "unknown message %d", bi->bi_type);
254 if (state_put(state, &c, &dbi) == -1)
261 update_interfaces(void)
263 struct ifaddrs *oifas, *nifas;
265 if (getifaddrs(&nifas) == -1)
285 if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
286 (*lfun)(LOG_ERR, "clock_gettime failed (%m)");
291 for (n = 0, f = 1; state_iterate(state, &c, &dbi, f) == 1;
294 time_t when = c.c_duration + dbi.last;
297 sockaddr_snprintf(buf, sizeof(buf), "%a:%p", ss);
298 (*lfun)(LOG_DEBUG, "%s:[%u] %s count=%d duration=%d "
299 "last=%s " "now=%s", __func__, n, buf, dbi.count,
300 c.c_duration, fmttime(b1, sizeof(b1), dbi.last),
301 fmttime(b2, sizeof(b2), ts.tv_sec));
303 if (c.c_duration == -1 || when >= ts.tv_sec)
306 run_change("rem", &c, dbi.id, 0);
307 sockaddr_snprintf(buf, sizeof(buf), "%a", ss);
308 syslog(LOG_INFO, "released %s/%d:%d after %d seconds",
309 buf, c.c_lmask, c.c_port, c.c_duration);
311 state_del(state, &c);
317 addfd(struct pollfd **pfdp, bl_t **blp, size_t *nfd, size_t *maxfd,
320 bl_t bl = bl_create(true, path, vflag ? vdlog : vsyslog);
321 if (bl == NULL || !bl_isconnected(bl))
323 if (*nfd >= *maxfd) {
325 *blp = realloc(*blp, sizeof(**blp) * *maxfd);
327 err(EXIT_FAILURE, "malloc");
328 *pfdp = realloc(*pfdp, sizeof(**pfdp) * *maxfd);
330 err(EXIT_FAILURE, "malloc");
333 (*pfdp)[*nfd].fd = bl_getfd(bl);
334 (*pfdp)[*nfd].events = POLLIN;
340 uniqueadd(struct conf ***listp, size_t *nlist, size_t *mlist, struct conf *c)
342 struct conf **list = *listp;
344 if (c->c_name[0] == '\0')
346 for (size_t i = 0; i < *nlist; i++) {
347 if (strcmp(list[i]->c_name, c->c_name) == 0)
350 if (*nlist == *mlist) {
352 void *p = realloc(*listp, *mlist * sizeof(*list));
354 err(EXIT_FAILURE, "Can't allocate for rule list");
357 list[(*nlist)++] = c;
368 for (size_t i = 0; i < rconf.cs_n; i++)
369 uniqueadd(&list, &nlist, &mlist, &rconf.cs_c[i]);
370 for (size_t i = 0; i < lconf.cs_n; i++)
371 uniqueadd(&list, &nlist, &mlist, &lconf.cs_c[i]);
373 for (size_t i = 0; i < nlist; i++)
385 for (f = 1; state_iterate(state, &c, &dbi, f) == 1; f = 0) {
386 if (dbi.id[0] == '\0')
388 (void)run_change("rem", &c, dbi.id, 0);
389 (void)run_change("add", &c, dbi.id, sizeof(dbi.id));
394 main(int argc, char *argv[])
396 int c, tout, flags, flush, restore;
397 const char *spath, *blsock;
399 setprogname(argv[0]);
402 blsock = _PATH_BLSOCK;
406 flags = O_RDWR|O_EXCL|O_CLOEXEC;
407 while ((c = getopt(argc, argv, "C:c:D:dfP:rR:s:t:v")) != -1) {
410 controlprog = optarg;
437 tout = atoi(optarg) * 1000;
451 signal(SIGHUP, sighup);
452 signal(SIGINT, sigdone);
453 signal(SIGQUIT, sigdone);
454 signal(SIGTERM, sigdone);
455 signal(SIGUSR1, sigusr1);
456 signal(SIGUSR2, sigusr2);
458 openlog(getprogname(), LOG_PID, LOG_DAEMON);
470 conf_parse(configfile);
479 struct pollfd *pfd = NULL;
485 addfd(&pfd, &bl, &nfd, &maxfd, blsock);
487 FILE *fp = fopen(spath, "r");
490 err(EXIT_FAILURE, "Can't open `%s'", spath);
491 for (; (line = fparseln(fp, NULL, NULL, NULL, 0)) != NULL;
493 addfd(&pfd, &bl, &nfd, &maxfd, line);
497 state = state_open(dbfile, flags, 0600);
499 state = state_open(dbfile, flags | O_CREAT, 0600);
504 if (daemon(0, 0) == -1)
505 err(EXIT_FAILURE, "daemon failed");
506 if (pidfile(NULL) == -1)
507 err(EXIT_FAILURE, "Can't create pidfile");
510 for (size_t t = 0; !done; t++) {
513 conf_parse(configfile);
515 switch (poll(pfd, (nfds_t)nfd, tout)) {
519 (*lfun)(LOG_ERR, "poll (%m)");
525 for (size_t i = 0; i < nfd; i++)
526 if (pfd[i].revents & POLLIN)