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, '!');
59 memset(mx, 0, sizeof *mx);
63 mxtabrealloc(Mxtab *mx)
70 mx->mx = realloc(mx->mx, sizeof mx->mx[0] * mx->amx);
72 sysfatal("no memory for mx");
76 mxtabadd(Mxtab *mx, char *host, char *ip, char *net, int pref)
83 for(i = mx->nmx; i>0 && x[i-1].pref>pref && x[i-1].netdir == net; i--)
85 strecpy(x[i].host, x[i].host + sizeof x[i].host, host);
87 strecpy(x[i].ip, x[i].ip + sizeof x[i].ip, ip);
97 timeout(void*, char *msg)
99 if(strstr(msg, "alarm"))
105 timedwrite(int fd, void *buf, long len, long ms)
109 atnotify(timeout, 1);
111 n = pwrite(fd, buf, len, 0);
113 atnotify(timeout, 0);
118 dnslookup(Mxtab *mx, int fd, char *query, char *domain, char *net, int pref0)
121 char buf[1024], *f[4];
123 n = timedwrite(fd, query, strlen(query), 60*1000);
125 rerrstr(buf, sizeof buf);
126 dprint("dns: %s\n", buf);
127 if(strstr(buf, "dns failure")){
128 /* if dns fails for the mx lookup, we have to stop */
137 if((n = read(fd, buf, sizeof buf - 1)) < 1)
140 // chat("dns: %s\n", buf);
141 n = tokenize(buf, f, nelem(f));
144 if(strcmp(f[1], "mx") == 0 && n == 4){
145 if(strchr(domain, '.') == 0)
146 strcpy(domain, f[0]);
147 mxtabadd(mx, f[3], nil, net, atoi(f[2]));
149 else if (strcmp(f[1], "ip") == 0 && n == 3){
150 if(strchr(domain, '.') == 0)
151 strcpy(domain, f[0]);
152 mxtabadd(mx, f[0], f[2], net, pref0);
164 for (bmp = bustedmxs; *bmp != nil; bmp++)
165 if (strcmp(mx, *bmp) == 0)
171 complain(Mxtab *mx, char *domain)
173 char buf[1024], *e, *p;
177 e = buf + sizeof buf;
178 for(i = 0; i < mx->nmx; i++)
179 p = seprint(p, e, "%s ", mx->mx[i].ip);
180 syslog(0, "smtpd.mx", "loopback for %s %s", domain, buf);
184 okaymx(Mxtab *mx, char *domain)
189 /* look for malicious dns entries; TODO use badcidr in ../spf/ to catch more than ip4 */
190 for(i = 0; i < mx->nmx; i++){
192 if(x->valid && strcmp(x->ip, "127.0.0.1") == 0){
193 dprint("illegal: domain %s lists 127.0.0.1 as mail server", domain);
194 complain(mx, domain);
195 werrstr("illegal: domain %s lists 127.0.0.1 as mail server", domain);
198 if(x->valid && busted(x->host)){
199 dprint("lookup: skipping busted mx %s\n", x->host);
207 lookup(Mxtab *mx, char *net, char *host, char *domain, char *type)
209 char dns[128], buf[1024];
213 snprint(dns, sizeof dns, "%s/dns", net);
214 fd = open(dns, ORDWR);
218 snprint(buf, sizeof buf, "%s %s", host, type);
219 dprint("sending %s '%s'\n", dns, buf);
220 dnslookup(mx, fd, buf, domain, net, 10000);
222 for(i = 0; i < mx->nmx; i++){
228 snprint(buf, sizeof buf, "%s %s", x->host, "ip");
229 dprint("sending %s '%s'\n", dns, buf);
230 dnslookup(mx, fd, buf, domain, net, x->pref);
235 if(strcmp(type, "mx") == 0){
236 if(okaymx(mx, domain) == -1)
238 for(i = 0; i < mx->nmx; i++){
240 dprint("mx list: %s %d %s\n", x->host, x->pref, x->ip);
249 lookcall(Mxtab *mx, DS *d, char *domain, char *type)
255 if(lookup(mx, d->netdir, d->host, domain, type) == -1){
256 for(i = 0; i < mx->nmx; i++)
257 if(mx->mx[i].netdir == d->netdir)
262 for(i = 0; i < mx->nmx; i++){
264 if(x->ip[0] == 0 || x->valid == 0){
268 snprint(buf, sizeof buf, "%s/%s!%s!%s", d->netdir, d->proto,
269 x->ip /*x->host*/, d->service);
270 dprint("mxdial trying %s [%s]\n", x->host, buf);
271 atnotify(timeout, 1);
273 mx->fd = dial(buf, 0, 0, 0);
275 atnotify(timeout, 0);
280 dprint(" failed %r\n");
288 mxdial0(char *addr, char *ddomain, char *gdomain, Mxtab *mx)
292 static char *tab[] = {"mx", "ip", };
294 dprint("mxdial(%s, %s, %s, mx)\n", addr, ddomain, gdomain);
295 memset(mx, 0, sizeof *mx);
296 addr = netmkaddr(addr, 0, "smtp");
298 dialstringparse(addr, d + 0);
300 if(d[0].netdir == nil){
302 d[0].netdir = "/net";
303 d[1].netdir = "/net.alt";
307 /* search all networks for mx records; then ip records */
308 for(j = 0; j < nelem(tab); j++)
309 for(i = 0; i < nd; i++)
310 if(lookcall(mx, d + i, ddomain, tab[j]) != -1)
313 /* grotty: try gateway machine by ip only (fixme: try cs lookup) */
315 dialstringparse(netmkaddr(gdomain, 0, "smtp"), d + 0);
316 if(lookcall(mx, d + 0, gdomain, "ip") != -1)
324 mxdial(char *addr, char *ddomain, char *gdomain, Mx *x)
329 memset(x, 0, sizeof *x);
330 fd = mxdial0(addr, ddomain, gdomain, &mx);
331 if(fd >= 0 && mx.pmx >= 0)