I've been work(play?)ing with postscreen for several month, and I thought I'd like to get reverse name of client IP in the postscreen logs too. I guess that the postscreen must process all tests as quickly as possible, so, time consuming functions like DNS resolv, etc. should be asynchronous, parallel, and have appropriate giving-ups ;-)
Attached codes do resolve reverse name of clients and attached it to the log lines. In doing this, I did not added new service for asynchronous resolve, instead, give dnsblog service a second job. -- Yes, this is highly experimental. other modifications are to use these reverse names in the logs and make REJECT logs as seamless as smtpd's (plus, a little bit my favor). patch is diff to postfix-2.8-20101206. any comments would be appreciated. Thanks. -- Tomo.M
diff -ru postfix-2.8-20101206.orig/src/dnsblog/dnsblog.c postfix-2.8-20101206.n2/src/dnsblog/dnsblog.c
--- postfix-2.8-20101206.orig/src/dnsblog/dnsblog.c 2010-10-09 03:01:33.000000000 +0900
+++ postfix-2.8-20101206.n2/src/dnsblog/dnsblog.c 2010-12-08 23:22:32.000000000 +0900
@@ -122,6 +122,7 @@
*/
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
+#define STREQ(x,y) (strcmp((x),(y)) == 0)
/* static void dnsblog_query - query DNSBL for client address */
@@ -208,6 +209,48 @@
return (result);
}
+/* static VSTRING * revname_query - query Reverse Name for client address */
+
+#define CLIENT_NAME_UNKNOWN "unknown"
+#define AIRFORCE_MARK "=*="
+
+static VSTRING *revname_query(VSTRING *result, const char *addr)
+{
+ const char *myname = "revname_query";
+ MAI_HOSTNAME_STR client_name;
+ struct sockaddr_storage ss;
+ struct sockaddr *sa;
+ SOCKADDR_SIZE sa_length;
+ struct addrinfo *res0;
+
+ if (msg_verbose)
+ msg_info("%s: reverse resolve addr %s", myname, addr);
+
+ sa = (struct sockaddr *) & ss;
+
+ if (hostaddr_to_sockaddr(addr, (char *) 0, 0, &res0) != 0)
+ msg_fatal("%s: unable to convert address %s", myname, addr);
+ sa_length = res0->ai_addrlen;
+ if(sa_length > sizeof(ss))
+ sa_length = sizeof(ss);
+ memcpy((char *) sa, res0->ai_addr, sa_length);
+ freeaddrinfo(res0);
+
+ VSTRING_RESET(result);
+ if (sockaddr_to_hostname(sa, sa_length, &client_name,
+ (MAI_SERVNAME_STR *) 0, 0) != 0) {
+ vstring_strcat(result, CLIENT_NAME_UNKNOWN);
+ } else {
+ vstring_strcat(result, client_name.buf);
+ /* stop here so far.
+ * may add further reverse_name validation.
+ */
+ }
+
+ VSTRING_TERMINATE(result);
+ return (result);
+}
+
/* dnsblog_service - perform service for client */
static void dnsblog_service(VSTREAM *client_stream, char *unused_service,
@@ -230,7 +273,10 @@
ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, rbl_domain,
ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, addr,
ATTR_TYPE_END) == 2) {
- (void) dnsblog_query(result, STR(rbl_domain), STR(addr));
+ if (STREQ(STR(rbl_domain), AIRFORCE_MARK))
+ (void) revname_query(result, STR(addr));
+ else
+ (void) dnsblog_query(result, STR(rbl_domain), STR(addr));
if (var_dnsblog_delay > 0)
sleep(var_dnsblog_delay);
attr_print(client_stream, ATTR_FLAG_NONE,
diff -ru postfix-2.8-20101206.orig/src/postscreen/postscreen.c postfix-2.8-20101206.n2/src/postscreen/postscreen.c
--- postfix-2.8-20101206.orig/src/postscreen/postscreen.c 2010-12-06 09:50:12.000000000 +0900
+++ postfix-2.8-20101206.n2/src/postscreen/postscreen.c 2010-12-08 23:22:32.000000000 +0900
@@ -533,6 +533,12 @@
}
/*
+ * request resolve client's reverse name.
+ * XXXX: when to submit request
+ */
+ ps_revname_request(state->smtp_client_addr, (char *) state);
+
+ /*
* Reply with 421 when we can't forward more connections.
*/
if (var_ps_post_queue_limit > 0
diff -ru postfix-2.8-20101206.orig/src/postscreen/postscreen.h postfix-2.8-20101206.n2/src/postscreen/postscreen.h
--- postfix-2.8-20101206.orig/src/postscreen/postscreen.h 2010-12-06 08:37:33.000000000 +0900
+++ postfix-2.8-20101206.n2/src/postscreen/postscreen.h 2010-12-08 23:22:32.000000000 +0900
@@ -64,6 +64,8 @@
char *sender; /* MAIL FROM */
VSTRING *cmd_buffer; /* command read buffer */
int read_state; /* command read state machine */
+ int resolver; /* DNS resolver file descriptor (dnsblog) */
+ char *reverse_name; /* reverse name of client(not checked)*/
} PS_STATE;
#define PS_TIME_STAMP_NEW (0) /* test was never passed */
@@ -317,6 +319,7 @@
*/
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
+#define STREQ(x,y) (strcmp((x),(y)) == 0)
/*
* postscreen_state.c
@@ -324,6 +327,14 @@
#define PS_CLIENT_ADDR_PORT(state) \
(state)->smtp_client_addr, (state)->smtp_client_port
+#define PS_CLIENT_NAME_ADDR(state) \
+ ((state)->reverse_name ? (state)->reverse_name : "unknown"), \
+ (state)->smtp_client_addr
+
+#define PS_CLIENT_NAME_ADDR_PORT(state) \
+ ((state)->reverse_name ? (state)->reverse_name : "unknown"), \
+ (state)->smtp_client_addr, (state)->smtp_client_port
+
#define PS_PASS_SESSION_STATE(state, what, bits) do { \
if (msg_verbose) \
msg_info("PASS %s [%s]:%s", (what), PS_CLIENT_ADDR_PORT(state)); \
@@ -388,6 +399,8 @@
extern void ps_dnsbl_init(void);
extern int ps_dnsbl_retrieve(const char *, const char **, int);
extern int ps_dnsbl_request(const char *, void (*) (int, char *), char *);
+extern void ps_revname_receive(int, char *);
+extern int ps_revname_request(const char *, char *);
/*
* postscreen_tests.c
diff -ru postfix-2.8-20101206.orig/src/postscreen/postscreen_dnsbl.c postfix-2.8-20101206.n2/src/postscreen/postscreen_dnsbl.c
--- postfix-2.8-20101206.orig/src/postscreen/postscreen_dnsbl.c 2010-11-28 06:35:17.000000000 +0900
+++ postfix-2.8-20101206.n2/src/postscreen/postscreen_dnsbl.c 2010-12-08 23:22:32.000000000 +0900
@@ -199,6 +199,10 @@
static VSTRING *reply_dnsbl; /* domain in DNSBLOG reply */
static VSTRING *reply_addr; /* adress list in DNSBLOG reply */
+static VSTRING *reply_client_addr; /* client address in DNSBLOG reply */
+static VSTRING *reply_dummy; /* dummy domain in DNSBLOG reply */
+static VSTRING *reply_reverse_name; /* reverse name in DNSBLOG reply */
+
/* ps_dnsbl_add_site - add DNSBL site information */
static void ps_dnsbl_add_site(const char *site)
@@ -536,4 +540,70 @@
reply_client = vstring_alloc(100);
reply_dnsbl = vstring_alloc(100);
reply_addr = vstring_alloc(100);
+
+ reply_client_addr = vstring_alloc(100);
+ reply_dummy = vstring_alloc(100);
+ reply_reverse_name = vstring_alloc(100);
+}
+
+/* ps_revname_receive - receive reply Reverse Name of client */
+void ps_revname_receive(int event, char *context)
+{
+ const char *myname = "ps_revname_receive";
+ PS_STATE *state = (PS_STATE *)context;
+ VSTREAM *stream;
+
+ if (state->resolver < 0)
+ return;
+
+ PS_CLEAR_EVENT_REQUEST(state->resolver, ps_revname_receive, context);
+
+ stream = vstream_fdopen(state->resolver, O_RDWR);
+ if (attr_scan(stream,
+ ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
+ ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, reply_dummy,
+ ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, reply_client_addr,
+ ATTR_TYPE_STR, MAIL_ATTR_RBL_ADDR, reply_reverse_name,
+ ATTR_TYPE_END) == 3
+ && STREQ(STR(reply_client_addr), state->smtp_client_addr)
+ && LEN(reply_reverse_name) > 0) {
+
+ state->reverse_name = mystrdup(STR(reply_reverse_name));
+ } else {
+ /* XXX */
+ state->reverse_name = mystrdup("unknown");
+ }
+ vstream_fclose(stream);
+ state->resolver = -1;
+}
+
+/* ps_revname_request - request Reverse Name of client */
+#define AIRFORCE_MARK "=*="
+
+int ps_revname_request(const char *client_addr, char *state)
+{
+ const char *myname = "ps_revname_request";
+ int fd;
+ PS_STATE * ctx = (PS_STATE *) state;
+ VSTREAM *stream;
+
+ if ((fd = LOCAL_CONNECT("private/" DNSBL_SERVICE, NON_BLOCKING, 1)) < 0) {
+ msg_warn("%s: connect to " DNSBL_SERVICE " service: %m", myname);
+ ctx->resolver = -1;
+ return(-1);
+ }
+ ctx->resolver = fd;
+ stream = vstream_fdopen(fd, O_RDWR);
+ attr_print(stream, ATTR_FLAG_NONE,
+ ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, AIRFORCE_MARK,
+ ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, client_addr,
+ ATTR_TYPE_END);
+ if (vstream_fflush(stream) != 0) {
+ msg_warn("%s: error sending to " DNSBL_SERVICE " service: %m", myname);
+ vstream_fclose(stream);
+ ctx->resolver = -1;
+ return(-1);
+ }
+ PS_READ_EVENT_REQUEST(fd, ps_revname_receive, state, DNSBLOG_TIMEOUT);
+ return(0);
}
diff -ru postfix-2.8-20101206.orig/src/postscreen/postscreen_early.c postfix-2.8-20101206.n2/src/postscreen/postscreen_early.c
--- postfix-2.8-20101206.orig/src/postscreen/postscreen_early.c 2010-12-06 07:49:28.000000000 +0900
+++ postfix-2.8-20101206.n2/src/postscreen/postscreen_early.c 2010-12-08 23:22:32.000000000 +0900
@@ -106,7 +106,7 @@
* client to a dummy protocol engine, or continue to the next test.
*/
#define PS_DNSBL_FORMAT \
- "%s 5.7.1 Service unavailable; client [%s] blocked using %s\r\n"
+ "%s 4.7.1 <%s[%s]>: Client host rejected: %s\r\n"
if (state->flags & PS_STATE_FLAG_DNSBL_TODO) {
dnsbl_score =
@@ -123,14 +123,14 @@
switch (ps_dnsbl_action) {
case PS_ACT_DROP:
state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
- PS_DNSBL_FORMAT, "521",
- state->smtp_client_addr, dnsbl_name);
+ PS_DNSBL_FORMAT, "421",
+ PS_CLIENT_NAME_ADDR(state), dnsbl_name);
PS_DROP_SESSION_STATE(state, STR(state->dnsbl_reply));
return;
case PS_ACT_ENFORCE:
state->dnsbl_reply = vstring_sprintf(vstring_alloc(100),
- PS_DNSBL_FORMAT, "550",
- state->smtp_client_addr, dnsbl_name);
+ PS_DNSBL_FORMAT, "450",
+ PS_CLIENT_NAME_ADDR(state), dnsbl_name);
PS_ENFORCE_SESSION_STATE(state, STR(state->dnsbl_reply));
break;
case PS_ACT_IGNORE:
diff -ru postfix-2.8-20101206.orig/src/postscreen/postscreen_misc.c postfix-2.8-20101206.n2/src/postscreen/postscreen_misc.c
--- postfix-2.8-20101206.orig/src/postscreen/postscreen_misc.c 2010-12-06 07:50:09.000000000 +0900
+++ postfix-2.8-20101206.n2/src/postscreen/postscreen_misc.c 2010-12-08 23:22:32.000000000 +0900
@@ -108,6 +108,13 @@
"OLD" : "NEW", PS_CLIENT_ADDR_PORT(state));
/*
+ * clear reverse dns resolve request
+ */
+ if (state->resolver >= 0) {
+ ps_revname_receive(EVENT_TIME, (char *) state);
+ }
+
+ /*
* Update the postscreen cache. This still supports a scenario where a
* client gets whitelisted in the course of multiple sessions, as long as
* that client does not "fail" any test.
diff -ru postfix-2.8-20101206.orig/src/postscreen/postscreen_smtpd.c postfix-2.8-20101206.n2/src/postscreen/postscreen_smtpd.c
--- postfix-2.8-20101206.orig/src/postscreen/postscreen_smtpd.c 2010-12-01 07:42:19.000000000 +0900
+++ postfix-2.8-20101206.n2/src/postscreen/postscreen_smtpd.c 2010-12-08 23:22:32.000000000 +0900
@@ -321,9 +321,9 @@
if ((addr = ps_extract_addr(ps_temp, colon + 1)) == 0)
return (PS_SEND_REPLY(state,
"501 5.1.3 Bad recipient address syntax\r\n"));
- msg_info("NOQUEUE: reject: RCPT from [%s]:%s: %.*s; "
- "from=<%s>, to=<%s>, proto=%s, helo=<%s>",
- PS_CLIENT_ADDR_PORT(state),
+ msg_info("NOQUEUE: reject: RCPT from %s[%s]: %.*s; "
+ "from=<%s> to=<%s> proto=%s helo=<%s>",
+ PS_CLIENT_NAME_ADDR(state),
(int) strlen(state->rcpt_reply) - 2, state->rcpt_reply,
state->sender, addr, state->protocol,
state->helo_name ? state->helo_name : "");
@@ -812,6 +812,11 @@
static char *myname = "ps_smtpd_tests";
/*
+ *
+ */
+ msg_info("CLIENT %s[%s]:%s", PS_CLIENT_NAME_ADDR_PORT(state));
+
+ /*
* Report errors and progress in the context of this test.
*/
PS_BEGIN_TESTS(state, "tests after SMTP handshake");
diff -ru postfix-2.8-20101206.orig/src/postscreen/postscreen_state.c postfix-2.8-20101206.n2/src/postscreen/postscreen_state.c
--- postfix-2.8-20101206.orig/src/postscreen/postscreen_state.c 2010-12-01 06:40:55.000000000 +0900
+++ postfix-2.8-20101206.n2/src/postscreen/postscreen_state.c 2010-12-08 23:22:32.000000000 +0900
@@ -163,6 +163,8 @@
state->sender = 0;
state->cmd_buffer = 0;
state->read_state = 0;
+ state->resolver = (-1);
+ state->reverse_name = 0;
/*
* Update the stress level.
@@ -219,6 +221,8 @@
myfree(state->sender);
if (state->cmd_buffer)
vstring_free(state->cmd_buffer);
+ if (state->reverse_name)
+ myfree(state->reverse_name);
myfree((char *) state);
if (ps_check_queue_length < 0 || ps_post_queue_length < 0)
pgpUG81oGBMPL.pgp
Description: PGP signature
