| ... | ... |
@@ -197,6 +197,12 @@ int main(int argc, char **argv) {
|
| 197 | 197 |
} |
| 198 | 198 |
#endif |
| 199 | 199 |
|
| 200 |
+ if(localnets_init(copt)) {
|
|
| 201 |
+ logg_close(); |
|
| 202 |
+ freecfg(copt); |
|
| 203 |
+ return 1; |
|
| 204 |
+ } |
|
| 205 |
+ |
|
| 200 | 206 |
umask(0007); |
| 201 | 207 |
if(!(my_socket = cfgopt(copt, "MilterSocket")->strarg)) {
|
| 202 | 208 |
logg("!Please configure the MilterSocket directive\n");
|
| ... | ... |
@@ -253,6 +259,7 @@ int main(int argc, char **argv) {
|
| 253 | 253 |
|
| 254 | 254 |
logg_close(); |
| 255 | 255 |
cpool_free(); |
| 256 |
+ localnets_free(); |
|
| 256 | 257 |
return ret; |
| 257 | 258 |
} |
| 258 | 259 |
/* |
| ... | ... |
@@ -39,11 +39,28 @@ |
| 39 | 39 |
#include "netcode.h" |
| 40 | 40 |
|
| 41 | 41 |
|
| 42 |
+enum {
|
|
| 43 |
+ NON_SMTP, |
|
| 44 |
+ INET_HOST, |
|
| 45 |
+ INET6_HOST |
|
| 46 |
+}; |
|
| 47 |
+ |
|
| 48 |
+struct LOCALNET {
|
|
| 49 |
+ struct LOCALNET *next; |
|
| 50 |
+ /* most significant first */ |
|
| 51 |
+ uint32_t basehost[4]; |
|
| 52 |
+ uint32_t mask[4]; |
|
| 53 |
+ uint32_t family; |
|
| 54 |
+}; |
|
| 55 |
+ |
|
| 56 |
+struct LOCALNET *lnet = NULL; |
|
| 57 |
+ |
|
| 42 | 58 |
/* FIXME: for connect and send */ |
| 43 | 59 |
#define TIMEOUT 60 |
| 44 | 60 |
/* for recv */ |
| 45 | 61 |
long readtimeout; |
| 46 | 62 |
|
| 63 |
+ |
|
| 47 | 64 |
int nc_socket(struct CP_ENTRY *cpe) {
|
| 48 | 65 |
int flags, s = socket(cpe->server->sa_family, SOCK_STREAM, 0); |
| 49 | 66 |
char er[256]; |
| ... | ... |
@@ -321,18 +338,11 @@ int nc_connect_rand(int *main, int *alt, int *local) {
|
| 321 | 321 |
return 0; |
| 322 | 322 |
} |
| 323 | 323 |
|
| 324 |
- |
|
| 325 |
- |
|
| 326 |
-enum {
|
|
| 327 |
- NON_SMTP, |
|
| 328 |
- INET_HOST, |
|
| 329 |
- INET6_HOST |
|
| 330 |
-}; |
|
| 331 |
- |
|
| 332 | 324 |
int resolve(char *name, uint32_t *family, uint32_t *host) {
|
| 333 | 325 |
struct addrinfo hints, *res; |
| 334 | 326 |
|
| 335 | 327 |
if(!strcasecmp("local", name)) {
|
| 328 |
+ /* l->basehost[0] = l->basehost[1] = l->basehost[2] = l->basehost[3] = 0; DONT BOTHER*/ |
|
| 336 | 329 |
*family = NON_SMTP; |
| 337 | 330 |
return 0; |
| 338 | 331 |
} |
| ... | ... |
@@ -354,7 +364,7 @@ int resolve(char *name, uint32_t *family, uint32_t *host) {
|
| 354 | 354 |
|
| 355 | 355 |
*family = INET_HOST; |
| 356 | 356 |
host[0] = htonl(sa->sin_addr.s_addr); |
| 357 |
- host[1] = host[2] = host[3] = 0; |
|
| 357 |
+ /* host[1] = host[2] = host[3] = 0; DONT BOTHER*/ |
|
| 358 | 358 |
} else if(res->ai_addrlen == sizeof(struct sockaddr_in6) && res->ai_addr->sa_family == AF_INET6) {
|
| 359 | 359 |
struct sockaddr_in6 *sa = (struct sockaddr_in6 *)res->ai_addr; |
| 360 | 360 |
unsigned int i, j; |
| ... | ... |
@@ -364,7 +374,7 @@ int resolve(char *name, uint32_t *family, uint32_t *host) {
|
| 364 | 364 |
for(i=0, j=0; i<16; i++) {
|
| 365 | 365 |
u += (sa->sin6_addr.s6_addr[i] << (8*j)); |
| 366 | 366 |
if(++j == 4) {
|
| 367 |
- host[3-(i>>2)] = u; |
|
| 367 |
+ host[i>>2] = u; |
|
| 368 | 368 |
j = u = 0; |
| 369 | 369 |
} |
| 370 | 370 |
} |
| ... | ... |
@@ -378,23 +388,7 @@ int resolve(char *name, uint32_t *family, uint32_t *host) {
|
| 378 | 378 |
} |
| 379 | 379 |
|
| 380 | 380 |
|
| 381 |
-struct LOCALNET {
|
|
| 382 |
- struct LOCALNET *next; |
|
| 383 |
- uint32_t basehost[4]; |
|
| 384 |
- uint32_t mask[4]; |
|
| 385 |
- uint32_t family; |
|
| 386 |
-}; |
|
| 387 |
- |
|
| 388 |
- |
|
| 389 |
-void applymask(uint32_t *host, uint32_t *mask) {
|
|
| 390 |
- host[0] &= mask[0]; |
|
| 391 |
- host[1] &= mask[1]; |
|
| 392 |
- host[2] &= mask[2]; |
|
| 393 |
- host[3] &= mask[3]; |
|
| 394 |
-} |
|
| 395 |
- |
|
| 396 |
- |
|
| 397 |
-struct LOCALNET* localnet(char *name, char *mask) {
|
|
| 381 |
+struct LOCALNET *localnet(char *name, char *mask) {
|
|
| 398 | 382 |
struct LOCALNET *l = (struct LOCALNET *)malloc(sizeof(*l)); |
| 399 | 383 |
uint32_t nmask; |
| 400 | 384 |
unsigned int i; |
| ... | ... |
@@ -404,18 +398,17 @@ struct LOCALNET* localnet(char *name, char *mask) {
|
| 404 | 404 |
return NULL; |
| 405 | 405 |
} |
| 406 | 406 |
|
| 407 |
- l->next = NULL; |
|
| 408 | 407 |
if(resolve(name, &l->family, l->basehost)) {
|
| 409 | 408 |
free(l); |
| 410 | 409 |
return NULL; |
| 411 | 410 |
} |
| 412 | 411 |
|
| 413 | 412 |
if(l->family == NON_SMTP) {
|
| 414 |
- l->mask[0] = l->mask[1] = l->mask[2] = l->mask[3] = 0; |
|
| 415 |
- l->basehost[0] = l->basehost[1] = l->basehost[2] = l->basehost[3] = 0; |
|
| 413 |
+ l->mask[0] = l->mask[1] = l->mask[2] = l->mask[3] = 0x0; |
|
| 416 | 414 |
return l; |
| 417 | 415 |
} |
| 418 |
- if(!*mask) nmask = 32; |
|
| 416 |
+ |
|
| 417 |
+ if(!mask || !*mask) nmask = 32 + 96*(l->family == INET6_HOST); |
|
| 419 | 418 |
else nmask = atoi(mask); |
| 420 | 419 |
|
| 421 | 420 |
if((l->family == INET6_HOST && nmask > 128) || (l->family == INET_HOST && nmask > 32)) {
|
| ... | ... |
@@ -423,32 +416,74 @@ struct LOCALNET* localnet(char *name, char *mask) {
|
| 423 | 423 |
free(l); |
| 424 | 424 |
return NULL; |
| 425 | 425 |
} |
| 426 |
+ |
|
| 426 | 427 |
l->mask[0] = l->mask[1] = l->mask[2] = l->mask[3] = 0; |
| 427 | 428 |
for(i=0; i<nmask; i++) |
| 428 |
- l->mask[i>>5] |= 1<<(i&0x1f); |
|
| 429 |
- applymask(l->basehost, l->mask); |
|
| 429 |
+ l->mask[i>>5] |= 1<<(31-(i & 31)); |
|
| 430 |
+ |
|
| 431 |
+ l->basehost[0] &= l->mask[0]; |
|
| 432 |
+ l->basehost[1] &= l->mask[1]; |
|
| 433 |
+ l->basehost[2] &= l->mask[2]; |
|
| 434 |
+ l->basehost[3] &= l->mask[3]; |
|
| 435 |
+ |
|
| 430 | 436 |
return l; |
| 431 | 437 |
} |
| 432 | 438 |
|
| 433 | 439 |
|
| 434 |
-int belongto(struct LOCALNET* l, char *name) {
|
|
| 440 |
+int islocalnet(char *name) {
|
|
| 435 | 441 |
uint32_t host[4], family; |
| 442 |
+ struct LOCALNET* l = lnet; |
|
| 436 | 443 |
|
| 444 |
+ if(!l) return 0; |
|
| 437 | 445 |
if(resolve(name, &family, host)) {
|
| 438 | 446 |
logg("^Cannot resolv %s\n", name);
|
| 439 | 447 |
return 0; |
| 440 | 448 |
} |
| 441 | 449 |
while(l) {
|
| 442 |
- if ( |
|
| 443 |
- (l->family == family) && |
|
| 444 |
- (l->basehost[0] == (host[0] & l->mask[0])) && (l->basehost[1] == (host[1] & l->mask[1])) && |
|
| 445 |
- (l->basehost[2] == (host[2] & l->mask[2])) && (l->basehost[3] == (host[3] & l->mask[3])) |
|
| 446 |
- ) return 1; |
|
| 450 |
+ if( |
|
| 451 |
+ (l->family == family) && |
|
| 452 |
+ (l->basehost[0] == (host[0] & l->mask[0])) && (l->basehost[1] == (host[1] & l->mask[1])) && |
|
| 453 |
+ (l->basehost[2] == (host[2] & l->mask[2])) && (l->basehost[3] == (host[3] & l->mask[3])) |
|
| 454 |
+ ) return 1; |
|
| 447 | 455 |
l=l->next; |
| 448 | 456 |
} |
| 449 | 457 |
return 0; |
| 450 | 458 |
} |
| 451 | 459 |
|
| 460 |
+void localnets_free(void) {
|
|
| 461 |
+ while(lnet) {
|
|
| 462 |
+ struct LOCALNET *l = lnet->next; |
|
| 463 |
+ free(lnet); |
|
| 464 |
+ lnet = l; |
|
| 465 |
+ } |
|
| 466 |
+} |
|
| 467 |
+ |
|
| 468 |
+int localnets_init(struct cfgstruct *copt) {
|
|
| 469 |
+ const struct cfgstruct *cpt; |
|
| 470 |
+ |
|
| 471 |
+ if((cpt = cfgopt(copt, "LocalNet"))->enabled) {
|
|
| 472 |
+ while(cpt) {
|
|
| 473 |
+ char *lnet = cpt->strarg; |
|
| 474 |
+ struct LOCALNET *l; |
|
| 475 |
+ char *mask = strrchr(lnet, '/'); |
|
| 476 |
+ |
|
| 477 |
+ if(mask) {
|
|
| 478 |
+ *mask='\0'; |
|
| 479 |
+ mask++; |
|
| 480 |
+ } |
|
| 481 |
+ |
|
| 482 |
+ if((l = localnet(lnet, mask)) == NULL) {
|
|
| 483 |
+ localnets_free(); |
|
| 484 |
+ return 1; |
|
| 485 |
+ } |
|
| 486 |
+ l->next = lnet; |
|
| 487 |
+ lnet = l; |
|
| 488 |
+ cpt = (struct cfgstruct *) cpt->nextarg; |
|
| 489 |
+ } |
|
| 490 |
+ } |
|
| 491 |
+ return 0; |
|
| 492 |
+} |
|
| 493 |
+ |
|
| 452 | 494 |
/* |
| 453 | 495 |
* Local Variables: |
| 454 | 496 |
* mode: c |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
#ifndef _NETCODE_H |
| 2 | 2 |
#define _NETCODE_H |
| 3 | 3 |
|
| 4 |
+#include "shared/cfgparser.h" |
|
| 4 | 5 |
#include "connpool.h" |
| 5 | 6 |
|
| 6 | 7 |
void nc_ping_entry(struct CP_ENTRY *cpe); |
| ... | ... |
@@ -9,6 +10,9 @@ int nc_send(int s, const void *buf, size_t len); |
| 9 | 9 |
char *nc_recv(int s); |
| 10 | 10 |
int nc_sendmsg(int s, int fd); |
| 11 | 11 |
int nc_connect_entry(struct CP_ENTRY *cpe); |
| 12 |
+int localnets_init(struct cfgstruct *copt); |
|
| 13 |
+void localnets_free(void); |
|
| 14 |
+int islocalnet(char *name); |
|
| 12 | 15 |
|
| 13 | 16 |
extern long readtimeout; |
| 14 | 17 |
|
| ... | ... |
@@ -77,6 +77,20 @@ Example |
| 77 | 77 |
|
| 78 | 78 |
|
| 79 | 79 |
## |
| 80 |
+## Exclusions |
|
| 81 |
+## |
|
| 82 |
+ |
|
| 83 |
+# Messages originating from these hosts/networks will not be scanned |
|
| 84 |
+# This option takes a host(name)/mask pair in CIRD notation and can be |
|
| 85 |
+# repeated several times. If "/mask" is omitted, a host is assumed. |
|
| 86 |
+# To specify a locally orignated, non-smtp, email use the keyword "local" |
|
| 87 |
+# Default: unset |
|
| 88 |
+#LocalNet local |
|
| 89 |
+#LocalNet 192.168.0.0/24 |
|
| 90 |
+#LocalNet 1111:2222:3333::/48 |
|
| 91 |
+ |
|
| 92 |
+ |
|
| 93 |
+## |
|
| 80 | 94 |
## Logging options |
| 81 | 95 |
## |
| 82 | 96 |
|
| ... | ... |
@@ -146,6 +146,7 @@ struct cfgoption cfg_options[] = {
|
| 146 | 146 |
/* Milter specific options */ |
| 147 | 147 |
{"ClamdSocket", OPT_QUOTESTR, -1, NULL, 1, OPT_MILTER},
|
| 148 | 148 |
{"MilterSocket", OPT_QUOTESTR, -1, NULL, 1, OPT_MILTER},
|
| 149 |
+ {"LocalNet", OPT_QUOTESTR, -1, NULL, 1, OPT_MILTER},
|
|
| 149 | 150 |
|
| 150 | 151 |
/* Deprecated milter options */ |
| 151 | 152 |
{"ArchiveBlockEncrypted", OPT_BOOL, 0, NULL, 0, OPT_MILTER | OPT_DEPRECATED},
|