14fdc5a2e5dc1b2da0bcd4447e2610f0dc2dcbc9
[users/jgh/exim.git] / src / src / lookups / dnsdb.c
1 /* $Cambridge: exim/src/src/lookups/dnsdb.c,v 1.1 2004/10/07 13:10:01 ph10 Exp $ */
2
3 /*************************************************
4 *     Exim - an Internet mail transport agent    *
5 *************************************************/
6
7 /* Copyright (c) University of Cambridge 1995 - 2004 */
8 /* See the file NOTICE for conditions of use and distribution. */
9
10 #include "../exim.h"
11 #include "lf_functions.h"
12 #include "dnsdb.h"
13
14
15
16 /* Ancient systems (e.g. SunOS4) don't appear to have T_TXT defined in their
17 header files. */
18
19 #ifndef T_TXT
20 #define T_TXT 16
21 #endif
22
23 /* Table of recognized DNS record types and their integer values. */
24
25 static char *type_names[] = {
26   "a",
27 #if HAVE_IPV6
28   "aaaa",
29   #ifdef SUPPORT_A6
30   "a6",
31   #endif
32 #endif
33   "cname",
34   "mx",
35   "ns",
36   "ptr",
37   "srv",
38   "txt" };
39
40 static int type_values[] = {
41   T_A,
42 #if HAVE_IPV6
43   T_AAAA,
44   #ifdef SUPPORT_A6
45   T_A6,
46   #endif
47 #endif
48   T_CNAME,
49   T_MX,
50   T_NS,
51   T_PTR,
52   T_SRV,
53   T_TXT };
54
55
56 /*************************************************
57 *              Open entry point                  *
58 *************************************************/
59
60 /* See local README for interface description. */
61
62 void *
63 dnsdb_open(uschar *filename, uschar **errmsg)
64 {
65 filename = filename;   /* Keep picky compilers happy */
66 errmsg = errmsg;       /* Ditto */
67 return (void *)(-1);   /* Any non-0 value */
68 }
69
70
71
72 /*************************************************
73 *           Find entry point for dnsdb           *
74 *************************************************/
75
76 /* See local README for interface description. */
77
78 int
79 dnsdb_find(void *handle, uschar *filename, uschar *keystring, int length,
80   uschar **result, uschar **errmsg, BOOL *do_cache)
81 {
82 int rc;
83 int size = 256;
84 int ptr = 0;
85 int type = T_TXT;
86 uschar *orig_keystring = keystring;
87 uschar *equals = Ustrchr(keystring, '=');
88 uschar buffer[256];
89
90 /* Because we're the working in the search pool, we try to reclaim as much
91 store as possible later, so we preallocate the result here */
92
93 uschar *yield = store_get(size);
94
95 dns_record *rr;
96 dns_answer dnsa;
97 dns_scan dnss;
98
99 handle = handle;           /* Keep picky compilers happy */
100 filename = filename;
101 length = length;
102 do_cache = do_cache;
103
104 /* If the keystring contains an = this is preceded by a type name. */
105
106 if (equals != NULL)
107   {
108   int i;
109   int len = equals - keystring;
110   for (i = 0; i < sizeof(type_names)/sizeof(uschar *); i++)
111     {
112     if (len == Ustrlen(type_names[i]) &&
113         strncmpic(keystring, US type_names[i], len) == 0)
114       {
115       type = type_values[i];
116       break;
117       }
118     }
119   if (i >= sizeof(type_names)/sizeof(uschar *))
120     {
121     *errmsg = US"unsupported DNS record type";
122     return DEFER;
123     }
124   keystring += len + 1;
125   }
126
127 /* If the type is PTR, we have to construct the relevant magic lookup
128 key. This code is now in a separate function. */
129
130 if (type == T_PTR)
131   {
132   dns_build_reverse(keystring, buffer);
133   keystring = buffer;
134   }
135
136 DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", keystring);
137
138 /* Initialize the resolver, in case this is the first time it is used
139 in this run. Then do the lookup and sort out the result. */
140
141 dns_init(FALSE, FALSE);
142 rc = dns_lookup(&dnsa, keystring, type, NULL);
143
144 if (rc == DNS_NOMATCH || rc == DNS_NODATA) return FAIL;
145 if (rc != DNS_SUCCEED) return DEFER;
146
147 for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
148      rr != NULL;
149      rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
150   {
151   if (rr->type != type) continue;
152
153   /* There may be several addresses from an A6 record. Put newlines between
154   them, just as for between several records. */
155
156   if (type == T_A ||
157       #ifdef SUPPORT_A6
158       type == T_A6 ||
159       #endif
160       type == T_AAAA)
161     {
162     dns_address *da;
163     for (da = dns_address_from_rr(&dnsa, rr); da != NULL; da = da->next)
164       {
165       if (ptr != 0) yield = string_cat(yield, &size, &ptr, US"\n", 1);
166       yield = string_cat(yield, &size, &ptr, da->address, Ustrlen(da->address));
167       }
168     continue;
169     }
170
171   /* Other kinds of record just have one piece of data each. */
172
173   if (ptr != 0) yield = string_cat(yield, &size, &ptr, US"\n", 1);
174
175   if (type == T_TXT)
176     {
177     yield = string_cat(yield, &size, &ptr, (uschar *)(rr->data+1),
178       (rr->data)[0]);
179     }
180   else   /* T_CNAME, T_MX, T_NS, T_PTR */
181     {
182     uschar s[264];
183     uschar *p = (uschar *)(rr->data);
184     if (type == T_MX)
185       {
186       int num;
187       GETSHORT(num, p);            /* pointer is advanced */
188       sprintf(CS s, "%d ", num);
189       yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
190       }
191     else if (type == T_SRV)
192       {
193       int num, weight, port;
194       GETSHORT(num, p);            /* pointer is advanced */
195       GETSHORT(weight, p);
196       GETSHORT(port, p);
197       sprintf(CS s, "%d %d %d ", num, weight, port);
198       yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
199       }
200     rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p,
201       (DN_EXPAND_ARG4_TYPE)(s), sizeof(s));
202
203     /* If an overlong response was received, the data will have been
204     truncated and dn_expand may fail. */
205
206     if (rc < 0)
207       {
208       log_write(0, LOG_MAIN, "host name alias list truncated for %s",
209         orig_keystring);
210       break;
211       }
212     else yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
213     }
214   }
215
216 yield[ptr] = 0;
217 store_reset(yield + ptr + 1);    /* Reclaim unused */
218 *result = yield;
219
220 return OK;
221 }
222
223 /* End of lookups/dnsdb.c */