commit - /dev/null
commit + a248a3c15a4660190d07b7767de9998809d5b144
blob - /dev/null
blob + 0de0555c3d53d804c464490c227553854d447b28 (mode 644)
--- /dev/null
+++ Makefile
+# $OpenBSD: Makefile,v 1.1 2018/04/26 13:57:13 eric Exp $
+
+PROG= dnsbl
+BINDIR= /usr/bin
+SRCS+= main.c smtp_proc.c
+
+.include <bsd.prog.mk>
blob - /dev/null
blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 (mode 644)
blob - /dev/null
blob + 4f77a04cf6f65653b40d1dcc2354aab472a27900 (mode 644)
--- /dev/null
+++ main.c
+#include <sys/socket.h>
+
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "smtp_proc.h"
+
+static char **blacklists = NULL;
+static size_t nblacklists = 0;
+int retries = 0;
+enum filter_decision onfailure = FILTER_PROCEED;
+
+void usage(void);
+enum filter_decision dnsbl_connect(char *, int, time_t, char *, char *,
+ uint64_t, uint64_t, struct smtp_filter_connect *);
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ size_t i;
+ char *line = NULL;
+ size_t linesize = 0;
+ ssize_t linelen;
+ char *msgid, *token, *ip;
+ const char *errstr;
+ int lookup;
+
+ if (pledge("stdio dns", NULL) == -1)
+ err(1, "pledge");
+
+ while ((ch = getopt(argc, argv, "b:f:r:")) != -1) {
+ switch (ch) {
+ case 'b':
+ blacklists = reallocarray(blacklists, nblacklists + 1,
+ sizeof(*blacklists));
+ if (blacklists == NULL)
+ err(1, NULL);
+ if ((blacklists[nblacklists] = strdup(optarg)) == NULL)
+ err(1, NULL);
+ nblacklists++;
+ break;
+ case 'f':
+ if (strcasecmp(optarg, "proceed") == 0)
+ onfailure = FILTER_PROCEED;
+ else if (strcasecmp(optarg, "reject") == 0)
+ onfailure = FILTER_REJECT;
+ else if (strcasecmp(optarg, "disconnect") == 0)
+ onfailure = FILTER_DISCONNECT;
+ else if (strcasecmp(optarg, "rewrite") == 0)
+ onfailure = FILTER_REWRITE;
+ else
+ errx(1, "Invalid on failure case");
+ case 'r':
+ if ((retries = strtonum(optarg, 0, 10, &errstr)) == 0 &&
+ errstr != NULL)
+ errx(1, "retries %s", errstr);
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (nblacklists == 0)
+ errx(1, "No blacklist specified");
+
+ smtp_register_filter_connect(dnsbl_connect);
+ smtp_run();
+
+ return 0;
+}
+
+enum filter_decision
+dnsbl_connect(char *type, int version, time_t tm, char *direction, char *phase,
+ uint64_t reqid, uint64_t token, struct smtp_filter_connect *params)
+{
+ char query[255];
+ char reply[1500];
+ struct hostent *hent;
+ u_char *addr;
+ int i;
+
+ addr = (u_char *)&(params->addr);
+ for (i = 0; i < nblacklists; i++) {
+ if (params->af == AF_INET) {
+ if (snprintf(query, sizeof(query), "%u.%u.%u.%u.%s",
+ addr[3], addr[2], addr[1], addr[0],
+ blacklists[i]) >= sizeof(query))
+ errx(1, "Can't create query, domain too long");
+ } else if (params->af == AF_INET6) {
+ if (snprintf(query, sizeof(query), "%hhx.%hhx.%hhx.%hhx"
+ ".%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx"
+ ".%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx"
+ ".%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%hhx.%s",
+ (u_char) (addr[15] & 0xf), (u_char) (addr[15] >> 4),
+ (u_char) (addr[14] & 0xf), (u_char) (addr[14] >> 4),
+ (u_char) (addr[13] & 0xf), (u_char) (addr[13] >> 4),
+ (u_char) (addr[12] & 0xf), (u_char) (addr[12] >> 4),
+ (u_char) (addr[11] & 0xf), (u_char) (addr[11] >> 4),
+ (u_char) (addr[10] & 0xf), (u_char) (addr[10] >> 4),
+ (u_char) (addr[9] & 0xf), (u_char) (addr[9] >> 4),
+ (u_char) (addr[8] & 0xf), (u_char) (addr[8] >> 4),
+ (u_char) (addr[7] & 0xf), (u_char) (addr[8] >> 4),
+ (u_char) (addr[6] & 0xf), (u_char) (addr[7] >> 4),
+ (u_char) (addr[5] & 0xf), (u_char) (addr[5] >> 4),
+ (u_char) (addr[4] & 0xf), (u_char) (addr[4] >> 4),
+ (u_char) (addr[3] & 0xf), (u_char) (addr[3] >> 4),
+ (u_char) (addr[2] & 0xf), (u_char) (addr[2] >> 4),
+ (u_char) (addr[1] & 0xf), (u_char) (addr[1] >> 4),
+ (u_char) (addr[0] & 0xf), (u_char) (addr[0] >> 4),
+ blacklists[i]) >= sizeof(query))
+ errx(1, "Can't create query, domain too long");
+ } else
+ errx(1, "Invalid address family received");
+ }
+
+ for (i = -1; i < retries; i++) {
+ if ((hent = gethostbyname(query)) == NULL) {
+ if (h_errno == HOST_NOT_FOUND)
+ return FILTER_PROCEED;
+ if (h_errno != TRY_AGAIN)
+ return onfailure;
+ }
+ }
+ return FILTER_REJECT;
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-b blacklist]\n",
+ getprogname());
+ exit(1);
+}
blob - /dev/null
blob + 187b7cd5c48a092120a73d390b13c92987fb1d82 (mode 644)
--- /dev/null
+++ smtp_proc.c
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "smtp_proc.h"
+
+#define NITEMS(x) (sizeof(x) / sizeof(*x))
+
+typedef int (*smtp_cb)(char *, int, time_t, char *, char *, uint64_t, uint64_t,
+ void *);
+
+struct smtp_callback;
+
+static int smtp_register(char *, char *, char *, smtp_cb);
+static void smtp_connect(struct smtp_callback *, int, time_t, uint64_t,
+ uint64_t, char *);
+static void smtp_data(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
+ char *);
+static void smtp_data_line(struct smtp_callback *, int, time_t, uint64_t,
+ uint64_t, char *);
+static void smtp_rset(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
+ char *);
+static void smtp_quit(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
+ char *);
+static void smtp_noop(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
+ char *);
+static void smtp_help(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
+ char *);
+static void smtp_wiz(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
+ char *);
+static void smtp_commit(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
+ char *);
+static void smtp_handle(struct smtp_callback *, int, time_t, uint64_t, uint64_t,
+ void *);
+
+struct smtp_callback {
+ char *type;
+ char *phase;
+ char *direction;
+ void (*smtp_parse)(struct smtp_callback *, int, time_t, uint64_t,
+ uint64_t, char *);
+ smtp_cb cb;
+} smtp_callbacks[] = {
+ {"filter", "connect", "smtp-in", smtp_connect, NULL},
+ {"filter", "data", "smtp-in", smtp_data, NULL},
+ {"filter", "data-line", "smtp-in", smtp_data_line, NULL},
+ {"filter", "rset", "smtp-in", smtp_rset, NULL},
+ {"filter", "quit", "smtp-in", smtp_quit, NULL},
+ {"filter", "noop", "smtp-in", smtp_noop, NULL},
+ {"filter", "help", "smtp-in", smtp_help, NULL},
+ {"filter", "wiz", "smtp-in", smtp_wiz, NULL},
+ {"filter", "commit", "smtp-in", smtp_commit, NULL}
+};
+
+static int ready = 0;
+
+int
+smtp_register_filter_connect(enum filter_decision (*cb)(char *, int, time_t,
+ char *, char *, uint64_t, uint64_t, struct smtp_filter_connect *))
+{
+ return smtp_register("filter", "connect", "smtp-in", (smtp_cb) cb);
+}
+
+void
+smtp_run(void)
+{
+ char *line = NULL;
+ size_t linesize = 0;
+ ssize_t linelen;
+ char *start, *end, *type, *direction, *phase, *params;
+ int version;
+ time_t tm;
+ uint64_t reqid, token;
+ int i;
+
+ printf("register|ready\n");
+ ready = 1;
+
+ while ((linelen = getline(&line, &linesize, stdin)) != -1) {
+ if (line[linelen - 1] != '\n')
+ errx(1, "Invalid line received: missing newline");
+ line[linelen - 1] = '\0';
+ type = line;
+ if ((start = strchr(type, '|')) == NULL)
+ errx(1, "Invalid line received: missing version");
+ start++[0] = '\0';
+ if ((end = strchr(start, '|')) == NULL)
+ errx(1, "Invalid line received: missing time");
+ end++[0] = '\0';
+ if (strcmp(start, "1") != 0)
+ errx(1, "Unsupported protocol received: %s", start);
+ version = 1;
+ start = end;
+ if ((direction = strchr(start, '|')) == NULL)
+ errx(1, "Invalid line received: missing direction");
+ direction++[0] = '\0';
+ tm = (time_t) strtoull(start, &end, 10);
+ if (start[0] == '\0' || end[0] != '\0')
+ errx(1, "Invalid line received: invalid timestamp");
+ if ((phase = strchr(direction, '|')) == NULL)
+ errx(1, "Invalid line receieved: missing phase");
+ phase++[0] = '\0';
+ if ((start = strchr(phase, '|')) == NULL)
+ errx(1, "Invalid line received: missing reqid");
+ start++[0] = '\0';
+ reqid = strtoull(start, &end, 16);
+ if (start[0] == '|' || end[0] != '|')
+ errx(1, "Invalid line received: invalid reqid");
+ end++[0] = '\0';
+ start = end;
+ token = strtoull(start, &end, 16);
+ if (start[0] == '|' || end[0] != '|')
+ errx(1, "Invalid line received: invalid token");
+ params = end + 1;
+
+ for (i = 0; i < NITEMS(smtp_callbacks); i++) {
+ if (strcmp(type, smtp_callbacks[i].type) == 0 &&
+ strcmp(phase, smtp_callbacks[i].phase) == 0 &&
+ strcmp(direction, smtp_callbacks[i].direction) == 0)
+ break;
+ }
+ if (i == NITEMS(smtp_callbacks)) {
+ errx(1, "Invalid line received: received unregistered "
+ "%s: %s", type, phase);
+ }
+ smtp_callbacks[i].smtp_parse(&(smtp_callbacks[i]), version, tm,
+ reqid, token, params);
+ }
+}
+
+static void
+smtp_connect(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
+ uint64_t token, char *params)
+{
+ struct smtp_filter_connect sfconnect;
+ char *address;
+ int ret;
+
+ sfconnect.hostname = params;
+ if ((address = strchr(params, '|')) == NULL)
+ errx(1, "Invalid line received: missing address");
+ address++[0] = '\0';
+
+ sfconnect.af = AF_INET;
+ if (strncasecmp(address, "ipv6:", 5) == 0) {
+ sfconnect.af = AF_INET6;
+ address += 5;
+ }
+
+ ret = inet_pton(sfconnect.af, address, sfconnect.af == AF_INET ?
+ (void *)&(sfconnect.addr) : (void *)&(sfconnect.addr6));
+ if (ret == 0)
+ errx(1, "Invalid line received: Couldn't parse address");
+ if (ret == -1)
+ err(1, "Couldn't convert address");
+
+ smtp_handle(cb, version, tm, reqid, token, (void *)(&sfconnect));
+}
+
+static void
+smtp_data(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
+ uint64_t token, char *params)
+{
+}
+
+static void
+smtp_data_line(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
+ uint64_t token, char *params)
+{
+}
+
+static void
+smtp_rset(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
+ uint64_t token, char *params)
+{
+}
+
+static void
+smtp_quit(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
+ uint64_t token, char *params)
+{
+}
+
+static void
+smtp_noop(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
+ uint64_t token, char *params)
+{
+}
+
+static void
+smtp_help(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
+ uint64_t token, char *params)
+{
+}
+
+static void
+smtp_wiz(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
+ uint64_t token, char *params)
+{
+}
+
+static void
+smtp_commit(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
+ uint64_t token, char *params)
+{
+}
+
+static void
+smtp_handle(struct smtp_callback *cb, int version, time_t tm, uint64_t reqid,
+ uint64_t token, void *params)
+{
+ int ret;
+
+ switch (cb->cb(cb->type, version, tm, cb->direction, cb->phase, reqid,
+ token, params)) {
+ case FILTER_PROCEED:
+ printf("filter-result|%016"PRIx64"|%016"PRIx64"|proceed\n",
+ token, reqid);
+ break;
+ case FILTER_REJECT:
+ printf("filter-result|%016"PRIx64"|%016"PRIx64"|reject|%s\n",
+ token, reqid, "451 Proper message later");
+ break;
+ case FILTER_DISCONNECT:
+ printf("filter-result|%016"PRIx64"|%016"PRIx64"|disconnect|"
+ "%s\n", token, reqid, "421 Proper message later");
+ break;
+ case FILTER_REWRITE:
+ errx(1, "Not sure what is intended here yet");
+ }
+}
+
+static int
+smtp_register(char *type, char *phase, char *direction, smtp_cb cb)
+{
+ int i;
+
+ if (ready) {
+ errx(1, "Can't register when proc is running");
+ }
+ for (i = 0; i < NITEMS(smtp_callbacks); i++) {
+ if (strcmp(type, smtp_callbacks[i].type) == 0 &&
+ strcmp(phase, smtp_callbacks[i].phase) == 0 &&
+ strcmp(direction, smtp_callbacks[i].direction) == 0) {
+ if (smtp_callbacks[i].cb != NULL) {
+ errno = EALREADY;
+ return -1;
+ }
+ smtp_callbacks[i].cb = cb;
+ printf("register|%s|%s|%s\n", type, direction, phase);
+ return 0;
+ }
+ }
+ errno = EINVAL;
+ return -1;
+}
+
+
+//filter|1|1553668146|smtp-in|connect|478cc771bf86f378|5161a9ce4540b4d1|<unknown>|100.64.7.2
blob - /dev/null
blob + e190c1c0fa454eb54f08eb9c220e6d24132495f3 (mode 644)
--- /dev/null
+++ smtp_proc.h
+#include <netinet/in.h>
+
+struct smtp_filter_connect {
+ char *hostname;
+ int af;
+ union {
+ struct in_addr addr;
+ struct in6_addr addr6;
+ };
+};
+
+enum filter_decision {
+ FILTER_PROCEED = 0,
+ FILTER_REJECT,
+ FILTER_DISCONNECT,
+ FILTER_REWRITE
+};
+
+int smtp_register_filter_connect(enum filter_decision (*cb)(char *, int, time_t,
+ char *, char *, uint64_t, uint64_t, struct smtp_filter_connect *));
+void smtp_run(void);