|
|
1.1 root 1: #include <sys/types.h> /* needed for socket.h */
2: #include <sys/uio.h> /* needed for socket.h */
3: #include <sys/socket.h>
4: #include <sysexits.h>
5: #include <netinet/in.h>
6: #include <netdb.h>
7: #include <stdio.h>
8: #include <arpa/nameser.h>
9: #include <string.h>
10:
11: /* imports */
12: extern char *malloc(), *strcpy(), *inet_ntoa();
13:
14: extern int ipcdebug;
15: extern char syserrstr[];
16:
17: /* private */
18: #define MAXMXLIST 10
19: static struct mxitem {
20: char *host;
21: u_short pref;
22: u_char localflag;
23: } MXlist[MAXMXLIST + 1];
24: static char *strsave();
25: static int buildmxlist();
26: static void mxsave(), mxinsert(), mxlocal();
27: static struct hostent *getmxhost();
28:
29: mx_connect(dest, param)
30: char *dest, *param;
31: {
32: int s, lport, mxfatal;
33: char **addr;
34: char host[100];
35: struct hostent *hp;
36: struct sockaddr_in sin;
37: struct mxitem *mxp;
38: extern int tcp_service();
39: int port;
40: char *bp;
41: int errtype = 0;
42: char errstr[256];
43:
44: strcpy(host, dest);
45:
46: if ((port = tcp_service(host)) < 0) {
47: ipcsyserr("unknown service");
48: return(-1);
49: }
50:
51: mxfatal = buildmxlist(host);
52: if (MXlist[0].host == 0)
53: return(tcp_connect(dest, param));
54: /*MXlist[0].host = host;*/
55:
56: (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) 0, 0);
57:
58: /* slop in the loop -- i hate the socket dance */
59: for (mxp = MXlist; mxp->host; mxp++) {
60: int i;
61:
62: if ((hp = getmxhost(mxp->host)) == 0) {
63: if (mxfatal) {
64: ipcsyserr("stub - can't find useful host"); /*EX_NOHOST*/
65: return -1;
66: }
67: continue;
68: }
69: for (i=0; hp->h_addr_list[i]; i++) {
70: s = socket(AF_INET, SOCK_STREAM, 0);
71: if (s < 0) {
72: ipcsyserr("Can't open socket"); /*EX_OSERR*/
73: return -1;
74: }
75: bzero((char *)&sin, sizeof(sin));
76: sin.sin_port = port;
77: sin.sin_family = hp->h_addrtype;
78: bcopy(hp->h_addr_list[i], (char *) &sin.sin_addr,
79: hp->h_length);
80: if (ipcdebug)
81: fprintf(stderr, "try %s [%s]\n", mxp->host,
82: inet_ntoa(sin.sin_addr));
83: if (connect(s, (struct sockaddr *)&sin, sizeof(sin))>=0) {
84: if (ipcdebug)
85: fprintf(stderr, " connected\n");
86: return s;
87: }
88: ipcgetsyserr();
89: fprintf(stderr, "Couldn't connect to %s [%s]: %s\n",
90: mxp->host, inet_ntoa(sin.sin_addr), syserrstr);
91: if (errtype == 0 ||
92: (errtype != EX_TEMPFAIL && ipcmaperror()==EX_TEMPFAIL)) {
93: errtype = ipcmaperror();
94: strcpy(errstr, syserrstr);
95: }
96: close(s);
97: }
98: }
99: ipcseterror(errtype, errstr, "Can't connect to host");
100: return -1;
101: }
102:
103: /* return 1 for fatal MX error (authoritative NXDOMAIN), 0 o.w. */
104: static int
105: buildmxlist(host)
106: char *host;
107: { register HEADER *hp;
108: register char *cp;
109: register int n;
110: char q[PACKETSZ], a[PACKETSZ]; /* query, answer */
111: char *eom, *bp;
112: int buflen, ancount, qdcount;
113: char hostbuf[BUFSIZ+1];
114: u_short preference, reclen;
115: int niter = 0;
116: char nhostbuf[BUFSIZ+1];
117:
118: again:
119: if ((n = res_mkquery(QUERY, host, C_IN, T_MX, (char *) 0,
120: 0, (struct rrec *) 0, q, sizeof(q))) < 0)
121: return 0;
122: n = res_send(q, n, a, sizeof(a));
123: if (n < 0)
124: return 0;
125: if (ipcdebug)
126: fprintf(stderr, "buildmxlist got %d\n", n);
127: eom = a + n;
128: hp = (HEADER *) a;
129: ancount = ntohs(hp->ancount);
130: qdcount = ntohs(hp->qdcount);
131: if (ipcdebug)
132: fprintf(stderr, "buildmx rcode %d ancount %d qdcount %d aa %d\n",
133: hp->rcode, ancount, qdcount, hp->aa);
134: if (hp->rcode != NOERROR || ancount == 0) {
135: if (hp->aa == 0)
136: return 0; /* non-authoritative in any event */
137: return hp->rcode == NOERROR || hp->rcode == NXDOMAIN;
138: }
139: bp = hostbuf;
140: buflen = sizeof(hostbuf);
141: cp = a + sizeof(HEADER);
142: if (ipcdebug>1) {
143: int i;
144: fprintf(stderr, "buildmx got:");
145: for (i=0; i<n; i++)
146: if (a[i]>=' '&& a[i]<0177)
147: fprintf(stderr, "%c", a[i]);
148: else fprintf(stderr, "\\%.3o", a[i]&0377);
149: fprintf(stderr, "\n");
150: }
151: while (--qdcount >= 0)
152: cp += dn_skipname(cp,eom) + QFIXEDSZ;
153: /* TODO: if type is CNAME, reissue query */
154: while (--ancount >= 0 && cp < eom) {
155: int type;
156: cp += dn_skipname(cp,eom); /* name */
157: type = _getshort(cp);
158: cp += sizeof(u_short) /* type */
159: + sizeof(u_short) /* class */
160: + sizeof(u_long); /* ttl (see rfc973) */
161: reclen = _getshort(cp);
162: cp += sizeof(u_short);
163: if (type==T_CNAME) { /* canonical name */
164: if (dn_expand(a, eom, cp, nhostbuf, BUFSIZ) < 0)
165: if (ipcdebug)
166: fprintf(stderr, "CNAME? in mxexpand\n");
167: host = nhostbuf;
168: if (++niter>10)
169: return 0;
170: if (ipcdebug)
171: fprintf(stderr, "CNAME, try with %s\n", host);
172: goto again;
173: }
174: preference = _getshort(cp);
175: if ((n = dn_expand(a, eom, cp + sizeof(u_short), bp, buflen)) < 0)
176: break;
177: mxsave(bp, preference);
178: cp += reclen;
179: }
180: mxlocal();
181: return 0;
182: }
183:
184: /* NOT TODO: issue WKS query. (just try to connect.) */
185:
186: static void
187: mxsave(host, pref)
188: char *host;
189: u_short pref;
190: { struct mxitem *mxp;
191: int localflag;
192: static char thishost[64];
193:
194: if (*thishost == 0)
195: gethostname(thishost, sizeof(thishost));
196: if (ipcdebug)
197: fprintf(stderr, "MXsave %s\n", host);
198:
199: if (MXlist[MAXMXLIST].host)
200: return; /* full */
201:
202: localflag = (strcmp(thishost, host) == 0);
203:
204: /* insertion sort */
205: for (mxp = MXlist; mxp < MXlist + MAXMXLIST; mxp++) {
206: if (mxp->host == 0) {
207: mxinsert(mxp, host, pref, localflag);
208: return;
209: }
210: if (pref < mxp->pref) {
211: mxinsert(mxp, host, pref, localflag);
212: return;
213: }
214: if (pref == mxp->pref) {
215: if (mxp->localflag)
216: return;
217: if (localflag) {
218: mxp->host = strsave(host);
219: mxp->pref = pref;
220: mxp->localflag = localflag;
221: (++mxp)->host = 0;
222: return;
223: }
224: mxinsert(mxp, host, pref, localflag);
225: return;
226: }
227: }
228: }
229:
230: static void
231: mxinsert(mxlistp, host, pref, localflag)
232: struct mxitem *mxlistp;
233: char *host;
234: u_short pref;
235: { register struct mxitem *mxp;
236:
237: for (mxp = MXlist + MAXMXLIST - 1; mxp > mxlistp; --mxp)
238: *mxp = mxp[-1];
239: mxp->host = strsave(host);
240: mxp->pref = pref;
241: mxp->localflag = localflag;
242: }
243:
244: static char *
245: strsave(str)
246: register char *str;
247: { register char *rval;
248:
249: if ((rval = malloc(strlen(str) + 1)) == 0) {
250: ipcsyserr("mx connect malloc");
251: exit(1);
252: }
253: strcpy(rval, str);
254: return rval;
255: }
256:
257: static void
258: mxlocal()
259: { register struct mxitem *mxp;
260:
261: if (MXlist[0].host == 0)
262: return;
263:
264: for (mxp = MXlist; mxp->host; mxp++) {
265: if (mxp->localflag) {
266: mxp->host = 0;
267: break;
268: }
269: }
270: }
271:
272: static struct hostent *
273: getmxhost(host)
274: char *host;
275: { struct hostent *hp, *gethostbyname();
276: long inet_addr();
277: int err;
278: char errbuf[256];
279: static struct in_addr ia;
280: static char *hlist[2] = {0, 0};
281: static struct hostent he =
282: {0, 0, AF_INET, sizeof(struct in_addr), hlist};
283:
284: if (!host)
285: return 0;
286:
287: if ((hp = gethostbyname(host)) != 0)
288: return hp;
289: ipcgetsyserr();
290:
291: if ((ia.s_addr = inet_addr(host)) != -1) {
292: he.h_addr = (char *)&ia;
293: return &he;
294: }
295: sprintf(errbuf, "Error looking up MX Host '%s'.\n", host);
296: ipcsyserr(errbuf);
297: return 0;
298: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.