home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume3 / sm-smtp / mx.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-03  |  5.6 KB  |  276 lines

  1. #include <stdio.h>
  2. #include <netdb.h>
  3. #include <sysexits.h>
  4. #include <sys/errno.h>
  5. #include <sys/types.h>
  6. #include <sys/socket.h>
  7. #include <netinet/in.h>
  8. #include <arpa/nameser.h>
  9. #include "miscerrs.h"
  10.  
  11. /* imports */
  12. extern int errno, h_errno;
  13. extern char *malloc(), *strcpy(), *inet_ntoa();
  14.  
  15. /* exports */
  16. int mxconnect();
  17.  
  18. /* private */
  19. #define MAXMXLIST 10
  20. static struct mxitem {
  21.     char *host;
  22.     u_short pref;
  23.     u_char localflag;
  24. } MXlist[MAXMXLIST + 1];
  25. static char *strsave();
  26. static int buildmxlist();
  27. static void mxsave(), mxinsert(), mxlocal();
  28. static struct hostent *getmxhost();
  29.  
  30. #ifdef MXMAIN
  31.  
  32. #define bomb return
  33.  
  34. main(argc, argv)
  35.     char **argv;
  36. {    int fd;
  37.     char buf[BUFSIZ], *crlf, *index();
  38.     struct mxitem *mxp;
  39.  
  40.     for (;;) {
  41.         printf("domain: ");
  42.         if (argc > 1)
  43.             strcpy(buf, argv[1]);
  44.         else if (gets(buf) == 0)
  45.             break;
  46.         if ((fd = mxconnect(buf)) >= 0)
  47.             if (read(fd, buf, 512) > 0) {
  48.                 if ((crlf = index(buf, '\r')) != 0)
  49.                     strcpy(crlf, "\n");
  50.                 puts(buf);
  51.             } else
  52.                 perror("read");
  53.         close(fd);
  54.         if (argc > 1)
  55.             break;
  56.         for (mxp = MXlist; mxp < MXlist + MAXMXLIST + 1; mxp++)
  57.             mxp->host = 0;
  58.     }
  59.     return 0;
  60. }
  61. #endif
  62.  
  63. mxconnect(host)
  64.     char *host;
  65. {    int s, lport, mxfatal;
  66.     char **addr, errbuf[256];
  67.     struct hostent *hp;
  68.     struct servent *sp;
  69.     struct sockaddr_in sin;
  70.     struct mxitem *mxp;
  71.  
  72.     mxfatal = buildmxlist(host);
  73.     if (MXlist[0].host == 0)
  74.         MXlist[0].host = host;
  75.     if ((sp = getservbyname ("smtp", "tcp")) == NULL) {
  76.         (void)fprintf(stderr,"unknown service TCP/smtp\n");
  77.         bomb(E_OSFILE);
  78.     }
  79.     (void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) 0, 0);
  80.  
  81.     /* slop in the loop -- i hate the socket dance */
  82.     for (mxp = MXlist; mxp->host; mxp++) {
  83.         if ((s = rresvport(&lport)) < 0) {
  84.             perror("rresvport");
  85.             bomb(E_CANTOPEN);
  86.         }
  87.         if ((hp = getmxhost(mxp->host)) == 0) {
  88.             (void) close(s);
  89.             if (mxfatal)
  90.                 bomb(E_NOHOST);
  91.             continue;
  92.         }
  93.         bzero((char *)&sin, sizeof(sin));
  94.         sin.sin_port = sp->s_port;
  95.         sin.sin_family = hp->h_addrtype;
  96.         for (addr = hp->h_addr_list; *addr; addr++) {
  97.             bcopy(*addr, (char *) &sin.sin_addr, hp->h_length);
  98.             if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
  99.                 sprintf(errbuf, "%s [%s]", mxp->host, inet_ntoa(sin.sin_addr));
  100.                 perror(errbuf);
  101.                 continue;
  102.             }
  103.             return s;
  104.         }
  105.         close(s);
  106.     }
  107.  
  108.     bomb(E_TEMPFAIL);
  109. }
  110.  
  111. /* return 1 for fatal MX error (authoritative NXDOMAIN), 0 o.w. */
  112. static int
  113. buildmxlist(host)
  114.     char *host;
  115. {    register HEADER *hp;
  116.     register char *cp;
  117.     register int n;
  118.     char q[PACKETSZ], a[PACKETSZ];    /* query, answer */
  119.     char *eom, *bp;
  120.     int buflen, ancount, qdcount;
  121.     char hostbuf[BUFSIZ+1];
  122.     u_short preference, reclen;
  123.  
  124.     if ((n = res_mkquery(QUERY, host, C_IN, T_MX, (char *) 0, 0, (struct rrec *) 0, q, sizeof(q))) < 0)
  125.         return 0;
  126.     n = res_send(q, n, a, sizeof(a));
  127.     if (n < 0)
  128.         return 0;
  129.     eom = a + n;
  130.     hp = (HEADER *) a;
  131.     ancount = ntohs(hp->ancount);
  132.     qdcount = ntohs(hp->qdcount);
  133.     if (hp->rcode != NOERROR || ancount == 0)
  134.         return hp->rcode == NXDOMAIN && hp->aa;
  135.     bp = hostbuf;
  136.     buflen = sizeof(hostbuf);
  137.     cp = a + sizeof(HEADER);
  138.     while (--qdcount >= 0)
  139.         cp += dn_skip(cp) + QFIXEDSZ;
  140.     /* TODO: if type is CNAME, reissue query */
  141.     while (--ancount >= 0 && cp < eom) {
  142.         cp += dn_skip(cp)    /* name */
  143.             + sizeof(u_short)    /* type */    
  144.             + sizeof(u_short)    /* class */
  145.             + sizeof(u_long);    /* ttl (see rfc973) */
  146.         reclen = _getshort(cp);
  147.         cp += sizeof(u_short);
  148.         preference = _getshort(cp);
  149.         if ((n = dn_expand(a, eom, cp + sizeof(u_short), bp, buflen)) < 0)
  150.             break;
  151.         mxsave(bp, preference);
  152.         cp += reclen;
  153.     }
  154.     mxlocal();
  155.     return 0;
  156. }
  157.  
  158. /* NOT TODO: issue WKS query.  (just try to connect.) */
  159.  
  160. static void
  161. mxsave(host, pref)
  162.     char *host;
  163.     u_short pref;
  164. {    struct mxitem *mxp;
  165.     int localflag;
  166.     static char thishost[64];
  167.  
  168.     if (*thishost == 0)
  169.         gethostname(thishost, sizeof(thishost));
  170.  
  171.     if (MXlist[MAXMXLIST].host)
  172.         return;                /* full */
  173.  
  174.     localflag = (strcmp(thishost, host) == 0);
  175.  
  176.     /* insertion sort */
  177.     for (mxp = MXlist; mxp < MXlist + MAXMXLIST; mxp++) {
  178.         if (mxp->host == 0) {
  179.             mxinsert(mxp, host, pref, localflag);
  180.             return;
  181.         }
  182.         if (pref < mxp->pref) {
  183.             mxinsert(mxp, host, pref, localflag);
  184.             return;
  185.         }
  186.         if (pref == mxp->pref) {
  187.             if (mxp->localflag)
  188.                 return;
  189.             if (localflag) {
  190.                 mxp->host = strsave(host);
  191.                 mxp->pref = pref;
  192.                 mxp->localflag = localflag;
  193.                 (++mxp)->host = 0;
  194.                 return;
  195.             }
  196.             mxinsert(mxp, host, pref, localflag);
  197.             return;
  198.         }
  199.     }
  200. }
  201.  
  202. static void
  203. mxinsert(mxlistp, host, pref, localflag)
  204.     struct mxitem *mxlistp;
  205.     char *host;
  206.     u_short pref;
  207. {    register struct mxitem *mxp;
  208.  
  209.     for (mxp = MXlist + MAXMXLIST - 1; mxp > mxlistp; --mxp)
  210.         *mxp = mxp[-1];
  211.     mxp->host = strsave(host);
  212.     mxp->pref = pref;
  213.     mxp->localflag = localflag;
  214. }
  215.  
  216. static char *
  217. strsave(str)
  218.     register char *str;
  219. {    register char *rval;
  220.  
  221.     if ((rval = malloc(strlen(str) + 1)) == 0) {
  222.         perror("malloc");
  223.         bomb(-EX_SOFTWARE);
  224.     }
  225.     strcpy(rval, str);
  226.     return rval;
  227. }
  228.  
  229. static void
  230. mxlocal()
  231. {    register struct mxitem *mxp;
  232.  
  233.     if (MXlist[0].host == 0)
  234.         return;
  235.  
  236.     for (mxp = MXlist; mxp->host; mxp++) {
  237.         if (mxp->localflag) {
  238.             mxp->host = 0;
  239.             break;
  240.         }
  241.     }
  242. }
  243.  
  244. static struct hostent *
  245. getmxhost(host)
  246.     char *host;
  247. {    struct hostent *hp, *gethostbyname();
  248.  
  249.     if ((hp = gethostbyname(host)) != 0)
  250.         return hp;
  251.  
  252.     switch(h_errno) {
  253.  
  254.     case HOST_NOT_FOUND:
  255.         (void) fprintf(stderr, "unknown host (%s).\n", host);
  256.         break;
  257.  
  258.     case TRY_AGAIN:
  259.         (void) fprintf(stderr, "name server not responding (%s).\n", host);
  260.         break;
  261.  
  262.     case NO_RECOVERY:
  263.         (void) fprintf(stderr, "name server error (%s).\n", host);
  264.         break;
  265.         
  266.     case NO_ADDRESS:
  267.         (void) fprintf(stderr, "no IP address (%s).\n", host);
  268.         break;
  269.     
  270.     default:
  271.         (void) fprintf(stderr, "unknown resolver error (%s).\n", host);
  272.         break;
  273.     }
  274.     return 0;
  275. }
  276.