14fdc5a2e5dc1b2da0bcd4447e2610f0dc2dcbc9
[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 */