aboutsummaryrefslogtreecommitdiff
path: root/contrib/blocklist/bin/conf.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/blocklist/bin/conf.c')
-rw-r--r--contrib/blocklist/bin/conf.c200
1 files changed, 169 insertions, 31 deletions
diff --git a/contrib/blocklist/bin/conf.c b/contrib/blocklist/bin/conf.c
index 8f7e75a56be1..f469e28235cd 100644
--- a/contrib/blocklist/bin/conf.c
+++ b/contrib/blocklist/bin/conf.c
@@ -1,4 +1,4 @@
-/* $NetBSD: conf.c,v 1.24 2016/04/04 15:52:56 christos Exp $ */
+/* $NetBSD: conf.c,v 1.10 2025/02/11 17:48:30 christos Exp $ */
/*-
* Copyright (c) 2015 The NetBSD Foundation, Inc.
@@ -32,8 +32,10 @@
#include "config.h"
#endif
+#ifdef HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
-__RCSID("$NetBSD: conf.c,v 1.24 2016/04/04 15:52:56 christos Exp $");
+#endif
+__RCSID("$NetBSD: conf.c,v 1.10 2025/02/11 17:48:30 christos Exp $");
#include <stdio.h>
#ifdef HAVE_LIBUTIL_H
@@ -58,6 +60,7 @@ __RCSID("$NetBSD: conf.c,v 1.24 2016/04/04 15:52:56 christos Exp $");
#include <net/if.h>
#include <net/route.h>
#include <sys/socket.h>
+#include <dirent.h>
#include "bl.h"
#include "internal.h"
@@ -261,7 +264,7 @@ conf_gethostport(const char *f, size_t l, bool local, struct conf *c,
if (debug)
(*lfun)(LOG_DEBUG, "%s: host6 %s", __func__, p);
if (strcmp(p, "*") != 0) {
- if (inet_pton(AF_INET6, p, &sin6->sin6_addr) == -1)
+ if (inet_pton(AF_INET6, p, &sin6->sin6_addr) != 1)
goto out;
sin6->sin6_family = AF_INET6;
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
@@ -269,6 +272,8 @@ conf_gethostport(const char *f, size_t l, bool local, struct conf *c,
#endif
port = &sin6->sin6_port;
}
+ if (!*pstr)
+ pstr = "*";
} else if (pstr != p || strchr(p, '.') || conf_is_interface(p)) {
if (pstr == p)
pstr = "*";
@@ -311,7 +316,7 @@ conf_gethostport(const char *f, size_t l, bool local, struct conf *c,
*port = htons((in_port_t)c->c_port);
return 0;
out:
- (*lfun)(LOG_ERR, "%s: %s, %zu: Bad address [%s]", __func__, f, l, pstr);
+ (*lfun)(LOG_ERR, "%s: %s, %zu: Bad address [%s]", __func__, f, l, p);
return -1;
out1:
(*lfun)(LOG_ERR, "%s: %s, %zu: Can't specify mask %d with "
@@ -407,6 +412,8 @@ conf_parseline(const char *f, size_t l, char *p, struct conf *c, bool local)
{
int e;
+ c->c_lineno = l;
+
while (*p && isspace((unsigned char)*p))
p++;
@@ -471,7 +478,6 @@ conf_amask_eq(const void *v1, const void *v2, size_t len, int mask)
uint32_t m;
int omask = mask;
- len >>= 2;
switch (mask) {
case FSTAR:
if (memcmp(v1, v2, len) == 0)
@@ -485,7 +491,7 @@ conf_amask_eq(const void *v1, const void *v2, size_t len, int mask)
break;
}
- for (size_t i = 0; i < len; i++) {
+ for (size_t i = 0; i < (len >> 2); i++) {
if (mask > 32) {
m = htonl((uint32_t)~0);
mask -= 32;
@@ -501,7 +507,6 @@ conf_amask_eq(const void *v1, const void *v2, size_t len, int mask)
out:
if (debug > 1) {
char b1[256], b2[256];
- len <<= 2;
blhexdump(b1, sizeof(b1), "a1", v1, len);
blhexdump(b2, sizeof(b2), "a2", v2, len);
(*lfun)(LOG_DEBUG, "%s: %s != %s [0x%x]", __func__,
@@ -691,6 +696,25 @@ conf_addr_eq(const struct sockaddr_storage *s1,
static int
conf_eq(const struct conf *c1, const struct conf *c2)
{
+ if (!conf_addr_eq(&c1->c_ss, &c2->c_ss, FSTAR))
+ return 0;
+
+#define CMP(a, b, f) \
+ if ((a)->f != (b)->f) \
+ return 0;
+
+ CMP(c1, c2, c_port);
+ CMP(c1, c2, c_proto);
+ CMP(c1, c2, c_family);
+ CMP(c1, c2, c_uid);
+#undef CMP
+
+ return 1;
+}
+
+static int
+conf_match(const struct conf *c1, const struct conf *c2)
+{
if (!conf_addr_eq(&c1->c_ss, &c2->c_ss, c2->c_lmask))
return 0;
@@ -953,13 +977,54 @@ confset_free(struct confset *cs)
}
static void
-confset_replace(struct confset *dc, struct confset *sc)
+confset_merge(struct confset *dc, struct confset *sc)
{
- struct confset tc;
- tc = *dc;
- *dc = *sc;
- confset_init(sc);
- confset_free(&tc);
+ size_t i, j;
+ char buf[BUFSIZ];
+
+ /* Check each rule of the src confset (sc) */
+ for (i = 0; i < sc->cs_n; i++) {
+ /* Compare to each rule in the dest confset (dc) */
+ for (j = 0; j < dc->cs_n; j++) {
+ if (conf_eq(&dc->cs_c[j], &sc->cs_c[i])) {
+ break;
+ }
+ }
+
+ if (j == dc->cs_n) {
+ /* This is a new rule to add to the dest confset. */
+ if (confset_full(dc) && confset_grow(dc) == -1)
+ return;
+
+ *confset_get(dc) = sc->cs_c[i];
+ confset_add(dc);
+ continue;
+ }
+
+ /* We had a match above. */
+ /*
+ * Check whether the rule from the src confset is more
+ * restrictive than the existing one. Adjust the
+ * existing rule if necessary.
+ */
+ if (sc->cs_c[i].c_nfail == dc->cs_c[j].c_nfail &&
+ sc->cs_c[i].c_duration && dc->cs_c[j].c_duration) {
+ (*lfun)(LOG_DEBUG, "skipping existing rule: %s",
+ conf_print(buf, sizeof (buf), "", "\t", &sc->cs_c[i]));
+ continue;
+ }
+
+ if (sc->cs_c[i].c_nfail < dc->cs_c[j].c_nfail)
+ dc->cs_c[j].c_nfail = sc->cs_c[i].c_nfail;
+
+ if (sc->cs_c[i].c_duration > dc->cs_c[j].c_duration)
+ dc->cs_c[j].c_duration = sc->cs_c[i].c_duration;
+
+ (*lfun)(LOG_DEBUG, "adjusted existing rule: %s",
+ conf_print(buf, sizeof (buf), "", "\t", &dc->cs_c[j]));
+ }
+
+ confset_free(sc);
}
static void
@@ -990,7 +1055,7 @@ confset_match(const struct confset *cs, struct conf *c,
if (debug)
(*lfun)(LOG_DEBUG, "%s", conf_print(buf, sizeof(buf),
"check:\t", "", &cs->cs_c[i]));
- if (conf_eq(c, &cs->cs_c[i])) {
+ if (conf_match(c, &cs->cs_c[i])) {
if (debug)
(*lfun)(LOG_DEBUG, "%s",
conf_print(buf, sizeof(buf),
@@ -1160,21 +1225,14 @@ conf_find(int fd, uid_t uid, const struct sockaddr_storage *rss,
return cr;
}
-
-void
-conf_parse(const char *f)
+static void
+conf_parsefile(FILE *fp, const char *config_file)
{
- FILE *fp;
char *line;
size_t lineno, len;
struct confset lc, rc, *cs;
- if ((fp = fopen(f, "r")) == NULL) {
- (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__, f);
- return;
- }
-
- lineno = 1;
+ lineno = 0;
confset_init(&rc);
confset_init(&lc);
@@ -1197,23 +1255,103 @@ conf_parse(const char *f)
if (confset_grow(cs) == -1) {
confset_free(&lc);
confset_free(&rc);
- fclose(fp);
free(line);
return;
}
}
- if (conf_parseline(f, lineno, line, confset_get(cs),
+ if (conf_parseline(config_file, lineno, line, confset_get(cs),
cs == &lc) == -1)
continue;
confset_add(cs);
}
- fclose(fp);
- confset_sort(&lc);
- confset_sort(&rc);
+ confset_merge(&rconf, &rc);
+ confset_merge(&lconf, &lc);
+}
+
+
+static void
+conf_parsedir(DIR *dir, const char *config_path)
+{
+ long path_max;
+ struct dirent *dent;
+ char *path;
+ FILE *fp;
+
+ if ((path_max = pathconf(config_path, _PC_PATH_MAX)) == -1)
+ path_max = 2048;
+
+ if ((path = malloc((size_t)path_max)) == NULL) {
+ (*lfun)(LOG_ERR, "%s: Failed to allocate memory for path (%m)",
+ __func__);
+ return;
+ }
+
+ while ((dent = readdir(dir)) != NULL) {
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ (void) snprintf(path, (size_t)path_max, "%s/%s", config_path,
+ dent->d_name);
+ if ((fp = fopen(path, "r")) == NULL) {
+ (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__,
+ path);
+ continue;
+ }
+ conf_parsefile(fp, path);
+ fclose(fp);
+ }
+
+ free(path);
+}
+
+void
+conf_parse(const char *config_path)
+{
+ char *path;
+ DIR *dir;
+ FILE *fp;
+
+ if ((dir = opendir(config_path)) != NULL) {
+ /*
+ * If config_path is a directory, parse the configuration files
+ * in the directory. Then we're done here.
+ */
+ conf_parsedir(dir, config_path);
+ closedir(dir);
+ goto out;
+ } else if ((fp = fopen(config_path, "r")) != NULL) {
+ /* If config_path is a file, parse it. */
+ conf_parsefile(fp, config_path);
+ fclose(fp);
+ }
+
+ /*
+ * Append ".d" to config_path, and if that is a directory, parse the
+ * configuration files in the directory.
+ */
+ if (asprintf(&path, "%s.d", config_path) < 0) {
+ (*lfun)(LOG_ERR, "%s: Failed to allocate memory for path (%m)",
+ __func__);
+ goto out;
+ }
+
+ if ((dir = opendir(path)) != NULL) {
+ conf_parsedir(dir, path);
+ closedir(dir);
+ }
+ free(path);
+
+out:
+ if (dir == NULL && fp == NULL) {
+ (*lfun)(LOG_ERR, "%s: Cannot open `%s' (%m)", __func__,
+ config_path);
+ return;
+ }
- confset_replace(&rconf, &rc);
- confset_replace(&lconf, &lc);
+ confset_sort(&lconf);
+ confset_sort(&rconf);
if (debug) {
confset_list(&lconf, "local", "target");