Op Thu, 29 Aug 2013 14:04:59 +0200 schreef Boudewijn Dijkstra <[email protected]>:
Here's a suggested improvement to spamlogd(8) which keeps greytrap entries tarpitted while they keep trying. [...]

Because at least one person expressed an interest in my modification, find below an updated patch that fixes a subtle bug. The previous version could accidentally trap hosts that were just whitelisted but not yet added in the pf table <spamd-white>. The version below leaves these entries alone.

--- spamlogd.c.54       Fri Mar 18 23:37:06 2011
+++ spamlogd.c  Mon Sep  9 10:52:51 2013
@@ -21,7 +21,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */

-/* watch pf log for mail connections, update whitelist entries. */
+/* watch pf log for mail connections, update spamdb entries. */

 #include <sys/types.h>
 #include <sys/socket.h>
@@ -33,6 +33,7 @@
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
+#include <netinet/tcp.h>
 #include <arpa/inet.h>

 #include <net/pfvar.h>
@@ -64,6 +65,7 @@
 int greylist = 1;
 FILE *grey = NULL;

+u_short spamd_port;
 u_short sync_port;
 int syncsend;
 u_int8_t                flag_debug = 0;
@@ -74,13 +76,14 @@
 pcap_t                 *hpcap = NULL;
 struct syslog_data      sdata  = SYSLOG_DATA_INIT;
 time_t                  whiteexp = WHITEEXP;
+time_t                  trapexp = TRAPEXP;
 extern char            *__progname;

 void   logmsg(int , const char *, ...);
 void   sighandler_close(int);
 int    init_pcap(void);
 void   logpkt_handler(u_char *, const struct pcap_pkthdr *, const u_char *);
-int    dbupdate(char *, char *);
+int    dbupdate(char *, char *, int);
 void   usage(void);

 void
