Start
[exim.git] / src / src / lookups / dnsdb.c
CommitLineData
0756eb3c
PH
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
17header 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
25static 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
40static 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
62void *
63dnsdb_open(uschar *filename, uschar **errmsg)
64{
65filename = filename; /* Keep picky compilers happy */
66errmsg = errmsg; /* Ditto */
67return (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
78int
79dnsdb_find(void *handle, uschar *filename, uschar *keystring, int length,
80 uschar **result, uschar **errmsg, BOOL *do_cache)
81{
82int rc;
83int size = 256;
84int ptr = 0;
85int type = T_TXT;
86uschar *orig_keystring = keystring;
87uschar *equals = Ustrchr(keystring, '=');
88uschar buffer[256];
89
90/* Because we're the working in the search pool, we try to reclaim as much
91store as possible later, so we preallocate the result here */
92
93uschar *yield = store_get(size);
94
95dns_record *rr;
96dns_answer dnsa;
97dns_scan dnss;
98
99handle = handle; /* Keep picky compilers happy */
100filename = filename;
101length = length;
102do_cache = do_cache;
103
104/* If the keystring contains an = this is preceded by a type name. */
105
106if (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
128key. This code is now in a separate function. */
129
130if (type == T_PTR)
131 {
132 dns_build_reverse(keystring, buffer);
133 keystring = buffer;
134 }
135
136DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", keystring);
137
138/* Initialize the resolver, in case this is the first time it is used
139in this run. Then do the lookup and sort out the result. */
140
141dns_init(FALSE, FALSE);
142rc = dns_lookup(&dnsa, keystring, type, NULL);
143
144if (rc == DNS_NOMATCH || rc == DNS_NODATA) return FAIL;
145if (rc != DNS_SUCCEED) return DEFER;
146
147for (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
216yield[ptr] = 0;
217store_reset(yield + ptr + 1); /* Reclaim unused */
218*result = yield;
219
220return OK;
221}
222
223/* End of lookups/dnsdb.c */