1 1.15 christos /* $NetBSD: blocklistd.c,v 1.15 2026/02/07 14:32:04 christos Exp $ */ 2 1.1 christos 3 1.1 christos /*- 4 1.1 christos * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 1.1 christos * All rights reserved. 6 1.1 christos * 7 1.1 christos * This code is derived from software contributed to The NetBSD Foundation 8 1.1 christos * by Christos Zoulas. 9 1.1 christos * 10 1.1 christos * Redistribution and use in source and binary forms, with or without 11 1.1 christos * modification, are permitted provided that the following conditions 12 1.1 christos * are met: 13 1.1 christos * 1. Redistributions of source code must retain the above copyright 14 1.1 christos * notice, this list of conditions and the following disclaimer. 15 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 christos * notice, this list of conditions and the following disclaimer in the 17 1.1 christos * documentation and/or other materials provided with the distribution. 18 1.1 christos * 19 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 christos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 christos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 christos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 christos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 christos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 christos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 christos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 christos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 christos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 christos * POSSIBILITY OF SUCH DAMAGE. 30 1.1 christos */ 31 1.1 christos #ifdef HAVE_CONFIG_H 32 1.1 christos #include "config.h" 33 1.1 christos #endif 34 1.8 christos 35 1.8 christos #ifdef HAVE_SYS_CDEFS_H 36 1.1 christos #include <sys/cdefs.h> 37 1.8 christos #endif 38 1.15 christos __RCSID("$NetBSD: blocklistd.c,v 1.15 2026/02/07 14:32:04 christos Exp $"); 39 1.1 christos 40 1.1 christos #include <sys/types.h> 41 1.1 christos #include <sys/socket.h> 42 1.1 christos #include <sys/queue.h> 43 1.1 christos 44 1.1 christos #ifdef HAVE_LIBUTIL_H 45 1.1 christos #include <libutil.h> 46 1.1 christos #endif 47 1.1 christos #ifdef HAVE_UTIL_H 48 1.1 christos #include <util.h> 49 1.1 christos #endif 50 1.1 christos #include <string.h> 51 1.1 christos #include <signal.h> 52 1.1 christos #include <netdb.h> 53 1.1 christos #include <stdio.h> 54 1.1 christos #include <stdbool.h> 55 1.1 christos #include <string.h> 56 1.1 christos #include <inttypes.h> 57 1.1 christos #include <syslog.h> 58 1.1 christos #include <ctype.h> 59 1.1 christos #include <limits.h> 60 1.1 christos #include <errno.h> 61 1.1 christos #include <poll.h> 62 1.1 christos #include <fcntl.h> 63 1.1 christos #include <err.h> 64 1.1 christos #include <stdlib.h> 65 1.1 christos #include <unistd.h> 66 1.1 christos #include <time.h> 67 1.1 christos #include <ifaddrs.h> 68 1.1 christos #include <netinet/in.h> 69 1.1 christos 70 1.1 christos #include "bl.h" 71 1.1 christos #include "internal.h" 72 1.1 christos #include "conf.h" 73 1.1 christos #include "run.h" 74 1.1 christos #include "state.h" 75 1.1 christos #include "support.h" 76 1.1 christos 77 1.1 christos static const char *configfile = _PATH_BLCONF; 78 1.1 christos static DB *state; 79 1.1 christos static const char *dbfile = _PATH_BLSTATE; 80 1.1 christos static sig_atomic_t readconf; 81 1.1 christos static sig_atomic_t done; 82 1.1 christos static int vflag; 83 1.1 christos 84 1.1 christos static void 85 1.1 christos sigusr1(int n __unused) 86 1.1 christos { 87 1.1 christos debug++; 88 1.1 christos } 89 1.1 christos 90 1.1 christos static void 91 1.1 christos sigusr2(int n __unused) 92 1.1 christos { 93 1.1 christos debug--; 94 1.1 christos } 95 1.1 christos 96 1.1 christos static void 97 1.1 christos sighup(int n __unused) 98 1.1 christos { 99 1.1 christos readconf++; 100 1.1 christos } 101 1.1 christos 102 1.1 christos static void 103 1.1 christos sigdone(int n __unused) 104 1.1 christos { 105 1.1 christos done++; 106 1.1 christos } 107 1.1 christos 108 1.1 christos static __dead void 109 1.1 christos usage(int c) 110 1.1 christos { 111 1.2 christos if (c != '?') 112 1.1 christos warnx("Unknown option `%c'", (char)c); 113 1.1 christos fprintf(stderr, "Usage: %s [-vdfr] [-c <config>] [-R <rulename>] " 114 1.1 christos "[-P <sockpathsfile>] [-C <controlprog>] [-D <dbfile>] " 115 1.1 christos "[-s <sockpath>] [-t <timeout>]\n", getprogname()); 116 1.1 christos exit(EXIT_FAILURE); 117 1.1 christos } 118 1.1 christos 119 1.1 christos static int 120 1.1 christos getremoteaddress(bl_info_t *bi, struct sockaddr_storage *rss, socklen_t *rsl) 121 1.1 christos { 122 1.1 christos *rsl = sizeof(*rss); 123 1.1 christos memset(rss, 0, *rsl); 124 1.1 christos 125 1.1 christos if (getpeername(bi->bi_fd, (void *)rss, rsl) != -1) 126 1.1 christos return 0; 127 1.1 christos 128 1.1 christos if (errno != ENOTCONN) { 129 1.1 christos (*lfun)(LOG_ERR, "getpeername failed (%m)"); 130 1.1 christos return -1; 131 1.1 christos } 132 1.1 christos 133 1.1 christos if (bi->bi_slen == 0) { 134 1.1 christos (*lfun)(LOG_ERR, "unconnected socket with no peer in message"); 135 1.1 christos return -1; 136 1.1 christos } 137 1.1 christos 138 1.1 christos switch (bi->bi_ss.ss_family) { 139 1.1 christos case AF_INET: 140 1.1 christos *rsl = sizeof(struct sockaddr_in); 141 1.1 christos break; 142 1.1 christos case AF_INET6: 143 1.1 christos *rsl = sizeof(struct sockaddr_in6); 144 1.1 christos break; 145 1.1 christos default: 146 1.1 christos (*lfun)(LOG_ERR, "bad client passed socket family %u", 147 1.1 christos (unsigned)bi->bi_ss.ss_family); 148 1.1 christos return -1; 149 1.1 christos } 150 1.1 christos 151 1.1 christos if (*rsl != bi->bi_slen) { 152 1.1 christos (*lfun)(LOG_ERR, "bad client passed socket length %u != %u", 153 1.1 christos (unsigned)*rsl, (unsigned)bi->bi_slen); 154 1.1 christos return -1; 155 1.1 christos } 156 1.1 christos 157 1.1 christos memcpy(rss, &bi->bi_ss, *rsl); 158 1.1 christos 159 1.1 christos #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 160 1.1 christos if (*rsl != rss->ss_len) { 161 1.1 christos (*lfun)(LOG_ERR, 162 1.1 christos "bad client passed socket internal length %u != %u", 163 1.1 christos (unsigned)*rsl, (unsigned)rss->ss_len); 164 1.1 christos return -1; 165 1.1 christos } 166 1.1 christos #endif 167 1.1 christos return 0; 168 1.1 christos } 169 1.1 christos 170 1.1 christos static void 171 1.1 christos process(bl_t bl) 172 1.1 christos { 173 1.1 christos struct sockaddr_storage rss; 174 1.1 christos socklen_t rsl; 175 1.1 christos char rbuf[BUFSIZ]; 176 1.1 christos bl_info_t *bi; 177 1.1 christos struct conf c; 178 1.1 christos struct dbinfo dbi; 179 1.1 christos struct timespec ts; 180 1.1 christos 181 1.9 christos memset(&dbi, 0, sizeof(dbi)); 182 1.10 christos memset(&c, 0, sizeof(c)); 183 1.1 christos if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { 184 1.1 christos (*lfun)(LOG_ERR, "clock_gettime failed (%m)"); 185 1.1 christos return; 186 1.1 christos } 187 1.1 christos 188 1.1 christos if ((bi = bl_recv(bl)) == NULL) { 189 1.1 christos (*lfun)(LOG_ERR, "no message (%m)"); 190 1.1 christos return; 191 1.1 christos } 192 1.1 christos 193 1.1 christos if (getremoteaddress(bi, &rss, &rsl) == -1) 194 1.13 christos goto out; 195 1.1 christos 196 1.6 christos if (debug || bi->bi_msg[0]) { 197 1.1 christos sockaddr_snprintf(rbuf, sizeof(rbuf), "%a:%p", (void *)&rss); 198 1.6 christos (*lfun)(bi->bi_msg[0] ? LOG_INFO : LOG_DEBUG, 199 1.14 christos "processing type=%d fd=%d remote=%s msg=\"%s\" " 200 1.14 christos "uid=%lu gid=%lu", 201 1.6 christos bi->bi_type, bi->bi_fd, rbuf, 202 1.1 christos bi->bi_msg, (unsigned long)bi->bi_uid, 203 1.1 christos (unsigned long)bi->bi_gid); 204 1.1 christos } 205 1.1 christos 206 1.1 christos if (conf_find(bi->bi_fd, bi->bi_uid, &rss, &c) == NULL) { 207 1.1 christos (*lfun)(LOG_DEBUG, "no rule matched"); 208 1.13 christos goto out; 209 1.1 christos } 210 1.1 christos 211 1.1 christos 212 1.1 christos if (state_get(state, &c, &dbi) == -1) 213 1.13 christos goto out; 214 1.1 christos 215 1.1 christos if (debug) { 216 1.1 christos char b1[128], b2[128]; 217 1.1 christos (*lfun)(LOG_DEBUG, "%s: initial db state for %s: count=%d/%d " 218 1.1 christos "last=%s now=%s", __func__, rbuf, dbi.count, c.c_nfail, 219 1.1 christos fmttime(b1, sizeof(b1), dbi.last), 220 1.1 christos fmttime(b2, sizeof(b2), ts.tv_sec)); 221 1.1 christos } 222 1.1 christos 223 1.1 christos switch (bi->bi_type) { 224 1.1 christos case BL_ABUSE: 225 1.1 christos /* 226 1.7 christos * If the application has signaled abusive behavior, set the 227 1.7 christos * number of fails to be two less than the configured limit. 228 1.7 christos * Fall through to the normal BL_ADD and BL_BADUSER processing, 229 1.11 christos * which will increment the failure count to the threshold, and 230 1.7 christos * block the abusive address. 231 1.1 christos */ 232 1.1 christos if (c.c_nfail != -1) 233 1.7 christos dbi.count = c.c_nfail - 2; 234 1.1 christos /*FALLTHROUGH*/ 235 1.1 christos case BL_ADD: 236 1.7 christos dbi.count++; /* will become += 2 */ 237 1.7 christos /*FALLTHROUGH*/ 238 1.7 christos case BL_BADUSER: 239 1.1 christos dbi.count++; 240 1.1 christos dbi.last = ts.tv_sec; 241 1.1 christos if (c.c_nfail != -1 && dbi.count >= c.c_nfail) { 242 1.1 christos /* 243 1.1 christos * No point in re-adding the rule. 244 1.1 christos * It might exist already due to latency in processing 245 1.1 christos * and removing the rule is the wrong thing to do as 246 1.1 christos * it allows a window to attack again. 247 1.1 christos */ 248 1.1 christos if (dbi.id[0] == '\0') { 249 1.1 christos int res = run_change("add", &c, 250 1.1 christos dbi.id, sizeof(dbi.id)); 251 1.1 christos if (res == -1) 252 1.1 christos goto out; 253 1.1 christos } 254 1.1 christos sockaddr_snprintf(rbuf, sizeof(rbuf), "%a", 255 1.1 christos (void *)&rss); 256 1.1 christos (*lfun)(LOG_INFO, 257 1.1 christos "blocked %s/%d:%d for %d seconds", 258 1.1 christos rbuf, c.c_lmask, c.c_port, c.c_duration); 259 1.1 christos } 260 1.1 christos break; 261 1.1 christos case BL_DELETE: 262 1.1 christos if (dbi.last == 0) 263 1.1 christos goto out; 264 1.1 christos dbi.count = 0; 265 1.1 christos dbi.last = 0; 266 1.1 christos break; 267 1.1 christos default: 268 1.1 christos (*lfun)(LOG_ERR, "unknown message %d", bi->bi_type); 269 1.1 christos } 270 1.1 christos state_put(state, &c, &dbi); 271 1.1 christos 272 1.1 christos out: 273 1.13 christos close(bi->bi_fd); 274 1.13 christos 275 1.1 christos if (debug) { 276 1.1 christos char b1[128], b2[128]; 277 1.1 christos (*lfun)(LOG_DEBUG, "%s: final db state for %s: count=%d/%d " 278 1.1 christos "last=%s now=%s", __func__, rbuf, dbi.count, c.c_nfail, 279 1.1 christos fmttime(b1, sizeof(b1), dbi.last), 280 1.1 christos fmttime(b2, sizeof(b2), ts.tv_sec)); 281 1.1 christos } 282 1.1 christos } 283 1.1 christos 284 1.1 christos static void 285 1.1 christos update_interfaces(void) 286 1.1 christos { 287 1.1 christos struct ifaddrs *oifas, *nifas; 288 1.1 christos 289 1.1 christos if (getifaddrs(&nifas) == -1) 290 1.1 christos return; 291 1.1 christos 292 1.1 christos oifas = ifas; 293 1.1 christos ifas = nifas; 294 1.1 christos 295 1.1 christos if (oifas) 296 1.1 christos freeifaddrs(oifas); 297 1.1 christos } 298 1.1 christos 299 1.1 christos static void 300 1.1 christos update(void) 301 1.1 christos { 302 1.1 christos struct timespec ts; 303 1.1 christos struct conf c; 304 1.1 christos struct dbinfo dbi; 305 1.1 christos unsigned int f, n; 306 1.1 christos char buf[128]; 307 1.1 christos void *ss = &c.c_ss; 308 1.1 christos 309 1.1 christos if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { 310 1.1 christos (*lfun)(LOG_ERR, "clock_gettime failed (%m)"); 311 1.1 christos return; 312 1.1 christos } 313 1.1 christos 314 1.1 christos again: 315 1.1 christos for (n = 0, f = 1; state_iterate(state, &c, &dbi, f) == 1; 316 1.1 christos f = 0, n++) 317 1.1 christos { 318 1.1 christos time_t when = c.c_duration + dbi.last; 319 1.1 christos if (debug > 1) { 320 1.1 christos char b1[64], b2[64]; 321 1.1 christos sockaddr_snprintf(buf, sizeof(buf), "%a:%p", ss); 322 1.1 christos (*lfun)(LOG_DEBUG, "%s:[%u] %s count=%d duration=%d " 323 1.1 christos "last=%s " "now=%s", __func__, n, buf, dbi.count, 324 1.1 christos c.c_duration, fmttime(b1, sizeof(b1), dbi.last), 325 1.1 christos fmttime(b2, sizeof(b2), ts.tv_sec)); 326 1.1 christos } 327 1.1 christos if (c.c_duration == -1 || when >= ts.tv_sec) 328 1.1 christos continue; 329 1.1 christos if (dbi.id[0]) { 330 1.1 christos run_change("rem", &c, dbi.id, 0); 331 1.1 christos sockaddr_snprintf(buf, sizeof(buf), "%a", ss); 332 1.3 christos (*lfun)(LOG_INFO, "released %s/%d:%d after %d seconds", 333 1.1 christos buf, c.c_lmask, c.c_port, c.c_duration); 334 1.1 christos } 335 1.12 christos if (state_del(state, &c) == 0) 336 1.12 christos goto again; 337 1.1 christos } 338 1.1 christos } 339 1.1 christos 340 1.1 christos static void 341 1.1 christos addfd(struct pollfd **pfdp, bl_t **blp, size_t *nfd, size_t *maxfd, 342 1.1 christos const char *path) 343 1.1 christos { 344 1.5 christos bl_t bl = bl_create(true, path, vflag ? vdlog : vsyslog_r); 345 1.1 christos if (bl == NULL || !bl_isconnected(bl)) 346 1.1 christos exit(EXIT_FAILURE); 347 1.1 christos if (*nfd >= *maxfd) { 348 1.1 christos *maxfd += 10; 349 1.15 christos *blp = reallocarray(*blp, *maxfd, sizeof(**blp)); 350 1.1 christos if (*blp == NULL) 351 1.1 christos err(EXIT_FAILURE, "malloc"); 352 1.15 christos *pfdp = reallocarray(*pfdp, *maxfd, sizeof(**pfdp)); 353 1.1 christos if (*pfdp == NULL) 354 1.1 christos err(EXIT_FAILURE, "malloc"); 355 1.1 christos } 356 1.1 christos 357 1.1 christos (*pfdp)[*nfd].fd = bl_getfd(bl); 358 1.1 christos (*pfdp)[*nfd].events = POLLIN; 359 1.1 christos (*blp)[*nfd] = bl; 360 1.1 christos *nfd += 1; 361 1.1 christos } 362 1.1 christos 363 1.1 christos static void 364 1.1 christos uniqueadd(struct conf ***listp, size_t *nlist, size_t *mlist, struct conf *c) 365 1.1 christos { 366 1.1 christos struct conf **list = *listp; 367 1.1 christos 368 1.1 christos if (c->c_name[0] == '\0') 369 1.1 christos return; 370 1.1 christos for (size_t i = 0; i < *nlist; i++) { 371 1.1 christos if (strcmp(list[i]->c_name, c->c_name) == 0) 372 1.1 christos return; 373 1.1 christos } 374 1.1 christos if (*nlist == *mlist) { 375 1.1 christos *mlist += 10; 376 1.15 christos void *p = reallocarray(*listp, *mlist, sizeof(*list)); 377 1.1 christos if (p == NULL) 378 1.1 christos err(EXIT_FAILURE, "Can't allocate for rule list"); 379 1.1 christos list = *listp = p; 380 1.1 christos } 381 1.1 christos list[(*nlist)++] = c; 382 1.1 christos } 383 1.1 christos 384 1.1 christos static void 385 1.1 christos rules_flush(void) 386 1.1 christos { 387 1.1 christos struct conf **list; 388 1.1 christos size_t nlist, mlist; 389 1.1 christos 390 1.1 christos list = NULL; 391 1.1 christos mlist = nlist = 0; 392 1.1 christos for (size_t i = 0; i < rconf.cs_n; i++) 393 1.1 christos uniqueadd(&list, &nlist, &mlist, &rconf.cs_c[i]); 394 1.1 christos for (size_t i = 0; i < lconf.cs_n; i++) 395 1.1 christos uniqueadd(&list, &nlist, &mlist, &lconf.cs_c[i]); 396 1.1 christos 397 1.1 christos for (size_t i = 0; i < nlist; i++) 398 1.1 christos run_flush(list[i]); 399 1.1 christos free(list); 400 1.1 christos } 401 1.1 christos 402 1.1 christos static void 403 1.1 christos rules_restore(void) 404 1.1 christos { 405 1.4 christos DB *db; 406 1.1 christos struct conf c; 407 1.1 christos struct dbinfo dbi; 408 1.1 christos unsigned int f; 409 1.1 christos 410 1.4 christos db = state_open(dbfile, O_RDONLY, 0); 411 1.4 christos if (db == NULL) { 412 1.4 christos (*lfun)(LOG_ERR, "Can't open `%s' to restore state (%m)", 413 1.15 christos dbfile); 414 1.4 christos return; 415 1.4 christos } 416 1.4 christos for (f = 1; state_iterate(db, &c, &dbi, f) == 1; f = 0) { 417 1.1 christos if (dbi.id[0] == '\0') 418 1.1 christos continue; 419 1.1 christos (void)run_change("add", &c, dbi.id, sizeof(dbi.id)); 420 1.4 christos state_put(state, &c, &dbi); 421 1.1 christos } 422 1.4 christos state_close(db); 423 1.4 christos state_sync(state); 424 1.1 christos } 425 1.1 christos 426 1.1 christos int 427 1.1 christos main(int argc, char *argv[]) 428 1.1 christos { 429 1.1 christos int c, tout, flags, flush, restore, ret; 430 1.1 christos const char *spath, **blsock; 431 1.1 christos size_t nblsock, maxblsock; 432 1.1 christos 433 1.1 christos setprogname(argv[0]); 434 1.1 christos 435 1.1 christos spath = NULL; 436 1.1 christos blsock = NULL; 437 1.1 christos maxblsock = nblsock = 0; 438 1.1 christos flush = 0; 439 1.1 christos restore = 0; 440 1.1 christos tout = 0; 441 1.1 christos flags = O_RDWR|O_EXCL|O_CLOEXEC; 442 1.1 christos while ((c = getopt(argc, argv, "C:c:D:dfP:rR:s:t:v")) != -1) { 443 1.1 christos switch (c) { 444 1.1 christos case 'C': 445 1.1 christos controlprog = optarg; 446 1.1 christos break; 447 1.1 christos case 'c': 448 1.1 christos configfile = optarg; 449 1.1 christos break; 450 1.1 christos case 'D': 451 1.1 christos dbfile = optarg; 452 1.1 christos break; 453 1.1 christos case 'd': 454 1.1 christos debug++; 455 1.1 christos break; 456 1.1 christos case 'f': 457 1.1 christos flush++; 458 1.1 christos break; 459 1.1 christos case 'P': 460 1.1 christos spath = optarg; 461 1.1 christos break; 462 1.1 christos case 'R': 463 1.1 christos rulename = optarg; 464 1.1 christos break; 465 1.1 christos case 'r': 466 1.1 christos restore++; 467 1.1 christos break; 468 1.1 christos case 's': 469 1.1 christos if (nblsock >= maxblsock) { 470 1.1 christos maxblsock += 10; 471 1.15 christos void *p = reallocarray(blsock, maxblsock, 472 1.15 christos sizeof(*blsock)); 473 1.1 christos if (p == NULL) 474 1.15 christos err(EXIT_FAILURE, "Can't allocate " 475 1.15 christos "memory for %zu sockets", 476 1.15 christos maxblsock); 477 1.1 christos blsock = p; 478 1.1 christos } 479 1.1 christos blsock[nblsock++] = optarg; 480 1.1 christos break; 481 1.1 christos case 't': 482 1.1 christos tout = atoi(optarg) * 1000; 483 1.1 christos break; 484 1.1 christos case 'v': 485 1.1 christos vflag++; 486 1.1 christos break; 487 1.1 christos default: 488 1.1 christos usage(c); 489 1.1 christos } 490 1.1 christos } 491 1.1 christos 492 1.1 christos argc -= optind; 493 1.1 christos if (argc) 494 1.2 christos usage('?'); 495 1.1 christos 496 1.1 christos signal(SIGHUP, sighup); 497 1.1 christos signal(SIGINT, sigdone); 498 1.1 christos signal(SIGQUIT, sigdone); 499 1.1 christos signal(SIGTERM, sigdone); 500 1.1 christos signal(SIGUSR1, sigusr1); 501 1.1 christos signal(SIGUSR2, sigusr2); 502 1.1 christos 503 1.1 christos openlog(getprogname(), LOG_PID, LOG_DAEMON); 504 1.1 christos 505 1.1 christos if (debug) { 506 1.1 christos lfun = dlog; 507 1.1 christos if (tout == 0) 508 1.1 christos tout = 5000; 509 1.1 christos } else { 510 1.1 christos if (tout == 0) 511 1.1 christos tout = 15000; 512 1.1 christos } 513 1.1 christos 514 1.1 christos update_interfaces(); 515 1.1 christos conf_parse(configfile); 516 1.1 christos if (flush) { 517 1.1 christos rules_flush(); 518 1.1 christos if (!restore) 519 1.1 christos flags |= O_TRUNC; 520 1.1 christos } 521 1.1 christos 522 1.1 christos struct pollfd *pfd = NULL; 523 1.1 christos bl_t *bl = NULL; 524 1.1 christos size_t nfd = 0; 525 1.1 christos size_t maxfd = 0; 526 1.1 christos 527 1.1 christos for (size_t i = 0; i < nblsock; i++) 528 1.1 christos addfd(&pfd, &bl, &nfd, &maxfd, blsock[i]); 529 1.1 christos free(blsock); 530 1.1 christos 531 1.1 christos if (spath) { 532 1.1 christos FILE *fp = fopen(spath, "r"); 533 1.1 christos char *line; 534 1.1 christos if (fp == NULL) 535 1.1 christos err(EXIT_FAILURE, "Can't open `%s'", spath); 536 1.1 christos for (; (line = fparseln(fp, NULL, NULL, NULL, 0)) != NULL; 537 1.1 christos free(line)) 538 1.1 christos addfd(&pfd, &bl, &nfd, &maxfd, line); 539 1.1 christos fclose(fp); 540 1.1 christos } 541 1.1 christos if (nfd == 0) 542 1.1 christos addfd(&pfd, &bl, &nfd, &maxfd, _PATH_BLSOCK); 543 1.1 christos 544 1.1 christos state = state_open(dbfile, flags, 0600); 545 1.1 christos if (state == NULL) 546 1.1 christos state = state_open(dbfile, flags | O_CREAT, 0600); 547 1.14 christos else { 548 1.14 christos if (restore) { 549 1.14 christos if (!flush) 550 1.14 christos rules_flush(); 551 1.14 christos rules_restore(); 552 1.14 christos } 553 1.14 christos } 554 1.1 christos if (state == NULL) 555 1.15 christos exit(EXIT_FAILURE); 556 1.1 christos 557 1.1 christos if (!debug) { 558 1.1 christos if (daemon(0, 0) == -1) 559 1.1 christos err(EXIT_FAILURE, "daemon failed"); 560 1.1 christos if (pidfile(NULL) == -1) 561 1.1 christos err(EXIT_FAILURE, "Can't create pidfile"); 562 1.1 christos } 563 1.1 christos 564 1.1 christos for (size_t t = 0; !done; t++) { 565 1.1 christos if (readconf) { 566 1.1 christos readconf = 0; 567 1.1 christos conf_parse(configfile); 568 1.1 christos } 569 1.1 christos ret = poll(pfd, (nfds_t)nfd, tout); 570 1.13 christos if (debug) 571 1.1 christos (*lfun)(LOG_DEBUG, "received %d from poll()", ret); 572 1.1 christos switch (ret) { 573 1.1 christos case -1: 574 1.1 christos if (errno == EINTR) 575 1.1 christos continue; 576 1.1 christos (*lfun)(LOG_ERR, "poll (%m)"); 577 1.15 christos exit(EXIT_FAILURE); 578 1.1 christos case 0: 579 1.1 christos state_sync(state); 580 1.1 christos break; 581 1.1 christos default: 582 1.1 christos for (size_t i = 0; i < nfd; i++) 583 1.1 christos if (pfd[i].revents & POLLIN) 584 1.1 christos process(bl[i]); 585 1.1 christos } 586 1.1 christos if (t % 100 == 0) 587 1.1 christos state_sync(state); 588 1.1 christos if (t % 10000 == 0) 589 1.1 christos update_interfaces(); 590 1.1 christos update(); 591 1.1 christos } 592 1.1 christos state_close(state); 593 1.15 christos exit(EXIT_SUCCESS); 594 1.1 christos } 595