1 Description: Add support for ipv6
2 Origin: http://wilmer.gaast.net/blog/archives/61-spamass-milter-and-IPv6.html
4 Author: Wilmer van der Gaast <wilmer@gaast.net>
6 Index: spamass-milter/spamass-milter.cpp
7 ===================================================================
8 --- spamass-milter.orig/spamass-milter.cpp 2012-06-21 13:03:25.000000000 -0700
9 +++ spamass-milter/spamass-milter.cpp 2012-06-21 13:03:42.000000000 -0700
11 #include "subst_poll.h"
22 + struct sockaddr_in localhost;
25 debug(D_FUNC, "mlfi_connect: enter");
29 /* not a socket; probably a local user calling sendmail directly */
30 /* set to 127.0.0.1 */
31 - sctx->connect_ip.s_addr = htonl(INADDR_LOOPBACK);
32 + strcpy(sctx->connect_ip, "127.0.0.1");
33 + localhost.sin_family = AF_INET;
34 + localhost.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
35 + hostaddr = (struct sockaddr*) &localhost;
38 - sctx->connect_ip = ((struct sockaddr_in *) hostaddr)->sin_addr;
39 + getnameinfo(hostaddr, sizeof(struct sockaddr_in6),
40 + sctx->connect_ip, 63, NULL, 0, NI_NUMERICHOST);
41 + debug(D_FUNC, "Remote address: %s", sctx->connect_ip);
43 sctx->assassin = NULL;
47 /* debug(D_ALWAYS, "ZZZ set private context to %p", sctx); */
49 - if (ip_in_networklist(sctx->connect_ip, &ignorenets))
50 + if (ip_in_networklist(hostaddr, &ignorenets))
52 debug(D_NET, "%s is in our ignore list - accepting message",
53 - inet_ntoa(sctx->connect_ip));
55 debug(D_FUNC, "mlfi_connect: exit ignore");
59 return SMFIS_TEMPFAIL;
62 - assassin->set_connectip(string(inet_ntoa(sctx->connect_ip)));
63 + assassin->set_connectip(string(sctx->connect_ip));
65 // Store a pointer to the assassin object in our context struct
66 sctx->assassin = assassin;
67 @@ -2033,69 +2041,119 @@
69 char *tnet = strsep(&token, "/");
71 - struct in_addr net, mask;
73 + struct in6_addr net6;
75 if (list->num_nets % 10 == 0)
76 - list->nets = (struct net*)realloc(list->nets, sizeof(*list->nets) * (list->num_nets + 10));
77 + list->nets = (union net*)realloc(list->nets, sizeof(*list->nets) * (list->num_nets + 10));
79 - if (!inet_aton(tnet, &net))
80 + if (inet_pton(AF_INET, tnet, &net))
82 - fprintf(stderr, "Could not parse \"%s\" as a network\n", tnet);
85 + struct in_addr mask;
89 + if (strchr(tmask, '.') == NULL)
94 + ret = sscanf(tmask, "%u", &bits);
95 + if (ret != 1 || bits > 32)
97 + fprintf(stderr,"%s: bad CIDR value", tmask);
100 + mask.s_addr = htonl(~((1L << (32 - bits)) - 1) & 0xffffffff);
101 + } else if (!inet_pton(AF_INET6, tmask, &mask))
103 + fprintf(stderr, "Could not parse \"%s\" as a netmask\n", tmask);
107 + mask.s_addr = 0xffffffff;
111 + char *snet = strdup(inet_ntoa(net));
112 + debug(D_MISC, "Adding %s/%s to network list", snet, inet_ntoa(mask));
116 + net.s_addr = net.s_addr & mask.s_addr;
117 + list->nets[list->num_nets].net4.af = AF_INET;
118 + list->nets[list->num_nets].net4.network = net;
119 + list->nets[list->num_nets].net4.netmask = mask;
121 + } else if (inet_pton(AF_INET6, tnet, &net6))
123 - if (strchr(tmask, '.') == NULL)
131 - ret = sscanf(tmask, "%u", &bits);
132 - if (ret != 1 || bits > 32)
133 + if (sscanf(tmask, "%d", &mask) != 1 || mask > 128)
135 fprintf(stderr,"%s: bad CIDR value", tmask);
138 - mask.s_addr = htonl(~((1L << (32 - bits)) - 1) & 0xffffffff);
139 - } else if (!inet_aton(tmask, &mask))
141 - fprintf(stderr, "Could not parse \"%s\" as a netmask\n", tmask);
147 + list->nets[list->num_nets].net6.af = AF_INET6;
148 + list->nets[list->num_nets].net6.network = net6;
149 + list->nets[list->num_nets].net6.netmask = mask;
152 - mask.s_addr = 0xffffffff;
155 - char *snet = strdup(inet_ntoa(net));
156 - debug(D_MISC, "Adding %s/%s to network list", snet, inet_ntoa(mask));
158 + fprintf(stderr, "Could not parse \"%s\" as a network\n", tnet);
162 - net.s_addr = net.s_addr & mask.s_addr;
163 - list->nets[list->num_nets].network = net;
164 - list->nets[list->num_nets].netmask = mask;
170 -int ip_in_networklist(struct in_addr ip, struct networklist *list)
171 +int ip_in_networklist(struct sockaddr *addr, struct networklist *list)
175 if (list->num_nets == 0)
178 - debug(D_NET, "Checking %s against:", inet_ntoa(ip));
180 + //debug(D_NET, "Checking %s against:", inet_ntoa(ip));
181 for (i = 0; i < list->num_nets; i++)
183 - debug(D_NET, "%s", inet_ntoa(list->nets[i].network));
184 - debug(D_NET, "/%s", inet_ntoa(list->nets[i].netmask));
185 - if ((ip.s_addr & list->nets[i].netmask.s_addr) == list->nets[i].network.s_addr)
187 - debug(D_NET, "Hit!");
189 + if (list->nets[i].net.af == AF_INET && addr->sa_family == AF_INET)
191 + struct in_addr ip = ((struct sockaddr_in *)addr)->sin_addr;
193 + debug(D_NET, "%s", inet_ntoa(list->nets[i].net4.network));
194 + debug(D_NET, "/%s", inet_ntoa(list->nets[i].net4.netmask));
195 + if ((ip.s_addr & list->nets[i].net4.netmask.s_addr) == list->nets[i].net4.network.s_addr)
197 + debug(D_NET, "Hit!");
200 + } else if (list->nets[i].net.af == AF_INET6 && addr->sa_family == AF_INET6)
202 + u_int8_t *ip = ((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr;
205 + mask = list->nets[i].net6.netmask;
206 + for (j = 0; j < 16 && mask > 0; j++, mask -= 8)
208 + unsigned char bytemask;
210 + bytemask = (mask < 8) ? ~((1L << (8 - mask)) - 1) : 0xff;
212 + if ((ip[j] & bytemask) != (list->nets[i].net6.network.s6_addr[j] & bytemask))
218 + debug(D_NET, "Hit!");
224 Index: spamass-milter/spamass-milter.h
225 ===================================================================
226 --- spamass-milter.orig/spamass-milter.h 2012-06-21 13:03:25.000000000 -0700
227 +++ spamass-milter/spamass-milter.h 2012-06-21 13:03:42.000000000 -0700
229 extern struct smfiDesc smfilter;
231 /* struct describing a single network */
235 - struct in_addr network;
236 - struct in_addr netmask;
244 + struct in_addr network;
245 + struct in_addr netmask;
250 + struct in6_addr network;
251 + int netmask; /* Just the number of bits for IPv6 */
255 /* an array of networks */
264 /* Private data structure to carry per-client data between calls */
267 - struct in_addr connect_ip; // remote IP address
268 + char connect_ip[64]; // remote IP address
270 SpamAssassin *assassin; // pointer to the SA object if we're processing a message
273 int cmp_nocase_partial(const string&, const string&);
274 void closeall(int fd);
275 void parse_networklist(char *string, struct networklist *list);
276 -int ip_in_networklist(struct in_addr ip, struct networklist *list);
277 +int ip_in_networklist(struct sockaddr *addr, struct networklist *list);
278 void parse_debuglevel(char* string);
279 char *strlwr(char *str);
280 void warnmacro(char *macro, char *scope);