diff -Naur spamass-milter-0.1.3a/spamass-milter.cpp spamass-milter-0.1.3a.gugu/spamass-milter.cpp --- spamass-milter-0.1.3a/spamass-milter.cpp 2002-12-31 18:03:13.000000000 -0200 +++ spamass-milter-0.1.3a.gugu/spamass-milter.cpp 2003-01-07 10:30:53.000000000 -0200 @@ -80,6 +80,7 @@ #include #include #include +#include // C++ includes #include @@ -88,6 +89,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -111,7 +113,7 @@ "SpamAssassin", // filter name SMFI_VERSION, // version code -- leave untouched SMFIF_ADDHDRS|SMFIF_CHGHDRS|SMFIF_CHGBODY, // flags - NULL, // info filter callback + NULL, // connect info filter callback NULL, // HELO filter callback mlfi_envfrom, // envelope sender filter callback mlfi_envrcpt, // envelope recipient filter callback @@ -123,7 +125,93 @@ mlfi_close, // connection cleanup callback }; +static vector accepted_domains; +typedef pair masked_ip; +static vector accepted_networks; + +static void tolower(string& s) +{ + for (int i=0; i < s.size(); ++i) { + s[i] = tolower(s[i]); + } +} + +static void accept_relay(const char *relay_) +{ + string relay(relay_); + string::size_type noquad = relay.find_first_not_of("0123456789./"); + + if (noquad != string::npos) { // domain name + tolower(relay); + accepted_domains.push_back(relay); + } else { + string::size_type slash = relay.find_first_of('/'); + unsigned long mask = 0xffffffff; + if (slash != string::npos) { // net/mask + mask = inet_addr(relay.c_str() + slash + 1); + if (mask == INADDR_NONE) { + cerr << "error: Invalid netmask in relay spec (" << relay_ << ")."; + exit(1); + } + relay.erase(slash); + } + unsigned long net = inet_addr(relay.c_str()); + if (net == INADDR_NONE) { + cerr << "error: Invalid network in relay spec (" << relay_ << ")."; + exit(1); + } + + accepted_networks.push_back(make_pair(net&mask, mask)); + } +} + +static void dump_accepted_relays() +{ + for (vector::iterator i = accepted_domains.begin(); + i != accepted_domains.end(); ++i) { + debug(2, "accept_relay(%s)", i->c_str()); + } + for (vector::iterator i = accepted_networks.begin(); + i != accepted_networks.end(); ++i) { + debug(2, "accept_relay(%08lx, %08lx)", ntohl(i->first), ntohl(i->second)); + } +} + +static bool is_accepted_relay(char *hostname, _SOCK_ADDR *hostaddr) +{ + if (hostname && accepted_domains.size()) { + string name(hostname); + tolower(name); + for (vector::iterator i = accepted_domains.begin(); + i != accepted_domains.end(); ++i) { + if (name.size() >= i->size() + && name.substr(name.size() - i->size(), i->size()) == *i) { + debug(3, "accept_relay(%s)", hostname); + return true; + } + } + debug(3, "dont accept_relay(%s)", hostname); + } + + if (hostaddr + && hostaddr->sa_family == AF_INET + && accepted_networks.size()) { + unsigned long net = reinterpret_cast(hostaddr)->sin_addr.s_addr; + for (vector::iterator i = accepted_networks.begin(); + i != accepted_networks.end(); ++i) { + if ((net & i->second) == i->first) { + debug(3, "accept_relay(%08lx)", ntohl(net)); + return true; + } + } + debug(3, "dont accept_relay(%08lx)", ntohl(net)); + } + + return false; +} + int flag_debug = 0; +bool flag_accept=false; bool flag_reject = false; bool flag_sniffuser = false; int reject_score = -1; @@ -136,7 +224,7 @@ main(int argc, char* argv[]) { int c, err = 0; - const char *args = "p:fd:mr:u:"; + const char *args = "p:A:fd:mr:u:"; char *sock = NULL; bool dofork = false; @@ -146,6 +234,10 @@ case 'p': sock = strdup(optarg); break; + case 'A': + flag_accept = true; + accept_relay(optarg); + break; case 'f': dofork = true; break; @@ -172,8 +264,9 @@ if (!sock || err) { cout << PACKAGE_NAME << " - Version " << PACKAGE_VERSION << endl; cout << "SpamAssassin Sendmail Milter Plugin" << endl; - cout << "Usage: spamass-milter -p socket [-d nn] [-f] [-m] [-r nn] [-u user]" << endl; + cout << "Usage: spamass-milter -p socket [-A relay] [-d nn] [-f] [-m] [-r nn] [-u user]" << endl; cout << " -p socket: path to create socket" << endl; + cout << " -A: accept relay by domain name or n.n.n.n/m.m.m.m network spec" << endl; cout << " -d nn: set debug level to nn (1-3). Logs to syslog" << endl; cout << " -f: fork into background" << endl; cout << " -m: don't modify body, Content-type: or Subject:" << endl; @@ -203,6 +296,18 @@ openlog("spamass-milter", LOG_PID, LOG_MAIL); + if (dontmodify) { + // Tell sendmail we won't change bodies so that it doesn't need + // to be prepared for that. + smfilter.xxfi_flags &= ~SMFIF_CHGBODY; + } + + if (flag_accept) { + // Make sendmail call our connect callback if we need to. + smfilter.xxfi_connect = mlfi_connect; + dump_accepted_relays(); + } + (void) smfi_setconn(sock); if (smfi_register(smfilter) == MI_FAILURE) { fprintf(stderr, "smfi_register failed\n"); @@ -375,6 +480,25 @@ // {{{ MLFI callbacks // +// Gets called at the start of a SMTP connection +// +// checks if the messages in this connection should be accepted +// +sfsistat +mlfi_connect(SMFICTX* ctx, char* hostname, _SOCK_ADDR *hostaddr) +{ + debug(1, "mlfi_connect: enter"); + + if (is_accepted_relay(hostname, hostaddr)) { + debug(1, "mlfi_connect: accept"); + return SMFIS_ACCEPT; + } else { + debug(1, "mlfi_connect: continue"); + return SMFIS_CONTINUE; + } +} + +// // Gets called first for all messages // // creates SpamAssassin object and makes pointer to it diff -Naur spamass-milter-0.1.3a/spamass-milter.h spamass-milter-0.1.3a.gugu/spamass-milter.h --- spamass-milter-0.1.3a/spamass-milter.h 2002-12-23 15:08:30.000000000 -0200 +++ spamass-milter-0.1.3a.gugu/spamass-milter.h 2003-01-07 10:14:12.000000000 -0200 @@ -30,6 +30,7 @@ string retrieve_field(const string&, const string&); +sfsistat mlfi_connect(SMFICTX*, char*, _SOCK_ADDR *); sfsistat mlfi_envrcpt(SMFICTX*, char**); sfsistat mlfi_envfrom(SMFICTX*, char**); sfsistat mlfi_header(SMFICTX*, char*, char*);