1/*	$NetBSD: blacklistd.c,v 1.38 2019/02/27 02:20:18 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#include <sys/cdefs.h>
35__RCSID("$NetBSD: blacklistd.c,v 1.38 2019/02/27 02:20:18 christos Exp $");
36
37#include <sys/types.h>
38#include <sys/socket.h>
39#include <sys/queue.h>
40
41#ifdef HAVE_LIBUTIL_H
42#include <libutil.h>
43#endif
44#ifdef HAVE_UTIL_H
45#include <util.h>
46#endif
47#include <string.h>
48#include <signal.h>
49#include <netdb.h>
50#include <stdio.h>
51#include <stdbool.h>
52#include <string.h>
53#include <inttypes.h>
54#include <syslog.h>
55#include <ctype.h>
56#include <limits.h>
57#include <errno.h>
58#include <poll.h>
59#include <fcntl.h>
60#include <err.h>
61#include <stdlib.h>
62#include <unistd.h>
63#include <time.h>
64#include <ifaddrs.h>
65#include <netinet/in.h>
66
67#include "bl.h"
68#include "internal.h"
69#include "conf.h"
70#include "run.h"
71#include "state.h"
72#include "support.h"
73
74static const char *configfile = _PATH_BLCONF;
75static DB *state;
76static const char *dbfile = _PATH_BLSTATE;
77static sig_atomic_t readconf;
78static sig_atomic_t done;
79static int vflag;
80
81static void
82sigusr1(int n __unused)
83{
84	debug++;
85}
86
87static void
88sigusr2(int n __unused)
89{
90	debug--;
91}
92
93static void
94sighup(int n __unused)
95{
96	readconf++;
97}
98
99static void
100sigdone(int n __unused)
101{
102	done++;
103}
104
105static __dead void
106usage(int c)
107{
108	if (c)
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());
113	exit(EXIT_FAILURE);
114}
115
116static int
117getremoteaddress(bl_info_t *bi, struct sockaddr_storage *rss, socklen_t *rsl)
118{
119	*rsl = sizeof(*rss);
120	memset(rss, 0, *rsl);
121
122	if (getpeername(bi->bi_fd, (void *)rss, rsl) != -1)
123		return 0;
124
125	if (errno != ENOTCONN) {
126		(*lfun)(LOG_ERR, "getpeername failed (%m)");
127		return -1;
128	}
129
130	if (bi->bi_slen == 0) {
131		(*lfun)(LOG_ERR, "unconnected socket with no peer in message");
132		return -1;
133	}
134
135	switch (bi->bi_ss.ss_family) {
136	case AF_INET:
137		*rsl = sizeof(struct sockaddr_in);
138		break;
139	case AF_INET6:
140		*rsl = sizeof(struct sockaddr_in6);
141		break;
142	default:
143		(*lfun)(LOG_ERR, "bad client passed socket family %u",
144		    (unsigned)bi->bi_ss.ss_family);
145		return -1;
146	}
147
148	if (*rsl != bi->bi_slen) {
149		(*lfun)(LOG_ERR, "bad client passed socket length %u != %u",
150		    (unsigned)*rsl, (unsigned)bi->bi_slen);
151		return -1;
152	}
153
154	memcpy(rss, &bi->bi_ss, *rsl);
155
156#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
157	if (*rsl != rss->ss_len) {
158		(*lfun)(LOG_ERR,
159		    "bad client passed socket internal length %u != %u",
160		    (unsigned)*rsl, (unsigned)rss->ss_len);
161		return -1;
162	}
163#endif
164	return 0;
165}
166
167static void
168process(bl_t bl)
169{
170	struct sockaddr_storage rss;
171	socklen_t rsl;
172	char rbuf[BUFSIZ];
173	bl_info_t *bi;
174	struct conf c;
175	struct dbinfo dbi;
176	struct timespec ts;
177
178	if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
179		(*lfun)(LOG_ERR, "clock_gettime failed (%m)");
180		return;
181	}
182
183	if ((bi = bl_recv(bl)) == NULL) {
184		(*lfun)(LOG_ERR, "no message (%m)");
185		return;
186	}
187
188	if (getremoteaddress(bi, &rss, &rsl) == -1)
189		goto out;
190
191	if (debug) {
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);
197	}
198
199	if (conf_find(bi->bi_fd, bi->bi_uid, &rss, &c) == NULL) {
200		(*lfun)(LOG_DEBUG, "no rule matched");
201		goto out;
202	}
203
204
205	if (state_get(state, &c, &dbi) == -1)
206		goto out;
207
208	if (debug) {
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));
214	}
215
216	switch (bi->bi_type) {
217	case BL_ABUSE:
218		/*
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.
224		 */
225		if (c.c_nfail != -1)
226			dbi.count = c.c_nfail - 1;
227		/*FALLTHROUGH*/
228	case BL_ADD:
229		dbi.count++;
230		dbi.last = ts.tv_sec;
231		if (dbi.id[0]) {
232			/*
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.
240			 */
241			(*lfun)(LOG_DEBUG, "rule exists %s", dbi.id);
242			(void)run_change("rem", &c, dbi.id, 0);
243			dbi.id[0] = '\0';
244		}
245		if (c.c_nfail != -1 && dbi.count >= c.c_nfail) {
246			int res = run_change("add", &c, dbi.id, sizeof(dbi.id));
247			if (res == -1)
248				goto out;
249			sockaddr_snprintf(rbuf, sizeof(rbuf), "%a",
250			    (void *)&rss);
251			(*lfun)(LOG_INFO,
252			    "blocked %s/%d:%d for %d seconds",
253			    rbuf, c.c_lmask, c.c_port, c.c_duration);
254
255		}
256		break;
257	case BL_DELETE:
258		if (dbi.last == 0)
259			goto out;
260		dbi.count = 0;
261		dbi.last = 0;
262		break;
263	case BL_BADUSER:
264		/* ignore for now */
265		break;
266	default:
267		(*lfun)(LOG_ERR, "unknown message %d", bi->bi_type);
268	}
269	state_put(state, &c, &dbi);
270
271out:
272	close(bi->bi_fd);
273
274	if (debug) {
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));
280	}
281}
282
283static void
284update_interfaces(void)
285{
286	struct ifaddrs *oifas, *nifas;
287
288	if (getifaddrs(&nifas) == -1)
289		return;
290
291	oifas = ifas;
292	ifas = nifas;
293
294	if (oifas)
295		freeifaddrs(oifas);
296}
297
298static void
299update(void)
300{
301	struct timespec ts;
302	struct conf c;
303	struct dbinfo dbi;
304	unsigned int f, n;
305	char buf[128];
306	void *ss = &c.c_ss;
307
308	if (clock_gettime(CLOCK_REALTIME, &ts) == -1) {
309		(*lfun)(LOG_ERR, "clock_gettime failed (%m)");
310		return;
311	}
312
313again:
314	for (n = 0, f = 1; state_iterate(state, &c, &dbi, f) == 1;
315	    f = 0, n++)
316	{
317		time_t when = c.c_duration + dbi.last;
318		if (debug > 1) {
319			char b1[64], b2[64];
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));
325		}
326		if (c.c_duration == -1 || when >= ts.tv_sec)
327			continue;
328		if (dbi.id[0]) {
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);
333		}
334		state_del(state, &c);
335		goto again;
336	}
337}
338
339static void
340addfd(struct pollfd **pfdp, bl_t **blp, size_t *nfd, size_t *maxfd,
341    const char *path)
342{
343	bl_t bl = bl_create(true, path, vflag ? vdlog : vsyslog);
344	if (bl == NULL || !bl_isconnected(bl))
345		exit(EXIT_FAILURE);
346	if (*nfd >= *maxfd) {
347		*maxfd += 10;
348		*blp = realloc(*blp, sizeof(**blp) * *maxfd);
349		if (*blp == NULL)
350			err(EXIT_FAILURE, "malloc");
351		*pfdp = realloc(*pfdp, sizeof(**pfdp) * *maxfd);
352		if (*pfdp == NULL)
353			err(EXIT_FAILURE, "malloc");
354	}
355
356	(*pfdp)[*nfd].fd = bl_getfd(bl);
357	(*pfdp)[*nfd].events = POLLIN;
358	(*blp)[*nfd] = bl;
359	*nfd += 1;
360}
361
362static void
363uniqueadd(struct conf ***listp, size_t *nlist, size_t *mlist, struct conf *c)
364{
365	struct conf **list = *listp;
366
367	if (c->c_name[0] == '\0')
368		return;
369	for (size_t i = 0; i < *nlist; i++) {
370		if (strcmp(list[i]->c_name, c->c_name) == 0)
371			return;
372	}
373	if (*nlist == *mlist) {
374		*mlist += 10;
375		void *p = realloc(*listp, *mlist * sizeof(*list));
376		if (p == NULL)
377			err(EXIT_FAILURE, "Can't allocate for rule list");
378		list = *listp = p;
379	}
380	list[(*nlist)++] = c;
381}
382
383static void
384rules_flush(void)
385{
386	struct conf **list;
387	size_t nlist, mlist;
388
389	list = NULL;
390	mlist = nlist = 0;
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]);
395
396	for (size_t i = 0; i < nlist; i++)
397		run_flush(list[i]);
398	free(list);
399}
400
401static void
402rules_restore(void)
403{
404	struct conf c;
405	struct dbinfo dbi;
406	unsigned int f;
407
408	for (f = 1; state_iterate(state, &c, &dbi, f) == 1; f = 0) {
409		if (dbi.id[0] == '\0')
410			continue;
411		(void)run_change("add", &c, dbi.id, sizeof(dbi.id));
412	}
413}
414
415int
416main(int argc, char *argv[])
417{
418	int c, tout, flags, flush, restore, ret;
419	const char *spath, **blsock;
420	size_t nblsock, maxblsock;
421
422	setprogname(argv[0]);
423
424	spath = NULL;
425	blsock = NULL;
426	maxblsock = nblsock = 0;
427	flush = 0;
428	restore = 0;
429	tout = 0;
430	flags = O_RDWR|O_EXCL|O_CLOEXEC;
431	while ((c = getopt(argc, argv, "C:c:D:dfP:rR:s:t:v")) != -1) {
432		switch (c) {
433		case 'C':
434			controlprog = optarg;
435			break;
436		case 'c':
437			configfile = optarg;
438			break;
439		case 'D':
440			dbfile = optarg;
441			break;
442		case 'd':
443			debug++;
444			break;
445		case 'f':
446			flush++;
447			break;
448		case 'P':
449			spath = optarg;
450			break;
451		case 'R':
452			rulename = optarg;
453			break;
454		case 'r':
455			restore++;
456			break;
457		case 's':
458			if (nblsock >= maxblsock) {
459				maxblsock += 10;
460				void *p = realloc(blsock,
461				    sizeof(*blsock) * maxblsock);
462				if (p == NULL)
463				    err(EXIT_FAILURE,
464					"Can't allocate memory for %zu sockets",
465					maxblsock);
466				blsock = p;
467			}
468			blsock[nblsock++] = optarg;
469			break;
470		case 't':
471			tout = atoi(optarg) * 1000;
472			break;
473		case 'v':
474			vflag++;
475			break;
476		default:
477			usage(c);
478		}
479	}
480
481	argc -= optind;
482	if (argc)
483		usage(0);
484
485	signal(SIGHUP, sighup);
486	signal(SIGINT, sigdone);
487	signal(SIGQUIT, sigdone);
488	signal(SIGTERM, sigdone);
489	signal(SIGUSR1, sigusr1);
490	signal(SIGUSR2, sigusr2);
491
492	openlog(getprogname(), LOG_PID, LOG_DAEMON);
493
494	if (debug) {
495		lfun = dlog;
496		if (tout == 0)
497			tout = 5000;
498	} else {
499		if (tout == 0)
500			tout = 15000;
501	}
502
503	update_interfaces();
504	conf_parse(configfile);
505	if (flush) {
506		rules_flush();
507		if (!restore)
508			flags |= O_TRUNC;
509	}
510
511	struct pollfd *pfd = NULL;
512	bl_t *bl = NULL;
513	size_t nfd = 0;
514	size_t maxfd = 0;
515
516	for (size_t i = 0; i < nblsock; i++)
517		addfd(&pfd, &bl, &nfd, &maxfd, blsock[i]);
518	free(blsock);
519
520	if (spath) {
521		FILE *fp = fopen(spath, "r");
522		char *line;
523		if (fp == NULL)
524			err(EXIT_FAILURE, "Can't open `%s'", spath);
525		for (; (line = fparseln(fp, NULL, NULL, NULL, 0)) != NULL;
526		    free(line))
527			addfd(&pfd, &bl, &nfd, &maxfd, line);
528		fclose(fp);
529	}
530	if (nfd == 0)
531		addfd(&pfd, &bl, &nfd, &maxfd, _PATH_BLSOCK);
532
533	state = state_open(dbfile, flags, 0600);
534	if (state == NULL)
535		state = state_open(dbfile,  flags | O_CREAT, 0600);
536	if (state == NULL)
537		return EXIT_FAILURE;
538
539	if (restore) {
540		if (!flush)
541			rules_flush();
542		rules_restore();
543	}
544
545	if (!debug) {
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");
550	}
551
552	for (size_t t = 0; !done; t++) {
553		if (readconf) {
554			readconf = 0;
555			conf_parse(configfile);
556		}
557		ret = poll(pfd, (nfds_t)nfd, tout);
558		if (debug)
559			(*lfun)(LOG_DEBUG, "received %d from poll()", ret);
560		switch (ret) {
561		case -1:
562			if (errno == EINTR)
563				continue;
564			(*lfun)(LOG_ERR, "poll (%m)");
565			return EXIT_FAILURE;
566		case 0:
567			state_sync(state);
568			break;
569		default:
570			for (size_t i = 0; i < nfd; i++)
571				if (pfd[i].revents & POLLIN)
572					process(bl[i]);
573		}
574		if (t % 100 == 0)
575			state_sync(state);
576		if (t % 10000 == 0)
577			update_interfaces();
578		update();
579	}
580	state_close(state);
581	return 0;
582}
583