]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/blacklist/bin/blacklistd.c
dts: Update our copy to be in sync with Linux 5.7
[FreeBSD/FreeBSD.git] / contrib / blacklist / bin / blacklistd.c
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
74 static const char *configfile = _PATH_BLCONF;
75 static DB *state;
76 static const char *dbfile = _PATH_BLSTATE;
77 static sig_atomic_t readconf;
78 static sig_atomic_t done;
79 static int vflag;
80
81 static void
82 sigusr1(int n __unused)
83 {
84         debug++;
85 }
86
87 static void
88 sigusr2(int n __unused)
89 {
90         debug--;
91 }
92
93 static void
94 sighup(int n __unused)
95 {
96         readconf++;
97 }
98
99 static void
100 sigdone(int n __unused)
101 {
102         done++;
103 }
104
105 static __dead void
106 usage(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
116 static int
117 getremoteaddress(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
167 static void
168 process(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
271 out:
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
283 static void
284 update_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
298 static void
299 update(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
313 again:
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
339 static void
340 addfd(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
362 static void
363 uniqueadd(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
383 static void
384 rules_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
401 static void
402 rules_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
415 int
416 main(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 }