diff options
author | gilles <gilles@poolp.org> | 2016-07-06 17:32:37 +0200 |
---|---|---|
committer | gilles <gilles@poolp.org> | 2016-07-06 17:32:37 +0200 |
commit | 0f08a78d655a165c2dc29f201c6fc1e270ca3a1d (patch) | |
tree | a3e17b7b6d87cf85a16ea2937f2698a8cc1b3f58 | |
parent | remove all experimental filters from -extras (diff) | |
download | OpenSMTPD-extras-0f08a78d655a165c2dc29f201c6fc1e270ca3a1d.tar.xz OpenSMTPD-extras-0f08a78d655a165c2dc29f201c6fc1e270ca3a1d.zip |
experimental filter-dnsbl
-rw-r--r-- | configure.ac | 13 | ||||
-rw-r--r-- | extras/filters/Makefile.am | 4 | ||||
-rw-r--r-- | extras/filters/filter-dnsbl/Makefile.am | 14 | ||||
-rw-r--r-- | extras/filters/filter-dnsbl/filter-dnsbl.8 | 103 | ||||
-rw-r--r-- | extras/filters/filter-dnsbl/filter_dnsbl.c | 187 |
5 files changed, 321 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index ea33729..5f394b7 100644 --- a/configure.ac +++ b/configure.ac @@ -996,6 +996,19 @@ AC_SUBST([pkglibexecdir]) # individual modules # +HAVE_FILTER_DNSBL=no +AC_ARG_WITH([filter-dnsbl], + [ --with-filter-dnsbl Enable filter dnsbl], + [ + if test "x$withval" != "xno" ; then + AC_DEFINE([HAVE_FILTER_DNSBL], [1], + [Define if you have filter dnsbl]) + HAVE_FILTER_DNSBL=yes + fi + ] +) +AM_CONDITIONAL([HAVE_FILTER_DNSBL], [test $HAVE_FILTER_DNSBL = yes]) + HAVE_FILTER_MONKEY=no AC_ARG_WITH([filter-monkey], [ --with-filter-monkey Enable filter monkey], diff --git a/extras/filters/Makefile.am b/extras/filters/Makefile.am index eb670bb..7c7240b 100644 --- a/extras/filters/Makefile.am +++ b/extras/filters/Makefile.am @@ -1,5 +1,9 @@ SUBDIRS = +if HAVE_FILTER_DNSBL +SUBDIRS += filter-dnsbl +endif + if HAVE_FILTER_MONKEY SUBDIRS += filter-monkey endif diff --git a/extras/filters/filter-dnsbl/Makefile.am b/extras/filters/filter-dnsbl/Makefile.am new file mode 100644 index 0000000..1db4695 --- /dev/null +++ b/extras/filters/filter-dnsbl/Makefile.am @@ -0,0 +1,14 @@ +include $(top_srcdir)/mk/paths.mk +include $(top_srcdir)/mk/filter.mk +include $(top_srcdir)/mk/experimental.mk + +pkglibexec_PROGRAMS = filter-dnsbl + +filter_dnsbl_SOURCES = $(SRCS) +filter_dnsbl_SOURCES += filter_dnsbl.c + +man_MANS = filter-dnsbl.8 + +if !NO_LIBASR +LDADD += -lasr +endif diff --git a/extras/filters/filter-dnsbl/filter-dnsbl.8 b/extras/filters/filter-dnsbl/filter-dnsbl.8 new file mode 100644 index 0000000..254a5db --- /dev/null +++ b/extras/filters/filter-dnsbl/filter-dnsbl.8 @@ -0,0 +1,103 @@ +.\" +.\" Copyright (c) 2015, 2016 Joerg Jung <jung@openbsd.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: May 16 2016 $ +.Dt FILTER-DNSBL 8 +.Os +.Sh NAME +.Nm filter-dnsbl +.Nd smtpd filter for DNSBL checks +.Sh SYNOPSIS +.Nm +.Op Fl Cdv +.Op Fl c Ar path +.Op Fl h Ar host +.Op Fl w Ar host +.Sh DESCRIPTION +.Nm +is a filter for +.Xr smtpd 8 +which can be used to check new connections against a +DNS-based Blackhole List (DNSBL) and optional a DNS-based Whitelist (DNSWL). +.Pp +The options are as follows: +.Bl -tag -width "-c path" +.It Fl C +No +.Xr chroot 2 +mode, if this option is specified, +.Nm +will not run in a chroot. +.It Fl c Ar path +Set the chroot +.Ar path . +.Pp +The default +.Ar path +is +.Pa /var/empty +(compile option). +.It Fl d +Debug mode, if this option is specified, +.Nm +will run in the foreground and log to +.Em stderr . +.It Fl h Ar host +Set the DNSBL +.Ar host +to be queried. +.Pp +The default +.Ar host +is dnsbl.sorbs.net. +.It Fl v +Produce more verbose output. +.It Fl w Ar host +Set the DNSWL +.Ar host +to be queried. +.Pp +The default is to not query a DNSWL +.Ar host . +.El +.Pp +.Nm +runs by default in a chroot. +In order to make DNS queries working, a valid +.Pa resolv.conf +is required within the chroot. +.Pp +The debug and verbose options given with the +.Xr smtpd 8 +invocation are intially passed to +.Nm . +.Pp +The remote IP address of new connections is used in a DNS query against the +DNSBL and optional DNSWL. +If the remote address is listed in the DNSBL, the connection is rejected, +otherwise accepted. +If the optional DNSWL host is given, it is queried first and if the remote +address is listed the connection is accepted (without checking the DNSBL). +.Sh SEE ALSO +.Xr chroot 2 , +.Xr filter_api 3 , +.Xr smtpd.conf 5 , +.Xr smtpd 8 +.Sh HISTORY +The first version of +.Nm +was written in 2013. +.Sh AUTHORS +.An Eric Faurot Aq Mt eric@openbsd.org diff --git a/extras/filters/filter-dnsbl/filter_dnsbl.c b/extras/filters/filter-dnsbl/filter_dnsbl.c new file mode 100644 index 0000000..6835538 --- /dev/null +++ b/extras/filters/filter-dnsbl/filter_dnsbl.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> + * Copyright (c) 2016 Joerg Jung <jung@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "includes.h" + +#include <sys/types.h> +#include <sys/socket.h> + +#include <ctype.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <asr.h> + +#include <smtpd-api.h> + +struct dnsbl { + uint64_t id; + struct asr_query *aq_bl, *aq_wl; +}; + +static const char *dnsbl_host = "dnsbl.sorbs.net", *dnswl_host; + +static void +dnsbl_event_black(struct asr_result *ar, void *p) +{ + struct dnsbl *dl = p; + + if (ar->ar_addrinfo) + freeaddrinfo(ar->ar_addrinfo); + if (ar->ar_gai_errno == EAI_NODATA || ar->ar_gai_errno == EAI_NONAME) { + log_info("info: event_black: ACCEPT address"); + filter_api_accept(dl->id); + } else if (ar->ar_gai_errno) { + log_warnx("warn: session %016"PRIx64": event_black: getaddrinfo '%s'", dl->id, gai_strerror(ar->ar_gai_errno)); + filter_api_reject_code(dl->id, FILTER_FAIL, 451, "4.7.1 DNSBL filter failed"); + } else { + log_warnx("warn: session %016"PRIx64": event_black: REJECT address", dl->id); + filter_api_reject_code(dl->id, FILTER_CLOSE, 554, "5.7.1 Address in DNSBL"); + } + free(dl); +} + +static void +dnsbl_event_white(struct asr_result *ar, void *p) +{ + struct dnsbl *dl = p; + + if (ar->ar_addrinfo) + freeaddrinfo(ar->ar_addrinfo); + if (ar->ar_gai_errno == EAI_NODATA || ar->ar_gai_errno == EAI_NONAME) { + log_debug("debug: event_white: address not in DNSWL"); + event_asr_run(dl->aq_bl, dnsbl_event_black, dl); + } else if (ar->ar_gai_errno) { + log_warnx("warn: session %016"PRIx64": event_white: getaddrinfo '%s'", dl->id, gai_strerror(ar->ar_gai_errno)); + filter_api_reject_code(dl->id, FILTER_FAIL, 451, "4.7.1 DNSBL filter failed"); + asr_abort(dl->aq_bl); + free(dl); + } else { + log_info("info: event_white: ACCEPT address"); + filter_api_accept(dl->id); + asr_abort(dl->aq_bl); + free(dl); + } +} + +static struct asr_query * +dnsbl_query(in_addr_t ia, const char *h) +{ + struct asr_query *aq; + struct addrinfo hints; + char buf[512]; + + ia = ntohl(ia); + if (snprintf(buf, sizeof(buf), "%d.%d.%d.%d.%s.", + ia & 0xff, (ia >> 8) & 0xff, (ia >> 16) & 0xff, (ia >> 24) & 0xff, h) >= sizeof(buf)) { + log_warnx("warn: query: host name too long: %s", buf); + return NULL; + } + log_debug("debug: query: checking %s", buf); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if (!(aq = getaddrinfo_async(buf, NULL, &hints, NULL))) { + log_warn("warn: query: getaddrinfo_async"); + return NULL; + } + return aq; +} + +static int +dnsbl_on_connect(uint64_t id, struct filter_connect *conn) +{ + struct dnsbl *dl; + in_addr_t ia; + + if (conn->remote.ss_family != AF_INET) + return filter_api_accept(id); + ia = ((const struct sockaddr_in *)&conn->remote)->sin_addr.s_addr; + dl = xcalloc(1, sizeof(struct dnsbl), "on_connect"); + dl->id = id; + if (!(dl->aq_bl = dnsbl_query(ia, dnsbl_host)) || (dnswl_host && + !(dl->aq_wl = dnsbl_query(ia, dnswl_host)))) { + free(dl); + return filter_api_reject_code(id, FILTER_FAIL, 451, "4.7.1 DNSBL filter failed"); + } + dnswl_host ? event_asr_run(dl->aq_wl, dnsbl_event_white, dl) : + event_asr_run(dl->aq_bl, dnsbl_event_black, dl); + return 1; +} + +int +main(int argc, char **argv) +{ + int ch, C = 0, d = 0, v = 0; + char *c = NULL, *h = NULL, *w = NULL; + + log_init(1); + + while ((ch = getopt(argc, argv, "Cc:dh:vw:")) != -1) { + switch (ch) { + case 'C': + C = 1; + break; + case 'c': + c = optarg; + break; + case 'd': + d = 1; + break; + case 'h': + h = optarg; + break; + case 'v': + v |= TRACE_DEBUG; + break; + case 'w': + w = optarg; + break; + default: + log_warnx("warn: bad option"); + return 1; + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (c) + c = strip(c); + if (h) + dnsbl_host = strip(h); + if (w) + dnswl_host = strip(w); + + log_init(d); + log_verbose(v); + + log_debug("debug: starting..."); + + filter_api_on_connect(dnsbl_on_connect); + if (c) + filter_api_set_chroot(c); /* getaddrinfo requires resolv.conf */ + if (C) + filter_api_no_chroot(); + + filter_api_loop(); + log_debug("debug: exiting"); + + return 1; +} |