Blame


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>
5 5cdb1798 2005-10-29 devnull
6 5cdb1798 2005-10-29 devnull enum
7 5cdb1798 2005-10-29 devnull {
8 5cdb1798 2005-10-29 devnull Nmx= 16,
9 cbeb0b26 2006-04-01 devnull Maxstring= 256
10 5cdb1798 2005-10-29 devnull };
11 5cdb1798 2005-10-29 devnull
12 5cdb1798 2005-10-29 devnull typedef struct Mx Mx;
13 5cdb1798 2005-10-29 devnull struct Mx
14 5cdb1798 2005-10-29 devnull {
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;
18 5cdb1798 2005-10-29 devnull };
19 5cdb1798 2005-10-29 devnull static Mx mx[Nmx];
20 5cdb1798 2005-10-29 devnull
21 5cdb1798 2005-10-29 devnull Ndb *db;
22 5cdb1798 2005-10-29 devnull extern int debug;
23 5cdb1798 2005-10-29 devnull
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*);
29 5cdb1798 2005-10-29 devnull
30 5cdb1798 2005-10-29 devnull int
31 5cdb1798 2005-10-29 devnull mxdial(char *addr, char *ddomain, char *gdomain)
32 5cdb1798 2005-10-29 devnull {
33 5cdb1798 2005-10-29 devnull int fd;
34 5cdb1798 2005-10-29 devnull DS ds;
35 5cdb1798 2005-10-29 devnull char err[Errlen];
36 5cdb1798 2005-10-29 devnull
37 5cdb1798 2005-10-29 devnull addr = netmkaddr(addr, 0, "smtp");
38 5cdb1798 2005-10-29 devnull dial_string_parse(addr, &ds);
39 5cdb1798 2005-10-29 devnull
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);
42 5cdb1798 2005-10-29 devnull
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);
47 5cdb1798 2005-10-29 devnull
48 5cdb1798 2005-10-29 devnull return fd;
49 b5f65921 2006-02-11 devnull }
50 b5f65921 2006-02-11 devnull
51 b5f65921 2006-02-11 devnull static int
52 a79cd783 2006-02-12 devnull timeout(void *v, char *msg)
53 b5f65921 2006-02-11 devnull {
54 a79cd783 2006-02-12 devnull USED(v);
55 a79cd783 2006-02-12 devnull
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;
59 5cdb1798 2005-10-29 devnull }
60 5cdb1798 2005-10-29 devnull
61 5cdb1798 2005-10-29 devnull /*
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
64 5cdb1798 2005-10-29 devnull */
65 5cdb1798 2005-10-29 devnull static int
66 5cdb1798 2005-10-29 devnull callmx(DS *ds, char *dest, char *domain)
67 5cdb1798 2005-10-29 devnull {
68 5cdb1798 2005-10-29 devnull int fd, i, nmx;
69 5cdb1798 2005-10-29 devnull char addr[Maxstring];
70 5cdb1798 2005-10-29 devnull
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;
76 5cdb1798 2005-10-29 devnull }
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);
81 5cdb1798 2005-10-29 devnull }
82 5cdb1798 2005-10-29 devnull
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;
90 5cdb1798 2005-10-29 devnull }
91 5cdb1798 2005-10-29 devnull }
92 5cdb1798 2005-10-29 devnull
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);
96 5cdb1798 2005-10-29 devnull
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);
100 e269d00c 2006-02-25 devnull }
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;
114 5cdb1798 2005-10-29 devnull }
115 5cdb1798 2005-10-29 devnull return -1;
116 5cdb1798 2005-10-29 devnull }
117 5cdb1798 2005-10-29 devnull
118 5cdb1798 2005-10-29 devnull /*
119 5cc53af9 2006-02-12 devnull * use dns to resolve the mx request
120 5cdb1798 2005-10-29 devnull */
121 5cdb1798 2005-10-29 devnull static int
122 5cdb1798 2005-10-29 devnull mxlookup(DS *ds, char *domain)
123 5cdb1798 2005-10-29 devnull {
124 5cc53af9 2006-02-12 devnull int i, n, nmx;
125 5cc53af9 2006-02-12 devnull Ndbtuple *t, *tmx, *tpref, *tip;
126 5cc53af9 2006-02-12 devnull
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);
135 5cc53af9 2006-02-12 devnull nmx++;
136 5cc53af9 2006-02-12 devnull break;
137 5cc53af9 2006-02-12 devnull }
138 5cc53af9 2006-02-12 devnull }
139 5cdb1798 2005-10-29 devnull }
140 5cc53af9 2006-02-12 devnull ndbfree(t);
141 5cdb1798 2005-10-29 devnull }
142 5cdb1798 2005-10-29 devnull
143 5cdb1798 2005-10-29 devnull /*
144 5cdb1798 2005-10-29 devnull * no mx record? try name itself.
145 5cdb1798 2005-10-29 devnull */
146 5cdb1798 2005-10-29 devnull /*
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?
150 5cdb1798 2005-10-29 devnull */
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));
154 5cdb1798 2005-10-29 devnull nmx++;
155 5cdb1798 2005-10-29 devnull }
156 5cdb1798 2005-10-29 devnull
157 5cdb1798 2005-10-29 devnull /*
158 5cdb1798 2005-10-29 devnull * look up all ip addresses
159 5cdb1798 2005-10-29 devnull */
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;
166 5cc53af9 2006-02-12 devnull }
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;
170 5cc53af9 2006-02-12 devnull
171 5cdb1798 2005-10-29 devnull no:
172 5cdb1798 2005-10-29 devnull /* remove mx[i] and go around again */
173 5cdb1798 2005-10-29 devnull nmx--;
174 5cdb1798 2005-10-29 devnull mx[i] = mx[nmx];
175 5cdb1798 2005-10-29 devnull i--;
176 5cdb1798 2005-10-29 devnull }
177 5cdb1798 2005-10-29 devnull return nmx;
178 5cdb1798 2005-10-29 devnull }
179 5cdb1798 2005-10-29 devnull
180 5cdb1798 2005-10-29 devnull static int
181 a79cd783 2006-02-12 devnull compar(const void *a, const void *b)
182 5cdb1798 2005-10-29 devnull {
183 5cdb1798 2005-10-29 devnull return ((Mx*)a)->pref - ((Mx*)b)->pref;
184 5cdb1798 2005-10-29 devnull }
185 5cdb1798 2005-10-29 devnull
186 5cdb1798 2005-10-29 devnull /* break up an address to its component parts */
187 5cdb1798 2005-10-29 devnull void
188 5cdb1798 2005-10-29 devnull dial_string_parse(char *str, DS *ds)
189 5cdb1798 2005-10-29 devnull {
190 5cdb1798 2005-10-29 devnull char *p, *p2;
191 5cdb1798 2005-10-29 devnull
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;
194 5cdb1798 2005-10-29 devnull
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--)
206 5cdb1798 2005-10-29 devnull ;
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;
210 5cdb1798 2005-10-29 devnull }
211 5cdb1798 2005-10-29 devnull *p = 0;
212 5cdb1798 2005-10-29 devnull ds->host = p + 1;
213 5cdb1798 2005-10-29 devnull }
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);
219 5cdb1798 2005-10-29 devnull }
220 5cdb1798 2005-10-29 devnull
221 5cdb1798 2005-10-29 devnull static void
222 5cdb1798 2005-10-29 devnull expand_meta(DS *ds)
223 5cdb1798 2005-10-29 devnull {
224 5cc53af9 2006-02-12 devnull static Ndb *db;
225 5cdb1798 2005-10-29 devnull Ndbs s;
226 5cdb1798 2005-10-29 devnull char *sys, *smtpserver;
227 5cdb1798 2005-10-29 devnull
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);
234 5cdb1798 2005-10-29 devnull }