Yahoo Groups archive

Milter-greylist

Index last updated: 2026-04-28 23:32 UTC

Message

Re: [milter-greylist] P0f support

2008-08-31 by Patrick Domack

Quoting manu@...:

> We do not need that: we have source and destination IP and ports.
> Do you have an URL with detailed documentation about this internal
> method?

Ok, the point of using udp was for spamass/amavis running on a  
different machine could get that same data (unless we place a header  
in the email with this data in it ourselfs so they don't need to fetch  
it), but from a pure greylisting standpoint, I don't see why the  
milter and p0f would ever be on seperate boxes.

All this code is taken directly from the p0f source package that  
includes samples in a few languages. The header file isn't moved into  
a normal include directoy for inclusion easily :(

#define QUERY_MAGIC             0x0defaced

#define NO_SCORE                -100

/* Masquerade detection flags: */
#define D_GENRE   0x0001
#define D_DETAIL  0x0002
#define D_LINK    0x0004
#define D_DIST    0x0008
#define D_NAT     0x0010
#define D_FW      0x0020
#define D_NAT2_1  0x0040
#define D_FW2_1   0x0080
#define D_NAT2_2  0x0100
#define D_FW2_2   0x0200
#define D_FAST    0x0400
#define D_TNEG    0x0800

#define D_TIME    0x4000
#define D_FAR     0x8000

#define QTYPE_FINGERPRINT       1
#define QTYPE_STATUS            2

struct p0f_query {
   _u32 magic;                   /* must be set to QUERY_MAGIC */
   _u8  type;                    /* QTYPE_* */
   _u32 id;                      /* Unique query ID */
   _u32 src_ad,dst_ad;           /* src address, local dst addr */
   _u16 src_port,dst_port;       /* src and dst ports */
};

#define RESP_OK         0       /* Response OK */
#define RESP_BADQUERY   1       /* Query malformed */
#define RESP_NOMATCH    2       /* No match for src-dst data */
#define RESP_STATUS     255     /* Status information */

struct p0f_response {
   _u32 magic;                   /* QUERY_MAGIC */
   _u32 id;                      /* Query ID (copied from p0f_query) */
   _u8  type;                    /* RESP_* */

   _u8  genre[20];               /* OS genre (empty if no match) */
   _u8  detail[40];              /* OS version (empty if no match) */
   _s8  dist;                    /* Distance (-1 if unknown ) */
   _u8  link[30];                /* Link type (empty if unknown) */
   _u8  tos[30];                 /* Traffic type (empty if unknown) */
   _u8  fw,nat;                  /* firewall and NAT flags flags */
   _u8  real;                    /* A real operating system? */
   _s16 score;                   /* Masquerade score (or NO_SCORE) */
   _u16 mflags;                  /* Masquerade flags (D_*) */
   _s32 uptime;                  /* Uptime in hours (-1 = unknown) */
};


struct p0f_status {
   _u32 magic;                   /* QUERY_MAGIC */
   _u32 id;                      /* Query ID (copied from p0f_query) */
   _u8  type;                    /* RESP_STATUS */

   _u8  version[16];             /* p0f version */
   _u8  mode;                    /* p0f mode (S - SYN; A - SYN+ACK, R  
- RST, O - stray) */
   _u32 fp_cksum;                /* Fingerprint file checksum */
   _u32 cache;                   /* p0f query cache size */
   _u32 packets;                 /* Total number of all packet received */
   _u32 matched;                 /* Total number of packets matched */
   _u32 queries;                 /* Total number of queries handled */
   _u32 cmisses;                 /* Total number of cache query misses */
   _u32 uptime;                  /* Process uptime in seconds */
};



   struct sockaddr_un x;
   struct p0f_query p;
   struct p0f_response r;
   _u32 s,d,sp,dp;
   _s32 sock;

   if (argc != 6) {
     debug("Usage: %s p0f_socket src_ip src_port dst_ip dst_port\n",
           argv[0]);
     exit(1);
   }

   s  = inet_addr(argv[2]);
   sp = atoi(argv[3]);
   d  = inet_addr(argv[4]);
   dp = atoi(argv[5]);

   if (!sp || !dp || s == INADDR_NONE || d == INADDR_NONE)
     fatal("Bad IP/port values.\n");

   sock = socket(PF_UNIX,SOCK_STREAM,0);
   if (sock < 0) pfatal("socket");

   memset(&x,0,sizeof(x));
   x.sun_family=AF_UNIX;
   strncpy(x.sun_path,argv[1],63);

   if (connect(sock,(struct sockaddr*)&x,sizeof(x)))  pfatal(argv[1]);

   p.magic    = QUERY_MAGIC;
   p.id       = 0x12345678;
   p.type     = QTYPE_FINGERPRINT;
   p.src_ad   = s;
   p.dst_ad   = d;
   p.src_port = sp;
   p.dst_port = dp;

   if (write(sock,&p,sizeof(p)) != sizeof(p))
     fatal("Socket write error (timeout?).\n");

   if (read(sock,&r,sizeof(r)) != sizeof(r))
     fatal("Response read error (timeout?).\n");

   if (r.magic != QUERY_MAGIC)
     fatal("Bad response magic.\n");

   if (r.type == RESP_BADQUERY)
     fatal("P0f did not honor our query.\n");

   if (r.type == RESP_NOMATCH) {
     printf("This connection is not (no longer?) in the cache.\n");
     exit(3);
   }

   if (!r.genre[0]) {
     printf("Genre and OS details not recognized.\n");
   } else {
     printf("Genre    : %s\n",r.genre);
     printf("Details  : %s\n",r.detail);
     if (r.dist != -1) printf("Distance : %d hops\n",r.dist);
   }

   if (r.link[0]) printf("Link     : %s\n",r.link);
   if (r.tos[0])  printf("Service  : %s\n",r.tos);

   if (r.uptime != -1)  printf("Uptime   : %d hrs\n",r.uptime);

   if (r.score != NO_SCORE)
     printf("M-Score  : %d%% (flags %x).\n",r.score,r.mflags);

   if (r.fw) printf("The host is behind a firewall.\n");
   if (r.nat) printf("The host is behind NAT or such.\n");

   shutdown(sock,2);
   close(sock);

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.