git-svn: trunk@3146
Nigel Horne authored on 2007/07/15 08:45:36... | ... |
@@ -1,7 +1,11 @@ |
1 |
+Sat Jul 14 23:50:56 BST 2007 (njh) |
|
2 |
+---------------------------------- |
|
3 |
+ * clamav-milter: Experimental mode: Handle A and MX in SPF records |
|
4 |
+ |
|
1 | 5 |
Sat Jul 14 22:07:16 BST 2007 (njh) |
2 | 6 |
---------------------------------- |
3 | 7 |
* clamav-milter: Experimental mode: basic SPF parser to reduce |
4 |
- phish false-positives |
|
8 |
+ phish false-positives |
|
5 | 9 |
Possible fix for 487 |
6 | 10 |
Some small tidies |
7 | 11 |
|
... | ... |
@@ -20,7 +24,7 @@ Thu Jul 12 11:41:15 BST 2007 (trog) |
20 | 20 |
Thu Jul 12 01:41:56 CEST 2007 (acab) |
21 | 21 |
------------------------------------ |
22 | 22 |
* libclamav: rename x86 macroes due to collisions on HPUX |
23 |
- reported by njh |
|
23 |
+ reported by njh |
|
24 | 24 |
|
25 | 25 |
Wed Jul 11 10:20:53 BST 2007 (njh) |
26 | 26 |
---------------------------------- |
... | ... |
@@ -69,7 +73,7 @@ Tue Jul 10 22:02:15 CEST 2007 (tk) |
69 | 69 |
Sun Jul 8 17:25:04 CEST 2007 (acab) |
70 | 70 |
------------------------------------ |
71 | 71 |
* misc: Implement compiler indepenedent sign-extended signed right shift |
72 |
- when needed - reported by Michal Spadlinski <gim913 * gmail.com> |
|
72 |
+ when needed - reported by Michal Spadlinski <gim913 * gmail.com> |
|
73 | 73 |
|
74 | 74 |
Sat Jul 07 10:52:00 CEST 2007 (edwin) |
75 | 75 |
---------------------------------- |
... | ... |
@@ -336,12 +336,13 @@ static int isLocal(const char *addr); |
336 | 336 |
static void clamdIsDown(void); |
337 | 337 |
static void *watchdog(void *a); |
338 | 338 |
static int check_and_reload_database(void); |
339 |
-static void timeoutBlacklist(char *ip_address, int time_of_blacklist); |
|
339 |
+static void timeoutBlacklist(char *ip_address, int time_of_blacklist, void *v); |
|
340 | 340 |
static void quit(void); |
341 | 341 |
static void broadcast(const char *mess); |
342 | 342 |
static int loadDatabase(void); |
343 | 343 |
static int increment_connexions(void); |
344 | 344 |
static void decrement_connexions(void); |
345 |
+static void dump_blacklist(char *key, int value, void *v); |
|
345 | 346 |
|
346 | 347 |
#ifdef SESSION |
347 | 348 |
static pthread_mutex_t version_mutex = PTHREAD_MUTEX_INITIALIZER; |
... | ... |
@@ -562,11 +563,12 @@ static void print_trace(void); |
562 | 562 |
static int verifyIncomingSocketName(const char *sockName); |
563 | 563 |
static int isWhitelisted(const char *emailaddress, int to); |
564 | 564 |
static int isBlacklisted(const char *ip_address); |
565 |
-static void mx(void); |
|
565 |
+static table_t *mx(const char *host, table_t *t); |
|
566 | 566 |
#ifdef HAVE_RESOLV_H |
567 |
-static void resolve(const char *host); |
|
567 |
+static table_t *resolve(const char *host, table_t *t); |
|
568 | 568 |
#ifdef CL_EXPERIMENTAL |
569 | 569 |
static void spf(struct privdata *privdata); |
570 |
+static void spf_ip(char *ip, int zero, void *v); |
|
570 | 571 |
#endif |
571 | 572 |
#endif |
572 | 573 |
static sfsistat black_hole(const struct privdata *privdata); |
... | ... |
@@ -2006,7 +2008,14 @@ main(int argc, char **argv) |
2006 | 2006 |
logg(_("*Debugging is on\n")); |
2007 | 2007 |
|
2008 | 2008 |
if(blacklist_time) { |
2009 |
- mx(); |
|
2009 |
+ char name[MAXHOSTNAMELEN + 1]; |
|
2010 |
+ |
|
2011 |
+ if(gethostname(name, sizeof(name)) < 0) { |
|
2012 |
+ perror("gethostname"); |
|
2013 |
+ return EX_UNAVAILABLE; |
|
2014 |
+ } |
|
2015 |
+ |
|
2016 |
+ blacklist = mx(name, NULL); |
|
2010 | 2017 |
if(blacklist) |
2011 | 2018 |
/* We must never blacklist ourself */ |
2012 | 2019 |
tableInsert(blacklist, "127.0.0.1", 0); |
... | ... |
@@ -2016,11 +2025,11 @@ main(int argc, char **argv) |
2016 | 2016 |
|
2017 | 2017 |
i = 0; |
2018 | 2018 |
while((w = cli_strtok(wont_blacklist, i++, ",")) != NULL) { |
2019 |
- logg(_("Won't blacklist %s\n"), w); |
|
2020 | 2019 |
(void)tableInsert(blacklist, w, 0); |
2021 | 2020 |
free(w); |
2022 | 2021 |
} |
2023 | 2022 |
} |
2023 |
+ tableIterate(blacklist, dump_blacklist, NULL); |
|
2024 | 2024 |
} |
2025 | 2025 |
|
2026 | 2026 |
cli_dbgmsg("Started: %s\n", clamav_version); |
... | ... |
@@ -5361,7 +5370,7 @@ watchdog(void *a) |
5361 | 5361 |
/* Garbage collect IP addresses no longer blacklisted */ |
5362 | 5362 |
if(blacklist) { |
5363 | 5363 |
pthread_mutex_lock(&blacklist_mutex); |
5364 |
- tableIterate(blacklist, timeoutBlacklist); |
|
5364 |
+ tableIterate(blacklist, timeoutBlacklist, NULL); |
|
5365 | 5365 |
pthread_mutex_unlock(&blacklist_mutex); |
5366 | 5366 |
} |
5367 | 5367 |
} |
... | ... |
@@ -5424,7 +5433,7 @@ watchdog(void *a) |
5424 | 5424 |
/* Garbage collect IP addresses no longer blacklisted */ |
5425 | 5425 |
if(blacklist) { |
5426 | 5426 |
pthread_mutex_lock(&blacklist_mutex); |
5427 |
- tableIterate(blacklist, timeoutBlacklist); |
|
5427 |
+ tableIterate(blacklist, timeoutBlacklist, NULL); |
|
5428 | 5428 |
pthread_mutex_unlock(&blacklist_mutex); |
5429 | 5429 |
} |
5430 | 5430 |
} |
... | ... |
@@ -5467,7 +5476,7 @@ check_and_reload_database(void) |
5467 | 5467 |
} |
5468 | 5468 |
|
5469 | 5469 |
static void |
5470 |
-timeoutBlacklist(char *ip_address, int time_of_blacklist) |
|
5470 |
+timeoutBlacklist(char *ip_address, int time_of_blacklist, void *v) |
|
5471 | 5471 |
{ |
5472 | 5472 |
if(time_of_blacklist == 0) /* Must not blacklist this IP address */ |
5473 | 5473 |
return; |
... | ... |
@@ -5961,8 +5970,8 @@ isBlacklisted(const char *ip_address) |
5961 | 5961 |
* This is only ever called once, which is wrong, but the overheard of calling |
5962 | 5962 |
* this from the watchdog isn't worth it |
5963 | 5963 |
*/ |
5964 |
-static void |
|
5965 |
-mx(void) |
|
5964 |
+static table_t * |
|
5965 |
+mx(const char *host, table_t *t) |
|
5966 | 5966 |
{ |
5967 | 5967 |
u_char *p, *end; |
5968 | 5968 |
const HEADER *hp; |
... | ... |
@@ -5971,37 +5980,31 @@ mx(void) |
5971 | 5971 |
HEADER h; |
5972 | 5972 |
u_char u[PACKETSZ]; |
5973 | 5973 |
} q; |
5974 |
- char name[MAXHOSTNAMELEN + 1]; |
|
5975 | 5974 |
char buf[BUFSIZ]; |
5976 | 5975 |
|
5977 |
- if(gethostname(name, sizeof(name)) < 0) { |
|
5978 |
- perror("gethostname"); |
|
5979 |
- return; |
|
5980 |
- } |
|
5981 |
- |
|
5982 |
- if(blacklist == NULL) { |
|
5983 |
- blacklist = tableCreate(); |
|
5976 |
+ if(t == NULL) { |
|
5977 |
+ t = tableCreate(); |
|
5984 | 5978 |
|
5985 |
- if(blacklist == NULL) |
|
5986 |
- return; |
|
5979 |
+ if(t == NULL) |
|
5980 |
+ return NULL; |
|
5987 | 5981 |
} |
5988 | 5982 |
|
5989 | 5983 |
was_initialised = _res.options & RES_INIT; |
5990 | 5984 |
|
5991 | 5985 |
if((!was_initialised) && res_init() < 0) |
5992 |
- return; |
|
5986 |
+ return t; |
|
5993 | 5987 |
|
5994 |
- len = res_query(name, C_IN, T_MX, (u_char *)&q, sizeof(q)); |
|
5988 |
+ len = res_query(host, C_IN, T_MX, (u_char *)&q, sizeof(q)); |
|
5995 | 5989 |
if(len < 0) { |
5996 | 5990 |
if(!was_initialised) |
5997 | 5991 |
res_close(); |
5998 |
- return; /* Host has no MX records */ |
|
5992 |
+ return t; /* Host has no MX records */ |
|
5999 | 5993 |
} |
6000 | 5994 |
|
6001 | 5995 |
if((unsigned int)len > sizeof(q)) { |
6002 | 5996 |
if(!was_initialised) |
6003 | 5997 |
res_close(); |
6004 |
- return; |
|
5998 |
+ return t; |
|
6005 | 5999 |
} |
6006 | 6000 |
|
6007 | 6001 |
hp = &(q.h); |
... | ... |
@@ -6012,7 +6015,7 @@ mx(void) |
6012 | 6012 |
if((len = dn_skipname(p, end)) < 0) { |
6013 | 6013 |
if(!was_initialised) |
6014 | 6014 |
res_close(); |
6015 |
- return; |
|
6015 |
+ return t; |
|
6016 | 6016 |
} |
6017 | 6017 |
|
6018 | 6018 |
i = ntohs(hp->ancount); |
... | ... |
@@ -6043,21 +6046,22 @@ mx(void) |
6043 | 6043 |
#else |
6044 | 6044 |
if(addr != (in_addr_t)-1) { |
6045 | 6045 |
#endif |
6046 |
- logg(_("Won't blacklist %s\n"), buf); |
|
6047 |
- (void)tableInsert(blacklist, buf, 0); |
|
6046 |
+ (void)tableInsert(t, buf, 0); |
|
6048 | 6047 |
} else |
6049 |
- resolve(buf); |
|
6048 |
+ t = resolve(buf, t); |
|
6050 | 6049 |
} |
6051 | 6050 |
if(!was_initialised) |
6052 | 6051 |
res_close(); |
6052 |
+ |
|
6053 |
+ return t; |
|
6053 | 6054 |
} |
6054 | 6055 |
|
6055 | 6056 |
/* |
6056 | 6057 |
* If the MX record points to a name, we need to resolve that name. This routine |
6057 | 6058 |
* does that |
6058 | 6059 |
*/ |
6059 |
-static void |
|
6060 |
-resolve(const char *host) |
|
6060 |
+static table_t * |
|
6061 |
+resolve(const char *host, table_t *t) |
|
6061 | 6062 |
{ |
6062 | 6063 |
u_char *p, *end; |
6063 | 6064 |
const HEADER *hp; |
... | ... |
@@ -6069,14 +6073,14 @@ resolve(const char *host) |
6069 | 6069 |
char buf[BUFSIZ]; |
6070 | 6070 |
|
6071 | 6071 |
if((host == NULL) || (*host == '\0')) |
6072 |
- return; |
|
6072 |
+ return t; |
|
6073 | 6073 |
|
6074 | 6074 |
len = res_query(host, C_IN, T_A, (u_char *)&q, sizeof(q)); |
6075 | 6075 |
if(len < 0) |
6076 |
- return; /* Host has no A records */ |
|
6076 |
+ return t; /* Host has no A records */ |
|
6077 | 6077 |
|
6078 | 6078 |
if((unsigned int)len > sizeof(q)) |
6079 |
- return; |
|
6079 |
+ return t; |
|
6080 | 6080 |
|
6081 | 6081 |
hp = &(q.h); |
6082 | 6082 |
p = q.u + HFIXEDSZ; |
... | ... |
@@ -6084,18 +6088,18 @@ resolve(const char *host) |
6084 | 6084 |
|
6085 | 6085 |
for(i = ntohs(hp->qdcount); i--; p += len + QFIXEDSZ) |
6086 | 6086 |
if((len = dn_skipname(p, end)) < 0) |
6087 |
- return; |
|
6087 |
+ return t; |
|
6088 | 6088 |
|
6089 | 6089 |
i = ntohs(hp->ancount); |
6090 | 6090 |
|
6091 | 6091 |
while((--i >= 0) && (p < end)) { |
6092 | 6092 |
u_short type; |
6093 | 6093 |
u_long ttl; |
6094 |
- struct in_addr addr; |
|
6095 | 6094 |
const char *ip; |
6095 |
+ struct in_addr addr; |
|
6096 | 6096 |
|
6097 | 6097 |
if((len = dn_expand(q.u, end, p, buf, sizeof(buf) - 1)) < 0) |
6098 |
- return; |
|
6098 |
+ return t; |
|
6099 | 6099 |
p += len; |
6100 | 6100 |
GETSHORT(type, p); |
6101 | 6101 |
p += INT16SZ; |
... | ... |
@@ -6109,10 +6113,16 @@ resolve(const char *host) |
6109 | 6109 |
p += 4; /* Should check len == 4 */ |
6110 | 6110 |
ip = inet_ntoa(addr); |
6111 | 6111 |
if(ip) { |
6112 |
- logg(_("Won't blacklist %s\n"), ip); |
|
6113 |
- (void)tableInsert(blacklist, ip, 0); |
|
6112 |
+ if(t == NULL) { |
|
6113 |
+ t = tableCreate(); |
|
6114 |
+ |
|
6115 |
+ if(t == NULL) |
|
6116 |
+ return NULL; |
|
6117 |
+ } |
|
6118 |
+ (void)tableInsert(t, ip, 0); |
|
6114 | 6119 |
} |
6115 | 6120 |
} |
6121 |
+ return t; |
|
6116 | 6122 |
} |
6117 | 6123 |
|
6118 | 6124 |
#ifdef CL_EXPERIMENTAL |
... | ... |
@@ -6127,7 +6137,7 @@ resolve(const char *host) |
6127 | 6127 |
static void |
6128 | 6128 |
spf(struct privdata *privdata) |
6129 | 6129 |
{ |
6130 |
- char *mailaddr, *ptr; |
|
6130 |
+ char *host, *ptr; |
|
6131 | 6131 |
u_char *p, *end; |
6132 | 6132 |
const HEADER *hp; |
6133 | 6133 |
int len, i; |
... | ... |
@@ -6152,27 +6162,27 @@ spf(struct privdata *privdata) |
6152 | 6152 |
|
6153 | 6153 |
if(privdata->from == NULL) |
6154 | 6154 |
return; |
6155 |
- if((mailaddr = strchr(privdata->from, '@')) == NULL) |
|
6155 |
+ if((host = strchr(privdata->from, '@')) == NULL) |
|
6156 | 6156 |
return; |
6157 | 6157 |
|
6158 |
- mailaddr = cli_strdup(++mailaddr); |
|
6158 |
+ host = cli_strdup(++host); |
|
6159 | 6159 |
|
6160 |
- if(mailaddr == NULL) |
|
6160 |
+ if(host == NULL) |
|
6161 | 6161 |
return; |
6162 | 6162 |
|
6163 |
- ptr = strchr(mailaddr, '>'); |
|
6163 |
+ ptr = strchr(host, '>'); |
|
6164 | 6164 |
|
6165 | 6165 |
if(ptr) |
6166 | 6166 |
*ptr = '\0'; |
6167 | 6167 |
|
6168 |
- len = res_query(mailaddr, C_IN, T_TXT, (u_char *)&q, sizeof(q)); |
|
6168 |
+ len = res_query(host, C_IN, T_TXT, (u_char *)&q, sizeof(q)); |
|
6169 | 6169 |
if(len < 0) { |
6170 |
- free(mailaddr); |
|
6170 |
+ free(host); |
|
6171 | 6171 |
return; /* Host has no TXT records */ |
6172 | 6172 |
} |
6173 | 6173 |
|
6174 | 6174 |
if((unsigned int)len > sizeof(q)) { |
6175 |
- free(mailaddr); |
|
6175 |
+ free(host); |
|
6176 | 6176 |
return; |
6177 | 6177 |
} |
6178 | 6178 |
|
... | ... |
@@ -6182,7 +6192,7 @@ spf(struct privdata *privdata) |
6182 | 6182 |
|
6183 | 6183 |
for(i = ntohs(hp->qdcount); i--; p += len + QFIXEDSZ) |
6184 | 6184 |
if((len = dn_skipname(p, end)) < 0) { |
6185 |
- free(mailaddr); |
|
6185 |
+ free(host); |
|
6186 | 6186 |
return; |
6187 | 6187 |
} |
6188 | 6188 |
|
... | ... |
@@ -6194,7 +6204,7 @@ spf(struct privdata *privdata) |
6194 | 6194 |
char txt[BUFSIZ]; |
6195 | 6195 |
|
6196 | 6196 |
if((len = dn_expand(q.u, end, p, buf, sizeof(buf) - 1)) < 0) { |
6197 |
- free(mailaddr); |
|
6197 |
+ free(host); |
|
6198 | 6198 |
return; |
6199 | 6199 |
} |
6200 | 6200 |
p += len; |
... | ... |
@@ -6214,9 +6224,9 @@ spf(struct privdata *privdata) |
6214 | 6214 |
struct in_addr remote_ip; /* IP connecting to us */ |
6215 | 6215 |
|
6216 | 6216 |
logg("%s(%s): SPF record %s\n", |
6217 |
- mailaddr, privdata->ip, txt); |
|
6217 |
+ host, privdata->ip, txt); |
|
6218 | 6218 |
/* |
6219 |
- * This is were the beef of the check will go. This |
|
6219 |
+ * This is where the beef of the check will go. This |
|
6220 | 6220 |
* trivial check is of little real benefit, but it |
6221 | 6221 |
* won't create false positives. |
6222 | 6222 |
*/ |
... | ... |
@@ -6267,18 +6277,45 @@ spf(struct privdata *privdata) |
6267 | 6267 |
#endif |
6268 | 6268 |
mask = MAKEMASK(preflen); |
6269 | 6269 |
if((ntohl(remote_ip.s_addr) & mask) == (ntohl(spf_range.s_addr) & mask)) { |
6270 |
- free(record); |
|
6271 | 6270 |
logg("SPF ip4 pass\n"); |
6272 | 6271 |
privdata->spf_ok = 1; |
6273 |
- break; |
|
6272 |
+ } |
|
6273 |
+ } else if(strcmp(record, "mx") == 0) { |
|
6274 |
+ table_t *t = mx(host, NULL); |
|
6275 |
+ |
|
6276 |
+ if(t) { |
|
6277 |
+ tableIterate(t, spf_ip, |
|
6278 |
+ (void *)privdata); |
|
6279 |
+ tableDestroy(t); |
|
6280 |
+ } |
|
6281 |
+ } else if(strcmp(record, "a") == 0) { |
|
6282 |
+ table_t *t = resolve(host, NULL); |
|
6283 |
+ |
|
6284 |
+ if(t) { |
|
6285 |
+ tableIterate(t, spf_ip, |
|
6286 |
+ (void *)privdata); |
|
6287 |
+ tableDestroy(t); |
|
6274 | 6288 |
} |
6275 | 6289 |
} |
6276 | 6290 |
free(record); |
6291 |
+ if(privdata->spf_ok) |
|
6292 |
+ break; |
|
6277 | 6293 |
} |
6278 | 6294 |
} |
6279 | 6295 |
p += len; |
6280 | 6296 |
} |
6281 |
- free(mailaddr); |
|
6297 |
+ free(host); |
|
6298 |
+} |
|
6299 |
+ |
|
6300 |
+static void |
|
6301 |
+spf_ip(char *ip, int zero, void *v) |
|
6302 |
+{ |
|
6303 |
+ struct privdata *privdata = (struct privdata *)v; |
|
6304 |
+ |
|
6305 |
+ if(strcmp(ip, privdata->ip) == 0) { |
|
6306 |
+ logg("SPF mx/a pass %s\n", ip); |
|
6307 |
+ privdata->spf_ok = 1; |
|
6308 |
+ } |
|
6282 | 6309 |
} |
6283 | 6310 |
|
6284 | 6311 |
#endif /*CL_EXPERIMENTAL*/ |
... | ... |
@@ -6466,3 +6503,9 @@ decrement_connexions(void) |
6466 | 6466 |
pthread_mutex_unlock(&n_children_mutex); |
6467 | 6467 |
} |
6468 | 6468 |
} |
6469 |
+ |
|
6470 |
+static void |
|
6471 |
+dump_blacklist(char *key, int value, void *v) |
|
6472 |
+{ |
|
6473 |
+ logg(_("Won't blacklist %s\n"), key); |
|
6474 |
+} |
... | ... |
@@ -199,7 +199,7 @@ tableRemove(table_t *table, const char *key) |
199 | 199 |
} |
200 | 200 |
|
201 | 201 |
void |
202 |
-tableIterate(table_t *table, void(*callback)(char *key, int value)) |
|
202 |
+tableIterate(table_t *table, void(*callback)(char *key, int value, void *arg), void *arg) |
|
203 | 203 |
{ |
204 | 204 |
tableEntry *tableItem; |
205 | 205 |
|
... | ... |
@@ -208,5 +208,5 @@ tableIterate(table_t *table, void(*callback)(char *key, int value)) |
208 | 208 |
|
209 | 209 |
for(tableItem = table->tableHead; tableItem; tableItem = tableItem->next) |
210 | 210 |
if(tableItem->key) /* check node has not been deleted */ |
211 |
- (*callback)(tableItem->key, tableItem->value); |
|
211 |
+ (*callback)(tableItem->key, tableItem->value, arg); |
|
212 | 212 |
} |
... | ... |
@@ -40,4 +40,4 @@ int tableInsert(table_t *table, const char *key, int value); |
40 | 40 |
int tableUpdate(table_t *table, const char *key, int new_value); |
41 | 41 |
int tableFind(const table_t *table, const char *key); |
42 | 42 |
void tableRemove(table_t *table, const char *key); |
43 |
-void tableIterate(table_t *table, void(*callback)(char *key, int value)); |
|
43 |
+void tableIterate(table_t *table, void(*callback)(char *key, int value, void *arg), void *arg); |