From c9dac291902168d8e0c2e4edd74997fa8f00b9b0 Mon Sep 17 00:00:00 2001 From: Art Cancro Date: Wed, 7 Sep 2005 03:08:07 +0000 Subject: [PATCH] * When rejecting a message due to RBL, give the alleged spammers the relevant TXT record if there is one. Hopefully. This needs testing. --- citadel/ChangeLog | 5 +- citadel/locate_host.c | 135 ++++++++++++++++++++++++++++++++++++++++-- citadel/locate_host.h | 1 + 3 files changed, 134 insertions(+), 7 deletions(-) diff --git a/citadel/ChangeLog b/citadel/ChangeLog index c66ca2ed2..5651cb27c 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -1,4 +1,8 @@ $Log$ +Revision 654.23 2005/09/07 03:08:06 ajc +* When rejecting a message due to RBL, give the alleged spammers the + relevant TXT record if there is one. Hopefully. This needs testing. + Revision 654.22 2005/09/02 03:50:42 ajc * serv_network.c: fixed a bug in digest generation that was causing the tops of some messages to be cut off. @@ -7079,4 +7083,3 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant Fri Jul 10 1998 Art Cancro * Initial CVS import - diff --git a/citadel/locate_host.c b/citadel/locate_host.c index a3ff5c028..561595453 100644 --- a/citadel/locate_host.c +++ b/citadel/locate_host.c @@ -25,6 +25,15 @@ #include "tools.h" #include "domain.h" +#ifdef HAVE_RESOLV_H +#include +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +#include +#endif +#include +#endif + + void locate_host(char *tbuf, size_t n, char *abuf, size_t na, const struct in_addr *addr) @@ -35,7 +44,6 @@ void locate_host(char *tbuf, size_t n, int a1, a2, a3, a4; char address_string[SIZ]; - lprintf(CTDL_DEBUG, "locate_host() called\n"); #ifdef HAVE_NONREENTRANT_NETDB begin_critical_section(S_NETDB); @@ -83,7 +91,122 @@ bad_dns: #endif tbuf[63] = 0; - lprintf(CTDL_DEBUG, "locate_host() exiting\n"); +} + + +#define RESULT_SIZE 4096 /* What is the longest result text we support? */ + +int rblcheck_backend(char *domain, char *txtbuf, int txtbufsize) { + int a, b, c; + char *result = NULL; + u_char fixedans[ PACKETSZ ]; + u_char *answer; + int need_to_free_answer = 0; + const u_char *cp; + u_char *rp; + const u_char *cend; + const u_char *rend; + int len; + + /* Make our DNS query. */ + //res_init(); + answer = fixedans; + len = res_query( domain, C_IN, T_A, answer, PACKETSZ ); + + /* Was there a problem? If so, the domain doesn't exist. */ + if( len == -1 ) { + if (txtbuf != NULL) { + strcpy(txtbuf, ""); + } + return(0); + } + + if( len > PACKETSZ ) + { + answer = malloc( len ); + need_to_free_answer = 1; + len = res_query( domain, C_IN, T_A, answer, len ); + if( len == -1 ) { + if (txtbuf != NULL) { + snprintf(txtbuf, txtbufsize, + "Message rejected due to known spammer source IP address"); + } + if (need_to_free_answer) free(answer); + return(1); + } + } + + result = ( char * )malloc( RESULT_SIZE ); + result[ 0 ] = '\0'; + + + /* Make another DNS query for textual data; this shouldn't + be a performance hit, since it'll now be cached at the + nameserver we're using. */ + res_init(); + len = res_query( domain, C_IN, T_TXT, answer, PACKETSZ ); + + /* Just in case there's no TXT record... */ + if( len == -1 ) + { + if (txtbuf != NULL) { + snprintf(txtbuf, txtbufsize, + "Message rejected due to known spammer source IP address"); + } + if (need_to_free_answer) free(answer); + free(result); + return(1); + } + + /* Skip the header and the address we queried. */ + cp = answer + sizeof( HEADER ); + while( *cp != '\0' ) + { + a = *cp++; + while( a-- ) + cp++; + } + + /* This seems to be a bit of magic data that we need to + skip. I wish there were good online documentation + for programming for libresolv, so I'd know what I'm + skipping here. Anyone reading this, feel free to + enlighten me. */ + cp += 1 + NS_INT16SZ + NS_INT32SZ; + + /* Skip the type, class and ttl. */ + cp += ( NS_INT16SZ * 2 ) + NS_INT32SZ; + + /* Get the length and end of the buffer. */ + NS_GET16( c, cp ); + cend = cp + c; + + /* Iterate over any multiple answers we might have. In + this context, it's unlikely, but anyway. */ + rp = result; + rend = result + RESULT_SIZE - 1; + while( cp < cend && rp < rend ) + { + a = *cp++; + if( a != 0 ) + for( b = a; b > 0 && cp < cend && rp < rend; + b-- ) + { + if( *cp == '\n' || *cp == '"' || + *cp == '\\' ) + { + *rp++ = '\\'; + } + *rp++ = *cp++; + } + } + *rp = '\0'; + if (txtbuf != NULL) { + snprintf(txtbuf, txtbufsize, "%s", result); + } + if (need_to_free_answer) free(answer); + free(result); + return(1); } @@ -99,6 +222,7 @@ int rbl_check_addr(struct in_addr *addr, char *message_to_spammer) int rbl; int num_rbl; char rbl_domains[SIZ]; + char txt_answer[1024]; strcpy(message_to_spammer, "ok"); @@ -119,10 +243,9 @@ int rbl_check_addr(struct in_addr *addr, char *message_to_spammer) a4, a3, a2, a1); extract_token(&tbuf[strlen(tbuf)], rbl_domains, rbl, '|', (sizeof tbuf - strlen(tbuf))); - if (gethostbyname(tbuf) != NULL) { - strcpy(message_to_spammer, - "5.7.1 Message rejected due to known spammer source IP address" - ); + if (rblcheck_backend(tbuf, txt_answer, sizeof txt_answer)) { + sprintf(message_to_spammer, "5.7.1 %s", txt_answer); + lprintf(CTDL_INFO, "RBL: %s\n", txt_answer); return(1); } } diff --git a/citadel/locate_host.h b/citadel/locate_host.h index e2abe7967..b71d389c7 100644 --- a/citadel/locate_host.h +++ b/citadel/locate_host.h @@ -4,3 +4,4 @@ void locate_host(char *tbuf, size_t n, const struct in_addr *addr); int rbl_check(char *message_to_spammer); int hostname_to_dotted_quad(char *addr, char *host); +int rblcheck_backend(char *domain, char *txtbuf, int txtbufsize); -- 2.39.2