|
|
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.