Commit | Line | Data |
---|---|---|
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 | |
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 */ |