5 char *bustedmxs[Maxbustedmx];
14 t = csipinfo(ds->netdir, "sys", sysname(), &s, 1);
16 strecpy(ds->expand, ds->expand+sizeof ds->expand, t->val);
17 ds->host = ds->expand;
22 /* break up an address to its component parts */
24 dialstringparse(char *str, DS *ds)
28 strecpy(ds->buf, ds->buf + sizeof ds->buf, str);
29 p = strchr(ds->buf, '!');
39 for(p2 = p; *p2 != '/'; p2--)
48 ds->service = strchr(ds->host, '!');
61 memset(mx, 0, sizeof *mx);
65 mxtabrealloc(Mxtab *mx)
72 mx->mx = realloc(mx->mx, sizeof mx->mx[0] * mx->amx);
74 sysfatal("no memory for mx");
78 mxtabadd(Mxtab *mx, char *host, char *ip, char *net, int pref)
85 for(i = mx->nmx; i>0 && x[i-1].pref>pref && x[i-1].netdir == net; i--)
87 strecpy(x[i].host, x[i].host + sizeof x[i].host, host);
89 strecpy(x[i].ip, x[i].ip + sizeof x[i].ip, ip);
99 timeout(void*, char *msg)
101 if(strstr(msg, "alarm"))
107 timedwrite(int fd, void *buf, long len, long ms)
111 atnotify(timeout, 1);
113 n = pwrite(fd, buf, len, 0);
115 atnotify(timeout, 0);
120 dnslookup(Mxtab *mx, int fd, char *query, char *domain, char *net, int pref0)
123 char buf[1024], *f[4];
125 n = timedwrite(fd, query, strlen(query), 60*1000);
127 rerrstr(buf, sizeof buf);
128 dprint("dns: %s\n", buf);
129 if(strstr(buf, "dns failure")){
130 /* if dns fails for the mx lookup, we have to stop */
139 if((n = read(fd, buf, sizeof buf - 1)) < 1)
142 // chat("dns: %s\n", buf);
143 n = tokenize(buf, f, nelem(f));
146 if(strcmp(f[1], "mx") == 0 && n == 4){
147 if(strchr(domain, '.') == 0)
148 strcpy(domain, f[0]);
149 mxtabadd(mx, f[3], nil, net, atoi(f[2]));
151 else if (strcmp(f[1], "ip") == 0 && n == 3){
152 if(strchr(domain, '.') == 0)
153 strcpy(domain, f[0]);
154 mxtabadd(mx, f[0], f[2], net, pref0);
166 for (bmp = bustedmxs; *bmp != nil; bmp++)
167 if (strcmp(mx, *bmp) == 0)
173 complain(Mxtab *mx, char *domain)
175 char buf[1024], *e, *p;
179 e = buf + sizeof buf;
180 for(i = 0; i < mx->nmx; i++)
181 p = seprint(p, e, "%s ", mx->mx[i].ip);
182 syslog(0, "smtpd.mx", "loopback for %s %s", domain, buf);
186 okaymx(Mxtab *mx, char *domain)
191 /* look for malicious dns entries; TODO use badcidr in ../spf/ to catch more than ip4 */
192 for(i = 0; i < mx->nmx; i++){
194 if(x->valid && strcmp(x->ip, "127.0.0.1") == 0){
195 dprint("illegal: domain %s lists 127.0.0.1 as mail server", domain);
196 complain(mx, domain);
197 werrstr("illegal: domain %s lists 127.0.0.1 as mail server", domain);
200 if(x->valid && busted(x->host)){
201 dprint("lookup: skipping busted mx %s\n", x->host);
209 lookup(Mxtab *mx, char *net, char *host, char *domain, char *type)
211 char dns[128], buf[1024];
215 snprint(dns, sizeof dns, "%s/dns", net);
216 fd = open(dns, ORDWR);
220 snprint(buf, sizeof buf, "%s %s", host, type);
221 dprint("sending %s '%s'\n", dns, buf);
222 dnslookup(mx, fd, buf, domain, net, 10000);
224 for(i = 0; i < mx->nmx; i++){
230 snprint(buf, sizeof buf, "%s %s", x->host, "ip");
231 dprint("sending %s '%s'\n", dns, buf);
232 dnslookup(mx, fd, buf, domain, net, x->pref);
237 if(strcmp(type, "mx") == 0){
238 if(okaymx(mx, domain) == -1)
240 for(i = 0; i < mx->nmx; i++){
242 dprint("mx list: %s %d %s\n", x->host, x->pref, x->ip);
251 lookcall(Mxtab *mx, DS *d, char *domain, char *type)
257 if(lookup(mx, d->netdir, d->host, domain, type) == -1){
258 for(i = 0; i < mx->nmx; i++)
259 if(mx->mx[i].netdir == d->netdir)
264 for(i = 0; i < mx->nmx; i++){
266 if(x->ip[0] == 0 || x->valid == 0){
270 snprint(buf, sizeof buf, "%s/%s!%s!%s", d->netdir, d->proto,
271 x->ip /*x->host*/, d->service);
272 dprint("mxdial trying %s [%s]\n", x->host, buf);
273 atnotify(timeout, 1);
275 mx->fd = dial(buf, 0, 0, 0);
277 atnotify(timeout, 0);
282 dprint(" failed %r\n");
290 mxdial0(char *addr, char *ddomain, char *gdomain, Mxtab *mx)
294 static char *tab[] = {"mx", "ip", };
296 dprint("mxdial(%s, %s, %s, mx)\n", addr, ddomain, gdomain);
297 memset(mx, 0, sizeof *mx);
299 dialstringparse(addr, d + 0);
301 if(d[0].netdir == nil){
303 d[0].netdir = "/net";
304 d[1].netdir = "/net.alt";
308 /* search all networks for mx records; then ip records */
309 for(j = 0; j < nelem(tab); j++)
310 for(i = 0; i < nd; i++)
311 if(lookcall(mx, d + i, ddomain, tab[j]) != -1)
314 /* grotty: try gateway machine by ip only (fixme: try cs lookup) */
316 dialstringparse(netmkaddr(gdomain, 0, "smtp"), d + 0);
317 if(lookcall(mx, d + 0, gdomain, "ip") != -1)
325 mxdial(char *addr, char *ddomain, char *gdomain, Mx *x)
330 memset(x, 0, sizeof *x);
331 fd = mxdial0(addr, ddomain, gdomain, &mx);
332 if(fd >= 0 && mx.pmx >= 0)