]> Pileus Git - ~andy/fetchmail/blob - mxget.c
Note Earl's regression fix for SSL_CTX_clear_options() on older OpenSSL.
[~andy/fetchmail] / mxget.c
1 /*
2  * mxget.c -- fetch MX records for given DNS name
3  *
4  * Copyright (C) 1996, 1997, 1998, 2000, 2002 by Eric S. Raymond
5  * Copyright (C) 2005, 2006, 2007 by Matthias Andree
6  * For license terms, see the file COPYING in this directory.
7  */
8
9 #include "config.h"
10 #include "fetchmail.h"
11 #include <stdio.h>
12 #include <string.h>
13 #ifdef HAVE_RES_SEARCH
14 #ifdef HAVE_NET_SOCKET_H
15 #include <net/socket.h>
16 #endif
17 #include <netdb.h>
18 #include <sys/types.h>
19 #include <netinet/in.h>
20
21 #ifdef __BEOS__
22 #include "beos/beos_nameser.h"
23 #endif
24
25 #ifdef HAVE_ARPA_NAMESER_H
26 #include <arpa/nameser.h>
27 #endif
28 #ifdef HAVE_RESOLV_H
29 #include <resolv.h>
30 #endif
31
32 #include "mx.h"
33
34 /*
35  * This ought to be in the bind library.  It's adapted from sendmail.
36  */
37
38 /*
39  * These are defined in RFC833. Some bind interface headers don't declare them.
40  * Ghod help us if they're ever actually incompatible with what's in 
41  * the arpa/nameser.h header.
42  */
43 #ifndef PACKETSZ
44 #define PACKETSZ        512             /* maximum packet size */
45 #endif
46 #ifndef HFIXEDSZ
47 #define HFIXEDSZ        12              /* #/bytes of fixed data in header */
48 #endif
49 #ifndef INT32SZ
50 #define INT32SZ         4               /* for systems without 32-bit ints */
51 #endif
52 #ifndef INT16SZ
53 #define INT16SZ         2               /* for systems without 16-bit ints */
54 #endif
55
56 /* minimum possible size of MX record in packet */
57 #define MIN_MX_SIZE     8       /* corresp to "a.com 0" w/ terminating space */
58
59 struct mxentry *getmxrecords(const char *name)
60 /* get MX records for given host */
61 {
62     char answer[PACKETSZ], *eom, *cp, *bp;
63     int n, ancount, qdcount, buflen, type, pref, ind;
64     static struct mxentry pmx[(PACKETSZ - HFIXEDSZ) / MIN_MX_SIZE];
65     static char MXHostBuf[PACKETSZ - HFIXEDSZ]; 
66     HEADER *hp;
67
68     pmx->name = (char *)NULL;
69     pmx->pref = -1;
70     n = res_search(name, C_IN,T_MX, (unsigned char *)&answer, sizeof(answer));
71     if (n == -1)
72         return((struct mxentry *)NULL);
73     if ((size_t)n > sizeof(answer))
74         n = sizeof(answer);     
75
76     hp = (HEADER *)&answer;
77     cp = answer + HFIXEDSZ;
78     eom = answer + n;
79     h_errno = 0;
80     for (qdcount = ntohs(hp->qdcount); qdcount--; cp += n + QFIXEDSZ)
81       if ((n = dn_skipname((unsigned char *)cp, (unsigned char *)eom)) < 0)
82             return((struct mxentry *)NULL);
83     buflen = sizeof(MXHostBuf) - 1;
84     bp = MXHostBuf;
85     ind = 0;
86     ancount = ntohs(hp->ancount);
87     while (--ancount >= 0 && cp < eom)
88     {
89         if ((n = dn_expand((unsigned char *)answer, (unsigned char *)eom,
90                            (unsigned char *)cp, bp, buflen)) < 0)
91             break;
92         cp += n;
93         GETSHORT(type, cp);
94         cp += INT16SZ + INT32SZ;
95         GETSHORT(n, cp);
96         if (type != T_MX)
97         {
98             cp += n;
99             continue;
100         }
101         GETSHORT(pref, cp);
102         if ((n = dn_expand((unsigned char *)answer, (unsigned char *)eom,
103                            (unsigned char *)cp, bp, buflen)) < 0)
104             break;
105         cp += n;
106
107         pmx[ind].name = bp;
108         pmx[ind].pref = pref;
109         ++ind;
110
111         n = strlen((const char *)bp);
112         bp += n;
113         *bp++ = '\0';
114
115         buflen -= n + 1;
116     }
117
118     pmx[ind].name = (char *)NULL;
119     pmx[ind].pref = -1;
120     return(pmx);
121 }
122 #endif /* HAVE_RES_SEARCH */
123
124 #ifdef STANDALONE
125 #include <stdlib.h>
126
127 int main(int argc, char *argv[])
128 {
129 #ifdef HAVE_RES_SEARCH
130     struct mxentry *responses;
131 #endif
132
133     if (argc != 2 || 0 == strcmp(argv[1], "-h")) {
134         fprintf(stderr, "Usage: %s domain\n", argv[0]);
135         exit(1);
136     }
137
138 #ifdef HAVE_RES_SEARCH
139     responses = getmxrecords(argv[1]);
140     if (responses == (struct mxentry *)NULL) {
141         puts("No MX records found");
142     } else {
143         do {
144             printf("%s %d\n", responses->name, responses->pref);
145         } while ((++responses)->name);
146     }
147 #else
148     puts("This program was compiled without HAS_RES_SEARCH and does nothing.");
149 #endif
150
151     return 0;
152 }
153 #endif /* TESTMAIN */
154
155 /* mxget.c ends here */