@@ -110,9 +113,11 @@
 init_pcap(void)
 {
        struct bpf_program      bpfp;
-       char    filter[PCAPFSIZ] = "ip and port 25 and action pass "
-                   "and tcp[13]&0x12=0x2";
+       char    filter[PCAPFSIZ];

+       snprintf(filter, PCAPFSIZ, "ip and (port 25 or %d) and action pass "
+                   "and tcp[13]&0x12=0x2", spamd_port);
+
        if ((hpcap = pcap_open_live(pflogif, PCAPSNAP, 1, PCAPTIMO,
            errbuf)) == NULL) {
                logmsg(LOG_ERR, "Failed to initialize: %s", errbuf);
@@ -157,6 +162,11 @@
        const struct ip         *ip = NULL;
        const struct pfloghdr   *hdr;
        char                     ipstraddr[40] = { '\0' };
+       int                      white = 1;
+       unsigned int             off;
+       const struct tcphdr     *tcp;
+       unsigned int             iplen;
+       unsigned int             port;

        hdr = (const struct pfloghdr *)sp;
        if (hdr->length < MIN_PFLOG_HDRLEN) {
@@ -185,26 +195,34 @@
                else if (hdr->dir == PF_OUT && !flag_inbound)
                        inet_ntop(af, &ip->ip_dst, ipstraddr,
                            sizeof(ipstraddr));
+               off = ntohs(ip->ip_off);
+               if ((off & 0x1fff) == 0) {
+                       iplen = ip->ip_hl * 4;
+                       tcp = (const struct tcphdr *)(sp + hdrlen + iplen);
+                       port = ntohs(tcp->th_dport);
+                       if (port == spamd_port)
+                               white = 0;
+               }
        }

        if (ipstraddr[0] != '\0') {
-               if (hdr->dir == PF_IN)
-                       logmsg(LOG_DEBUG,"inbound %s", ipstraddr);
-               else
-                       logmsg(LOG_DEBUG,"outbound %s", ipstraddr);
-               dbupdate(PATH_SPAMD_DB, ipstraddr);
+               logmsg(LOG_DEBUG, "%s %s %s",
+                   hdr->dir == PF_IN ? "inbound" : "outbound",
+                   white ? "white" : "spamd",
+                   ipstraddr);
+               dbupdate(PATH_SPAMD_DB, ipstraddr, white);
        }
 }

 int
-dbupdate(char *dbname, char *ip)
+dbupdate(char *dbname, char *ip, int white)
 {
        HASHINFO        hashinfo;
        DBT             dbk, dbd;
        DB              *db;
        struct gdata    gd;
        time_t          now;
-       int             r;
+       int             r, mod;
        struct in_addr  ia;

        now = time(NULL);
@@ -224,7 +242,7 @@
        dbk.data = ip;
        memset(&dbd, 0, sizeof(dbd));

-       /* add or update whitelist entry */
+       /* add or update entry */
        r = db->get(db, &dbk, &dbd, 0);
        if (r == -1) {
                logmsg(LOG_NOTICE, "db->get failed (%m)");
@@ -237,18 +255,11 @@
                gd.first = now;
                gd.bcount = 1;
                gd.pass = now;
-               gd.expire = now + whiteexp;
-               memset(&dbk, 0, sizeof(dbk));
-               dbk.size = strlen(ip);
-               dbk.data = ip;
-               memset(&dbd, 0, sizeof(dbd));
-               dbd.size = sizeof(gd);
-               dbd.data = &gd;
-               r = db->put(db, &dbk, &dbd, 0);
-               if (r) {
-                       logmsg(LOG_NOTICE, "db->put failed (%m)");
-                       goto bad;
-               }
+               if (white) {
+                       gd.expire = now + whiteexp;
+                       mod = 1;
+               } else
+                       mod = 0;
        } else {
                if (dbd.size != sizeof(gd)) {
                        /* whatever this is, it doesn't belong */
@@ -256,8 +267,22 @@
                        goto bad;
                }
                memcpy(&gd, dbd.data, sizeof(gd));
-               gd.pcount++;
-               gd.expire = now + whiteexp;
+               /* leave existing WHITE entries alone */
+               if (gd.pcount >= 0)
+                       mod = 0;
+               else {
+                       if (white) {
+                               gd.expire = now + whiteexp;
+                               gd.pcount++;
+                       } else {
+                               gd.expire = now + trapexp;
+                               gd.bcount++;
+                               gd.pcount = -1;
+                       }
+                       mod = 1;
+               }
+       }
+       if (mod) {
                memset(&dbk, 0, sizeof(dbk));
                dbk.size = strlen(ip);
                dbk.data = ip;
@@ -272,8 +297,12 @@
        }
        db->close(db);
        db = NULL;
-       if (syncsend)
-               sync_white(now, now + whiteexp, ip);
+       if (mod && syncsend) {
+               if (white)
+                       sync_white(now, now + trapexp, ip);
+               else
+                       sync_trapped(now, now + trapexp, ip);
+       }
        return (0);
  bad:
        db->close(db);
@@ -286,7 +315,7 @@
 {
        fprintf(stderr,
            "usage: %s [-DI] [-i interface] [-l pflog_interface] "
-           "[-W whiteexp] [-Y synctarget]\n",
+           "[-W whiteexp] [-T trapexp] [-Y synctarget]\n",
            __progname);
        exit(1);
 }
@@ -303,11 +332,14 @@
        char *sync_baddr = NULL;
        const char *errstr;

+       if ((ent = getservbyname("spamd", "tcp")) == NULL)
+               errx(1, "Can't find service \"spamd\" in /etc/services");
+       spamd_port = ntohs(ent->s_port);
        if ((ent = getservbyname("spamd-sync", "udp")) == NULL)
                errx(1, "Can't find service \"spamd-sync\" in /etc/services");
        sync_port = ntohs(ent->s_port);

-       while ((ch = getopt(argc, argv, "DIi:l:W:Y:")) != -1) {
+       while ((ch = getopt(argc, argv, "DIi:l:T:W:Y:")) != -1) {
                switch (ch) {
                case 'D':
                        flag_debug = 1;
@@ -320,6 +352,14 @@
                        break;
                case 'l':
                        pflogif = optarg;
+                       break;
+               case 'T':
+                       /* limit trapexp to 2160 hours (90 days) */
+                       trapexp = strtonum(optarg, 1, (24 * 90), &errstr);
+                       if (errstr)
+                               usage();
+                       /* convert to seconds from hours */
+                       trapexp *= (60 * 60);
                        break;
                case 'W':
                        /* limit whiteexp to 2160 hours (90 days) */





P.S. the sig in my previous message didn't instruct people to remove the obvious prefix to reply privately. My apologies.
--
(Remove the obvious prefix to reply privately.)
Gemaakt met Opera's e-mailprogramma: http://www.opera.com/mail/

Reply via email to