Implement the pseudo dns lookup type "zns" for ${dnsdb lookups.
[exim.git] / src / src / lookups / dnsdb.c
CommitLineData
33397d19 1/* $Cambridge: exim/src/src/lookups/dnsdb.c,v 1.2 2004/11/19 09:45:54 ph10 Exp $ */
0756eb3c
PH
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",
33397d19
PH
38 "txt",
39 "zns"
40};
0756eb3c
PH
41
42static int type_values[] = {
43 T_A,
44#if HAVE_IPV6
45 T_AAAA,
46 #ifdef SUPPORT_A6
47 T_A6,
48 #endif
49#endif
50 T_CNAME,
51 T_MX,
52 T_NS,
53 T_PTR,
54 T_SRV,
33397d19
PH
55 T_TXT,
56 T_ZNS /* Private type for "zone nameservers" */
57};
0756eb3c
PH
58
59
60/*************************************************
61* Open entry point *
62*************************************************/
63
64/* See local README for interface description. */
65
66void *
67dnsdb_open(uschar *filename, uschar **errmsg)
68{
69filename = filename; /* Keep picky compilers happy */
70errmsg = errmsg; /* Ditto */
71return (void *)(-1); /* Any non-0 value */
72}
73
74
75
76/*************************************************
77* Find entry point for dnsdb *
78*************************************************/
79
80/* See local README for interface description. */
81
82int
83dnsdb_find(void *handle, uschar *filename, uschar *keystring, int length,
84 uschar **result, uschar **errmsg, BOOL *do_cache)
85{
86int rc;
87int size = 256;
88int ptr = 0;
89int type = T_TXT;
90uschar *orig_keystring = keystring;
91uschar *equals = Ustrchr(keystring, '=');
92uschar buffer[256];
93
94/* Because we're the working in the search pool, we try to reclaim as much
95store as possible later, so we preallocate the result here */
96
97uschar *yield = store_get(size);
98
99dns_record *rr;
100dns_answer dnsa;
101dns_scan dnss;
102
103handle = handle; /* Keep picky compilers happy */
104filename = filename;
105length = length;
106do_cache = do_cache;
107
108/* If the keystring contains an = this is preceded by a type name. */
109
110if (equals != NULL)
111 {
112 int i;
113 int len = equals - keystring;
114 for (i = 0; i < sizeof(type_names)/sizeof(uschar *); i++)
115 {
116 if (len == Ustrlen(type_names[i]) &&
117 strncmpic(keystring, US type_names[i], len) == 0)
118 {
119 type = type_values[i];
120 break;
121 }
122 }
123 if (i >= sizeof(type_names)/sizeof(uschar *))
124 {
125 *errmsg = US"unsupported DNS record type";
126 return DEFER;
127 }
128 keystring += len + 1;
129 }
130
131/* If the type is PTR, we have to construct the relevant magic lookup
132key. This code is now in a separate function. */
133
134if (type == T_PTR)
135 {
136 dns_build_reverse(keystring, buffer);
137 keystring = buffer;
138 }
139
140DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", keystring);
141
142/* Initialize the resolver, in case this is the first time it is used
143in this run. Then do the lookup and sort out the result. */
144
145dns_init(FALSE, FALSE);
33397d19 146rc = dns_special_lookup(&dnsa, keystring, type, NULL);
0756eb3c
PH
147
148if (rc == DNS_NOMATCH || rc == DNS_NODATA) return FAIL;
149if (rc != DNS_SUCCEED) return DEFER;
150
33397d19
PH
151/* If the lookup was a pseudo-type, change it to the correct type for searching
152the returned records; then search for them. */
153
154if (type == T_ZNS) type = T_NS;
0756eb3c
PH
155for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
156 rr != NULL;
157 rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
158 {
159 if (rr->type != type) continue;
160
161 /* There may be several addresses from an A6 record. Put newlines between
162 them, just as for between several records. */
163
164 if (type == T_A ||
165 #ifdef SUPPORT_A6
166 type == T_A6 ||
167 #endif
168 type == T_AAAA)
169 {
170 dns_address *da;
171 for (da = dns_address_from_rr(&dnsa, rr); da != NULL; da = da->next)
172 {
173 if (ptr != 0) yield = string_cat(yield, &size, &ptr, US"\n", 1);
174 yield = string_cat(yield, &size, &ptr, da->address, Ustrlen(da->address));
175 }
176 continue;
177 }
178
179 /* Other kinds of record just have one piece of data each. */
180
181 if (ptr != 0) yield = string_cat(yield, &size, &ptr, US"\n", 1);
182
183 if (type == T_TXT)
184 {
185 yield = string_cat(yield, &size, &ptr, (uschar *)(rr->data+1),
186 (rr->data)[0]);
187 }
188 else /* T_CNAME, T_MX, T_NS, T_PTR */
189 {
190 uschar s[264];
191 uschar *p = (uschar *)(rr->data);
192 if (type == T_MX)
193 {
194 int num;
195 GETSHORT(num, p); /* pointer is advanced */
196 sprintf(CS s, "%d ", num);
197 yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
198 }
199 else if (type == T_SRV)
200 {
201 int num, weight, port;
202 GETSHORT(num, p); /* pointer is advanced */
203 GETSHORT(weight, p);
204 GETSHORT(port, p);
205 sprintf(CS s, "%d %d %d ", num, weight, port);
206 yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
207 }
208 rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p,
209 (DN_EXPAND_ARG4_TYPE)(s), sizeof(s));
210
211 /* If an overlong response was received, the data will have been
212 truncated and dn_expand may fail. */
213
214 if (rc < 0)
215 {
216 log_write(0, LOG_MAIN, "host name alias list truncated for %s",
217 orig_keystring);
218 break;
219 }
220 else yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
221 }
222 }
223
224yield[ptr] = 0;
225store_reset(yield + ptr + 1); /* Reclaim unused */
226*result = yield;
227
228return OK;
229}
230
231/* End of lookups/dnsdb.c */