#!/usr/bin/awk -f # # Usage in smtpd.conf: # filter proc-exec "/path/to/filter-dnsbl " # # Where: # - is a string used to resolve the DNSBL query, returning # only the response, use %s for assembled request, escape % with %%, e.g.: # "dig +short %s" # "host -t A %s | sed 's/^.*has address //'" # - is the DNSBL address-suffix to look up, e.g.: # "ix.dnsbl.manitu.net" # - is a regex, if IP(s) returned by the lookup match they are # considered "blacklisted", e.g.: # "^127\.0\.0\.[234]$" # # Example (smtpd.conf): # filter dnsbl_nixspam proc-exec "filter-dnsbl.awk \"host -t A %s | sed 's/^.*has address //'\" ix.dnsbl.manitu.net '^127\.0\.0\.2$'" BEGIN { if (ARGC != 4) { printf("Error, 4 args expected, got %d\n", ARGC) > "/dev/stderr" exit 1 # note, this will terminate smtpd } RESOLVE_CMD = ARGV[1] DNSBL = ARGV[2] IP_BL = ARGV[3] ARGC = 0 # no more input args / files FS = "|" } "config|ready" == $0 { print("register|filter|smtp-in|connect") > "/dev/stdin" print("register|ready") > "/dev/stdin" next } "filter" == $1 { if (NF < 9) { printf("Error, filter line not having enough fields, 9+ expected, got %d\n", NF) > "/dev/stderr" next # don't exit as this will stop smtpd } sess_id = $6 resp_token = $7 split($9, x, "[.:]") # reverse on the fly and trim port # @@@ note: with version < 0.6 (e.g. $2 == "0.5") the connecting ip is in $10 - not handling version detection, here req = x[4]"."x[3]"."x[2]"."x[1]"."DNSBL # @@@ works only with ipv4 ret = "proceed" cmd = sprintf(RESOLVE_CMD, req) while((cmd | getline r) > 0) { if(r ~ IP_BL) { ret = "reject|550 connecting server is blacklisted" break } } close(cmd) print(sess_id" DNSBL check: "$8" ["$9"]: "cmd" => "ret) > "/dev/stderr" print("filter-result|"sess_id"|"resp_token"|"ret) > "/dev/stdin" }