1 5cdb1798 2005-10-29 devnull #include "common.h"
2 5cdb1798 2005-10-29 devnull #include <ndb.h>
3 5cdb1798 2005-10-29 devnull #include "smtp.h" /* to publish dial_string_parse */
4 b5f65921 2006-02-11 devnull #include <ip.h>
9 cbeb0b26 2006-04-01 devnull Maxstring= 256
12 5cdb1798 2005-10-29 devnull typedef struct Mx Mx;
13 5cdb1798 2005-10-29 devnull struct Mx
15 5cdb1798 2005-10-29 devnull char host[256];
16 5cdb1798 2005-10-29 devnull char ip[24];
17 5cdb1798 2005-10-29 devnull int pref;
19 5cdb1798 2005-10-29 devnull static Mx mx[Nmx];
22 5cdb1798 2005-10-29 devnull extern int debug;
24 5cdb1798 2005-10-29 devnull static int mxlookup(DS*, char*);
25 a79cd783 2006-02-12 devnull static int compar(const void*, const void*);
26 5cdb1798 2005-10-29 devnull static int callmx(DS*, char*, char*);
27 5cdb1798 2005-10-29 devnull static void expand_meta(DS *ds);
28 5cdb1798 2005-10-29 devnull extern int cistrcmp(char*, char*);
31 5cdb1798 2005-10-29 devnull mxdial(char *addr, char *ddomain, char *gdomain)
35 5cdb1798 2005-10-29 devnull char err[Errlen];
37 5cdb1798 2005-10-29 devnull addr = netmkaddr(addr, 0, "smtp");
38 5cdb1798 2005-10-29 devnull dial_string_parse(addr, &ds);
40 5cdb1798 2005-10-29 devnull /* try connecting to destination or any of it's mail routers */
41 5cdb1798 2005-10-29 devnull fd = callmx(&ds, addr, ddomain);
43 5cdb1798 2005-10-29 devnull /* try our mail gateway */
44 5cdb1798 2005-10-29 devnull rerrstr(err, sizeof(err));
45 b5f65921 2006-02-11 devnull if(fd < 0 && gdomain && strstr(err, "can't translate") != 0)
46 5cdb1798 2005-10-29 devnull fd = dial(netmkaddr(gdomain, 0, "smtp"), 0, 0, 0);
48 5cdb1798 2005-10-29 devnull return fd;
51 b5f65921 2006-02-11 devnull static int
52 a79cd783 2006-02-12 devnull timeout(void *v, char *msg)
56 b5f65921 2006-02-11 devnull if(strstr(msg, "alarm"))
57 b5f65921 2006-02-11 devnull return 1;
58 b5f65921 2006-02-11 devnull return 0;
62 5cdb1798 2005-10-29 devnull * take an address and return all the mx entries for it,
63 5cdb1798 2005-10-29 devnull * most preferred first
65 5cdb1798 2005-10-29 devnull static int
66 5cdb1798 2005-10-29 devnull callmx(DS *ds, char *dest, char *domain)
68 5cdb1798 2005-10-29 devnull int fd, i, nmx;
69 5cdb1798 2005-10-29 devnull char addr[Maxstring];
71 5cdb1798 2005-10-29 devnull /* get a list of mx entries */
72 5cdb1798 2005-10-29 devnull nmx = mxlookup(ds, domain);
73 5cdb1798 2005-10-29 devnull if(nmx < 0){
74 5cdb1798 2005-10-29 devnull /* dns isn't working, don't just dial */
75 5cdb1798 2005-10-29 devnull return -1;
77 5cdb1798 2005-10-29 devnull if(nmx == 0){
78 5cdb1798 2005-10-29 devnull if(debug)
79 5cdb1798 2005-10-29 devnull fprint(2, "mxlookup returns nothing\n");
80 5cdb1798 2005-10-29 devnull return dial(dest, 0, 0, 0);
83 5cdb1798 2005-10-29 devnull /* refuse to honor loopback addresses given by dns */
84 5cdb1798 2005-10-29 devnull for(i = 0; i < nmx; i++){
85 5cdb1798 2005-10-29 devnull if(strcmp(mx[i].ip, "127.0.0.1") == 0){
86 5cdb1798 2005-10-29 devnull if(debug)
87 5cdb1798 2005-10-29 devnull fprint(2, "mxlookup returns loopback\n");
88 5cdb1798 2005-10-29 devnull werrstr("illegal: domain lists 127.0.0.1 as mail server");
89 5cdb1798 2005-10-29 devnull return -1;
93 5cdb1798 2005-10-29 devnull /* sort by preference */
94 5cdb1798 2005-10-29 devnull if(nmx > 1)
95 5cdb1798 2005-10-29 devnull qsort(mx, nmx, sizeof(Mx), compar);
97 e269d00c 2006-02-25 devnull if(debug){
98 e269d00c 2006-02-25 devnull for(i=0; i<nmx; i++)
99 e269d00c 2006-02-25 devnull print("%s %d\n", mx[i].host, mx[i].pref);
101 5cdb1798 2005-10-29 devnull /* dial each one in turn */
102 5cdb1798 2005-10-29 devnull for(i = 0; i < nmx; i++){
103 5cdb1798 2005-10-29 devnull snprint(addr, sizeof(addr), "%s/%s!%s!%s", ds->netdir, ds->proto,
104 5cdb1798 2005-10-29 devnull mx[i].host, ds->service);
105 5cdb1798 2005-10-29 devnull if(debug)
106 fe02cd59 2006-03-03 devnull fprint(2, "mxdial trying %s (%d)\n", addr, i);
107 b5f65921 2006-02-11 devnull atnotify(timeout, 1);
108 b5f65921 2006-02-11 devnull alarm(10*1000);
109 5cdb1798 2005-10-29 devnull fd = dial(addr, 0, 0, 0);
110 b5f65921 2006-02-11 devnull alarm(0);
111 b5f65921 2006-02-11 devnull atnotify(timeout, 0);
112 5cdb1798 2005-10-29 devnull if(fd >= 0)
113 5cdb1798 2005-10-29 devnull return fd;
115 5cdb1798 2005-10-29 devnull return -1;
119 5cc53af9 2006-02-12 devnull * use dns to resolve the mx request
121 5cdb1798 2005-10-29 devnull static int
122 5cdb1798 2005-10-29 devnull mxlookup(DS *ds, char *domain)
124 5cc53af9 2006-02-12 devnull int i, n, nmx;
125 5cc53af9 2006-02-12 devnull Ndbtuple *t, *tmx, *tpref, *tip;
127 5cc53af9 2006-02-12 devnull ds->netdir = "/net";
128 5cdb1798 2005-10-29 devnull nmx = 0;
129 5cc53af9 2006-02-12 devnull if((t = dnsquery(nil, ds->host, "mx")) != nil){
130 5cc53af9 2006-02-12 devnull for(tmx=t; (tmx=ndbfindattr(tmx->entry, nil, "mx")) != nil && nmx<Nmx; ){
131 e269d00c 2006-02-25 devnull for(tpref=tmx->line; tpref != tmx; tpref=tpref->line){
132 5cc53af9 2006-02-12 devnull if(strcmp(tpref->attr, "pref") == 0){
133 5cc53af9 2006-02-12 devnull strncpy(mx[nmx].host, tmx->val, sizeof(mx[n].host)-1);
134 5cc53af9 2006-02-12 devnull mx[nmx].pref = atoi(tpref->val);
140 5cc53af9 2006-02-12 devnull ndbfree(t);
144 5cdb1798 2005-10-29 devnull * no mx record? try name itself.
147 5cdb1798 2005-10-29 devnull * BUG? If domain has no dots, then we used to look up ds->host
148 5cdb1798 2005-10-29 devnull * but return domain instead of ds->host in the list. Now we return
149 5cdb1798 2005-10-29 devnull * ds->host. What will this break?
151 5cdb1798 2005-10-29 devnull if(nmx == 0){
152 5cdb1798 2005-10-29 devnull mx[0].pref = 1;
153 5cdb1798 2005-10-29 devnull strncpy(mx[0].host, ds->host, sizeof(mx[0].host));
158 5cdb1798 2005-10-29 devnull * look up all ip addresses
160 5cdb1798 2005-10-29 devnull for(i = 0; i < nmx; i++){
161 5cc53af9 2006-02-12 devnull if((t = dnsquery(nil, mx[i].host, "ip")) == nil)
162 5cdb1798 2005-10-29 devnull goto no;
163 5cc53af9 2006-02-12 devnull if((tip = ndbfindattr(t, nil, "ip")) == nil){
164 5cc53af9 2006-02-12 devnull ndbfree(t);
165 5cdb1798 2005-10-29 devnull goto no;
167 5cc53af9 2006-02-12 devnull strncpy(mx[i].ip, tip->val, sizeof(mx[i].ip)-1);
168 5cc53af9 2006-02-12 devnull ndbfree(t);
169 5cdb1798 2005-10-29 devnull continue;
172 5cdb1798 2005-10-29 devnull /* remove mx[i] and go around again */
174 5cdb1798 2005-10-29 devnull mx[i] = mx[nmx];
177 5cdb1798 2005-10-29 devnull return nmx;
180 5cdb1798 2005-10-29 devnull static int
181 a79cd783 2006-02-12 devnull compar(const void *a, const void *b)
183 5cdb1798 2005-10-29 devnull return ((Mx*)a)->pref - ((Mx*)b)->pref;
186 5cdb1798 2005-10-29 devnull /* break up an address to its component parts */
188 5cdb1798 2005-10-29 devnull dial_string_parse(char *str, DS *ds)
190 5cdb1798 2005-10-29 devnull char *p, *p2;
192 5cdb1798 2005-10-29 devnull strncpy(ds->buf, str, sizeof(ds->buf));
193 5cdb1798 2005-10-29 devnull ds->buf[sizeof(ds->buf)-1] = 0;
195 5cdb1798 2005-10-29 devnull p = strchr(ds->buf, '!');
196 5cdb1798 2005-10-29 devnull if(p == 0) {
197 5cdb1798 2005-10-29 devnull ds->netdir = 0;
198 5cdb1798 2005-10-29 devnull ds->proto = "net";
199 5cdb1798 2005-10-29 devnull ds->host = ds->buf;
200 5cdb1798 2005-10-29 devnull } else {
201 5cdb1798 2005-10-29 devnull if(*ds->buf != '/'){
202 5cdb1798 2005-10-29 devnull ds->netdir = 0;
203 5cdb1798 2005-10-29 devnull ds->proto = ds->buf;
204 5cdb1798 2005-10-29 devnull } else {
205 5cdb1798 2005-10-29 devnull for(p2 = p; *p2 != '/'; p2--)
207 5cdb1798 2005-10-29 devnull *p2++ = 0;
208 5cdb1798 2005-10-29 devnull ds->netdir = ds->buf;
209 5cdb1798 2005-10-29 devnull ds->proto = p2;
212 5cdb1798 2005-10-29 devnull ds->host = p + 1;
214 5cdb1798 2005-10-29 devnull ds->service = strchr(ds->host, '!');
215 5cdb1798 2005-10-29 devnull if(ds->service)
216 5cdb1798 2005-10-29 devnull *ds->service++ = 0;
217 5cdb1798 2005-10-29 devnull if(*ds->host == '$')
218 5cdb1798 2005-10-29 devnull expand_meta(ds);
221 5cdb1798 2005-10-29 devnull static void
222 5cdb1798 2005-10-29 devnull expand_meta(DS *ds)
224 5cc53af9 2006-02-12 devnull static Ndb *db;
226 5cdb1798 2005-10-29 devnull char *sys, *smtpserver;
228 5cc53af9 2006-02-12 devnull /* can't ask cs, so query database directly. */
229 5cdb1798 2005-10-29 devnull sys = sysname();
230 5cc53af9 2006-02-12 devnull if(db == nil)
231 5cc53af9 2006-02-12 devnull db = ndbopen(0);
232 5cdb1798 2005-10-29 devnull smtpserver = ndbgetvalue(db, &s, "sys", sys, "smtp", nil);
233 5cc53af9 2006-02-12 devnull snprint(ds->host, 128, "%s", smtpserver);