diff -up spamass-milter-0.3.1/spamass-milter.cpp.ipv6 spamass-milter-0.3.1/spamass-milter.cpp --- spamass-milter-0.3.1/spamass-milter.cpp.ipv6 2010-09-23 16:26:36.227224902 +0100 +++ spamass-milter-0.3.1/spamass-milter.cpp 2010-09-23 17:25:22.307099331 +0100 @@ -88,6 +88,7 @@ #include "subst_poll.h" #endif #include <errno.h> +#include <netdb.h> #include <grp.h> @@ -718,12 +719,18 @@ mlfi_connect(SMFICTX * ctx, char *hostna sctx = (struct context *)malloc(sizeof(*sctx)); if (!hostaddr) { + static struct sockaddr_in localhost; + /* not a socket; probably a local user calling sendmail directly */ /* set to 127.0.0.1 */ - sctx->connect_ip.s_addr = htonl(INADDR_LOOPBACK); + strcpy(sctx->connect_ip, "127.0.0.1"); + localhost.sin_family = AF_INET; + localhost.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + hostaddr = (struct sockaddr*) &localhost; } else { - sctx->connect_ip = ((struct sockaddr_in *) hostaddr)->sin_addr; + getnameinfo(hostaddr, sizeof(struct sockaddr_in6), + sctx->connect_ip, 63, NULL, 0, NI_NUMERICHOST); } sctx->assassin = NULL; sctx->helo = NULL; @@ -758,12 +765,12 @@ mlfi_connect(SMFICTX * ctx, char *hostna debug(D_ALWAYS, "smfi_setpriv failed!"); return SMFIS_TEMPFAIL; } - /* debug(D_ALWAYS, "ZZZ set private context to %p", sctx); */ - if (ip_in_networklist(sctx->connect_ip, &ignorenets)) + debug(D_NET, "Checking %s against:", sctx->connect_ip); + if (ip_in_networklist(hostaddr, &ignorenets)) { debug(D_NET, "%s is in our ignore list - accepting message", - inet_ntoa(sctx->connect_ip)); + sctx->connect_ip); debug(D_FUNC, "mlfi_connect: exit ignore"); return SMFIS_ACCEPT; } @@ -807,7 +814,6 @@ mlfi_envfrom(SMFICTX* ctx, char** envfro debug(D_ALWAYS, "smfi_getpriv failed!"); return SMFIS_TEMPFAIL; } - /* debug(D_ALWAYS, "ZZZ got private context %p", sctx); */ if (ignore_authenticated_senders) { @@ -835,7 +841,7 @@ mlfi_envfrom(SMFICTX* ctx, char** envfro return SMFIS_TEMPFAIL; }; - assassin->set_connectip(string(inet_ntoa(sctx->connect_ip))); + assassin->set_connectip(string(sctx->connect_ip)); // Store a pointer to the assassin object in our context struct sctx->assassin = assassin; @@ -2128,69 +2134,135 @@ void parse_networklist(char *string, str { char *tnet = strsep(&token, "/"); char *tmask = token; - struct in_addr net, mask; + struct in_addr net; + struct in6_addr net6; if (list->num_nets % 10 == 0) - list->nets = (struct net*)realloc(list->nets, sizeof(*list->nets) * (list->num_nets + 10)); + list->nets = (union net*)realloc(list->nets, sizeof(*list->nets) * (list->num_nets + 10)); - if (!inet_aton(tnet, &net)) + if (inet_pton(AF_INET, tnet, &net)) { - fprintf(stderr, "Could not parse \"%s\" as a network\n", tnet); - exit(1); - } + struct in_addr mask; + + if (tmask) + { + if (strchr(tmask, '.') == NULL) + { + /* CIDR */ + unsigned int bits; + int ret; + ret = sscanf(tmask, "%u", &bits); + if (ret != 1 || bits > 32) + { + fprintf(stderr,"%s: bad CIDR value", tmask); + exit(1); + } + mask.s_addr = htonl(~((1L << (32 - bits)) - 1) & 0xffffffff); + } else if (!inet_pton(AF_INET6, tmask, &mask)) + { + fprintf(stderr, "Could not parse \"%s\" as a netmask\n", tmask); + exit(1); + } + } else + mask.s_addr = 0xffffffff; - if (tmask) - { - if (strchr(tmask, '.') == NULL) + net.s_addr = net.s_addr & mask.s_addr; + list->nets[list->num_nets].net4.af = AF_INET; + list->nets[list->num_nets].net4.network = net; + list->nets[list->num_nets].net4.netmask = mask; + } else if (inet_pton(AF_INET6, tnet, &net6)) + { + int mask; + + if (tmask) { - /* CIDR */ - unsigned int bits; - int ret; - ret = sscanf(tmask, "%u", &bits); - if (ret != 1 || bits > 32) + if (sscanf(tmask, "%d", &mask) != 1 || mask > 128) { fprintf(stderr,"%s: bad CIDR value", tmask); exit(1); } - mask.s_addr = htonl(~((1L << (32 - bits)) - 1) & 0xffffffff); - } else if (!inet_aton(tmask, &mask)) - { - fprintf(stderr, "Could not parse \"%s\" as a netmask\n", tmask); - exit(1); - } + } else + mask = 128; + + list->nets[list->num_nets].net6.af = AF_INET6; + list->nets[list->num_nets].net6.network = net6; + list->nets[list->num_nets].net6.netmask = mask; } else - mask.s_addr = 0xffffffff; + { + fprintf(stderr, "Could not parse \"%s\" as a network\n", tnet); + exit(1); + } { - char *snet = strdup(inet_ntoa(net)); - debug(D_MISC, "Adding %s/%s to network list", snet, inet_ntoa(mask)); - free(snet); + int af = list->nets[list->num_nets].net.af; + char addrbuf[INET6_ADDRSTRLEN]; + char maskbuf[4]; + char *maskstr; + + if (af == AF_INET6) { + inet_ntop(af, &list->nets[list->num_nets].net6.network, + addrbuf, INET6_ADDRSTRLEN); + sprintf(maskbuf, "%d", list->nets[list->num_nets].net6.netmask); + maskstr = maskbuf; + list->nets[list->num_nets].net6.addrstr = strdup(addrbuf); + list->nets[list->num_nets].net6.maskstr = strdup(maskbuf); + } else + { + inet_ntop(af, &list->nets[list->num_nets].net4.network, + addrbuf, INET6_ADDRSTRLEN); + maskstr = inet_ntoa(list->nets[list->num_nets].net4.netmask); + list->nets[list->num_nets].net4.addrstr = strdup(addrbuf); + list->nets[list->num_nets].net4.maskstr = strdup(maskstr); + } + debug(D_MISC, "Added %s/%s to network list", addrbuf, maskstr); } - net.s_addr = net.s_addr & mask.s_addr; - list->nets[list->num_nets].network = net; - list->nets[list->num_nets].netmask = mask; list->num_nets++; } free(string); } -int ip_in_networklist(struct in_addr ip, struct networklist *list) +int ip_in_networklist(struct sockaddr *addr, struct networklist *list) { int i; if (list->num_nets == 0) return 0; - - debug(D_NET, "Checking %s against:", inet_ntoa(ip)); + for (i = 0; i < list->num_nets; i++) { - debug(D_NET, "%s", inet_ntoa(list->nets[i].network)); - debug(D_NET, "/%s", inet_ntoa(list->nets[i].netmask)); - if ((ip.s_addr & list->nets[i].netmask.s_addr) == list->nets[i].network.s_addr) - { - debug(D_NET, "Hit!"); - return 1; + if (list->nets[i].net.af == AF_INET && addr->sa_family == AF_INET) + { + struct in_addr ip = ((struct sockaddr_in *)addr)->sin_addr; + + debug(D_NET, "%s/%s", list->nets[i].net4.addrstr, list->nets[i].net4.maskstr); + if ((ip.s_addr & list->nets[i].net4.netmask.s_addr) == list->nets[i].net4.network.s_addr) + { + debug(D_NET, "Hit!"); + return 1; + } + } else if (list->nets[i].net.af == AF_INET6 && addr->sa_family == AF_INET6) + { + u_int8_t *ip = ((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr; + int mask, j; + + debug(D_NET, "%s/%s", list->nets[i].net6.addrstr, list->nets[i].net6.maskstr); + mask = list->nets[i].net6.netmask; + for (j = 0; j < 16 && mask > 0; j++, mask -= 8) + { + unsigned char bytemask; + + bytemask = (mask < 8) ? ~((1L << (8 - mask)) - 1) : 0xff; + + if ((ip[j] & bytemask) != (list->nets[i].net6.network.s6_addr[j] & bytemask)) + break; + } + + if (mask <= 0) + { + debug(D_NET, "Hit!"); + return 1; + } } } diff -up spamass-milter-0.3.1/spamass-milter.h.ipv6 spamass-milter-0.3.1/spamass-milter.h --- spamass-milter-0.3.1/spamass-milter.h.ipv6 2010-09-23 16:26:36.224160445 +0100 +++ spamass-milter-0.3.1/spamass-milter.h 2010-09-23 17:00:16.487410690 +0100 @@ -56,16 +56,34 @@ sfsistat mlfi_abort(SMFICTX*); extern struct smfiDesc smfilter; /* struct describing a single network */ -struct net +union net { - struct in_addr network; - struct in_addr netmask; + struct + { + uint8_t af; + } net; + struct + { + uint8_t af; + struct in_addr network; + struct in_addr netmask; + char *addrstr; + char *maskstr; + } net4; + struct + { + uint8_t af; + struct in6_addr network; + int netmask; /* Just the number of bits for IPv6 */ + char *addrstr; + char *maskstr; + } net6; }; /* an array of networks */ struct networklist { - struct net *nets; + union net *nets; int num_nets; }; @@ -162,7 +180,7 @@ public: /* Private data structure to carry per-client data between calls */ struct context { - struct in_addr connect_ip; // remote IP address + char connect_ip[64]; // remote IP address char *helo; char *our_fqdn; char *sender_address; @@ -184,7 +202,7 @@ string::size_type find_nocase(const stri int cmp_nocase_partial(const string&, const string&); void closeall(int fd); void parse_networklist(char *string, struct networklist *list); -int ip_in_networklist(struct in_addr ip, struct networklist *list); +int ip_in_networklist(struct sockaddr *addr, struct networklist *list); void parse_debuglevel(char* string); char *strlwr(char *str); void warnmacro(const char *macro, const char *scope);