Commit | Line | Data |
---|---|---|
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 | |
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", | |
33397d19 PH |
38 | "txt", |
39 | "zns" | |
40 | }; | |
0756eb3c PH |
41 | |
42 | static 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 | ||
66 | void * | |
67 | dnsdb_open(uschar *filename, uschar **errmsg) | |
68 | { | |
69 | filename = filename; /* Keep picky compilers happy */ | |
70 | errmsg = errmsg; /* Ditto */ | |
71 | return (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 | ||
82 | int | |
83 | dnsdb_find(void *handle, uschar *filename, uschar *keystring, int length, | |
84 | uschar **result, uschar **errmsg, BOOL *do_cache) | |
85 | { | |
86 | int rc; | |
87 | int size = 256; | |
88 | int ptr = 0; | |
89 | int type = T_TXT; | |
90 | uschar *orig_keystring = keystring; | |
91 | uschar *equals = Ustrchr(keystring, '='); | |
92 | uschar buffer[256]; | |
93 | ||
94 | /* Because we're the working in the search pool, we try to reclaim as much | |
95 | store as possible later, so we preallocate the result here */ | |
96 | ||
97 | uschar *yield = store_get(size); | |
98 | ||
99 | dns_record *rr; | |
100 | dns_answer dnsa; | |
101 | dns_scan dnss; | |
102 | ||
103 | handle = handle; /* Keep picky compilers happy */ | |
104 | filename = filename; | |
105 | length = length; | |
106 | do_cache = do_cache; | |
107 | ||
108 | /* If the keystring contains an = this is preceded by a type name. */ | |
109 | ||
110 | if (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 | |
132 | key. This code is now in a separate function. */ | |
133 | ||
134 | if (type == T_PTR) | |
135 | { | |
136 | dns_build_reverse(keystring, buffer); | |
137 | keystring = buffer; | |
138 | } | |
139 | ||
140 | DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", keystring); | |
141 | ||
142 | /* Initialize the resolver, in case this is the first time it is used | |
143 | in this run. Then do the lookup and sort out the result. */ | |
144 | ||
145 | dns_init(FALSE, FALSE); | |
33397d19 | 146 | rc = dns_special_lookup(&dnsa, keystring, type, NULL); |
0756eb3c PH |
147 | |
148 | if (rc == DNS_NOMATCH || rc == DNS_NODATA) return FAIL; | |
149 | if (rc != DNS_SUCCEED) return DEFER; | |
150 | ||
33397d19 PH |
151 | /* If the lookup was a pseudo-type, change it to the correct type for searching |
152 | the returned records; then search for them. */ | |
153 | ||
154 | if (type == T_ZNS) type = T_NS; | |
0756eb3c PH |
155 | for (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 | ||
224 | yield[ptr] = 0; | |
225 | store_reset(yield + ptr + 1); /* Reclaim unused */ | |
226 | *result = yield; | |
227 | ||
228 | return OK; | |
229 | } | |
230 | ||
231 | /* End of lookups/dnsdb.c */ |