1 /* $NetBSD: blacklistd.c,v 1.33 2015/06/21 01:13:21 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.33 2015/06/21 01:13:21 christos Exp $");
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/queue.h>
62 #include <netinet/in.h>
71 static const char *configfile
= _PATH_BLCONF
;
73 static const char *dbfile
= _PATH_BLSTATE
;
74 static sig_atomic_t readconf
;
75 static sig_atomic_t done
;
79 sigusr1(int n __unused
)
85 sigusr2(int n __unused
)
91 sighup(int n __unused
)
97 sigdone(int n __unused
)
106 warnx("Unknown option `%c'", (char)c
);
107 fprintf(stderr
, "Usage: %s [-vdfr] [-c <config>] [-R <rulename>] "
108 "[-P <sockpathsfile>] [-C <controlprog>] [-D <dbfile>] "
109 "[-s <sockpath>] [-t <timeout>]\n", getprogname());
114 getremoteaddress(bl_info_t
*bi
, struct sockaddr_storage
*rss
, socklen_t
*rsl
)
117 memset(rss
, 0, *rsl
);
119 if (getpeername(bi
->bi_fd
, (void *)rss
, rsl
) != -1)
122 if (errno
!= ENOTCONN
) {
123 (*lfun
)(LOG_ERR
, "getpeername failed (%m)");
127 if (bi
->bi_slen
== 0) {
128 (*lfun
)(LOG_ERR
, "unconnected socket with no peer in message");
132 switch (bi
->bi_ss
.ss_family
) {
134 *rsl
= sizeof(struct sockaddr_in
);
137 *rsl
= sizeof(struct sockaddr_in6
);
140 (*lfun
)(LOG_ERR
, "bad client passed socket family %u",
141 (unsigned)bi
->bi_ss
.ss_family
);
145 if (*rsl
!= bi
->bi_slen
) {
146 (*lfun
)(LOG_ERR
, "bad client passed socket length %u != %u",
147 (unsigned)*rsl
, (unsigned)bi
->bi_slen
);
151 memcpy(rss
, &bi
->bi_ss
, *rsl
);
153 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
154 if (*rsl
!= rss
->ss_len
) {
156 "bad client passed socket internal length %u != %u",
157 (unsigned)*rsl
, (unsigned)rss
->ss_len
);
167 struct sockaddr_storage rss
;
175 if (clock_gettime(CLOCK_REALTIME
, &ts
) == -1) {
176 (*lfun
)(LOG_ERR
, "clock_gettime failed (%m)");
180 if ((bi
= bl_recv(bl
)) == NULL
) {
181 (*lfun
)(LOG_ERR
, "no message (%m)");
185 if (getremoteaddress(bi
, &rss
, &rsl
) == -1)
189 sockaddr_snprintf(rbuf
, sizeof(rbuf
), "%a:%p", (void *)&rss
);
190 (*lfun
)(LOG_DEBUG
, "processing type=%d fd=%d remote=%s msg=%s"
191 " uid=%lu gid=%lu", bi
->bi_type
, bi
->bi_fd
, rbuf
,
192 bi
->bi_msg
, (unsigned long)bi
->bi_uid
,
193 (unsigned long)bi
->bi_gid
);
196 if (conf_find(bi
->bi_fd
, bi
->bi_uid
, &rss
, &c
) == NULL
) {
197 (*lfun
)(LOG_DEBUG
, "no rule matched");
202 if (state_get(state
, &c
, &dbi
) == -1)
206 char b1
[128], b2
[128];
207 (*lfun
)(LOG_DEBUG
, "%s: db state info for %s: count=%d/%d "
208 "last=%s now=%s", __func__
, rbuf
, dbi
.count
, c
.c_nfail
,
209 fmttime(b1
, sizeof(b1
), dbi
.last
),
210 fmttime(b2
, sizeof(b2
), ts
.tv_sec
));
213 switch (bi
->bi_type
) {
216 dbi
.last
= ts
.tv_sec
;
219 * We should not be getting this since the rule
220 * should have blocked the address. A possible
221 * explanation is that someone removed that rule,
222 * and another would be that we got another attempt
223 * before we added the rule. In anycase, we remove
224 * and re-add the rule because we don't want to add
225 * it twice, because then we'd lose track of it.
227 (*lfun
)(LOG_DEBUG
, "rule exists %s", dbi
.id
);
228 (void)run_change("rem", &c
, dbi
.id
, 0);
231 if (c
.c_nfail
!= -1 && dbi
.count
>= c
.c_nfail
) {
232 int res
= run_change("add", &c
, dbi
.id
, sizeof(dbi
.id
));
235 sockaddr_snprintf(rbuf
, sizeof(rbuf
), "%a",
238 "blocked %s/%d:%d for %d seconds",
239 rbuf
, c
.c_lmask
, c
.c_port
, c
.c_duration
);
249 (*lfun
)(LOG_ERR
, "unknown message %d", bi
->bi_type
);
251 if (state_put(state
, &c
, &dbi
) == -1)
258 update_interfaces(void)
260 struct ifaddrs
*oifas
, *nifas
;
262 if (getifaddrs(&nifas
) == -1)
282 if (clock_gettime(CLOCK_REALTIME
, &ts
) == -1) {
283 (*lfun
)(LOG_ERR
, "clock_gettime failed (%m)");
288 for (n
= 0, f
= 1; state_iterate(state
, &c
, &dbi
, f
) == 1;
291 time_t when
= c
.c_duration
+ dbi
.last
;
294 sockaddr_snprintf(buf
, sizeof(buf
), "%a:%p", ss
);
295 (*lfun
)(LOG_DEBUG
, "%s:[%u] %s count=%d duration=%d "
296 "last=%s " "now=%s", __func__
, n
, buf
, dbi
.count
,
297 c
.c_duration
, fmttime(b1
, sizeof(b1
), dbi
.last
),
298 fmttime(b2
, sizeof(b2
), ts
.tv_sec
));
300 if (c
.c_duration
== -1 || when
>= ts
.tv_sec
)
303 run_change("rem", &c
, dbi
.id
, 0);
304 sockaddr_snprintf(buf
, sizeof(buf
), "%a", ss
);
305 syslog(LOG_INFO
, "released %s/%d:%d after %d seconds",
306 buf
, c
.c_lmask
, c
.c_port
, c
.c_duration
);
308 state_del(state
, &c
);
314 addfd(struct pollfd
**pfdp
, bl_t
**blp
, size_t *nfd
, size_t *maxfd
,
317 bl_t bl
= bl_create(true, path
, vflag
? vdlog
: vsyslog
);
318 if (bl
== NULL
|| !bl_isconnected(bl
))
320 if (*nfd
>= *maxfd
) {
322 *blp
= realloc(*blp
, sizeof(**blp
) * *maxfd
);
324 err(EXIT_FAILURE
, "malloc");
325 *pfdp
= realloc(*pfdp
, sizeof(**pfdp
) * *maxfd
);
327 err(EXIT_FAILURE
, "malloc");
330 (*pfdp
)[*nfd
].fd
= bl_getfd(bl
);
331 (*pfdp
)[*nfd
].events
= POLLIN
;
337 uniqueadd(struct conf
***listp
, size_t *nlist
, size_t *mlist
, struct conf
*c
)
339 struct conf
**list
= *listp
;
341 if (c
->c_name
[0] == '\0')
343 for (size_t i
= 0; i
< *nlist
; i
++) {
344 if (strcmp(list
[i
]->c_name
, c
->c_name
) == 0)
347 if (*nlist
== *mlist
) {
349 void *p
= realloc(*listp
, *mlist
* sizeof(*list
));
351 err(EXIT_FAILURE
, "Can't allocate for rule list");
354 list
[(*nlist
)++] = c
;
365 for (size_t i
= 0; i
< rconf
.cs_n
; i
++)
366 uniqueadd(&list
, &nlist
, &mlist
, &rconf
.cs_c
[i
]);
367 for (size_t i
= 0; i
< lconf
.cs_n
; i
++)
368 uniqueadd(&list
, &nlist
, &mlist
, &lconf
.cs_c
[i
]);
370 for (size_t i
= 0; i
< nlist
; i
++)
382 for (f
= 1; state_iterate(state
, &c
, &dbi
, f
) == 1; f
= 0) {
383 if (dbi
.id
[0] == '\0')
385 (void)run_change("rem", &c
, dbi
.id
, 0);
386 (void)run_change("add", &c
, dbi
.id
, sizeof(dbi
.id
));
391 main(int argc
, char *argv
[])
393 int c
, tout
, flags
, flush
, restore
;
394 const char *spath
, *blsock
;
396 setprogname(argv
[0]);
399 blsock
= _PATH_BLSOCK
;
403 flags
= O_RDWR
|O_EXCL
|O_CLOEXEC
;
404 while ((c
= getopt(argc
, argv
, "C:c:D:dfP:rR:s:t:v")) != -1) {
407 controlprog
= optarg
;
434 tout
= atoi(optarg
) * 1000;
448 signal(SIGHUP
, sighup
);
449 signal(SIGINT
, sigdone
);
450 signal(SIGQUIT
, sigdone
);
451 signal(SIGTERM
, sigdone
);
452 signal(SIGUSR1
, sigusr1
);
453 signal(SIGUSR2
, sigusr2
);
455 openlog(getprogname(), LOG_PID
, LOG_DAEMON
);
467 conf_parse(configfile
);
476 struct pollfd
*pfd
= NULL
;
482 addfd(&pfd
, &bl
, &nfd
, &maxfd
, blsock
);
484 FILE *fp
= fopen(spath
, "r");
487 err(EXIT_FAILURE
, "Can't open `%s'", spath
);
488 for (; (line
= fparseln(fp
, NULL
, NULL
, NULL
, 0)) != NULL
;
490 addfd(&pfd
, &bl
, &nfd
, &maxfd
, line
);
494 state
= state_open(dbfile
, flags
, 0600);
496 state
= state_open(dbfile
, flags
| O_CREAT
, 0600);
501 if (daemon(0, 0) == -1)
502 err(EXIT_FAILURE
, "daemon failed");
503 if (pidfile(NULL
) == -1)
504 err(EXIT_FAILURE
, "Can't create pidfile");
507 for (size_t t
= 0; !done
; t
++) {
510 conf_parse(configfile
);
512 switch (poll(pfd
, (nfds_t
)nfd
, tout
)) {
516 (*lfun
)(LOG_ERR
, "poll (%m)");
522 for (size_t i
= 0; i
< nfd
; i
++)
523 if (pfd
[i
].revents
& POLLIN
)