diff options
Diffstat (limited to 'lib/dns.c')
-rw-r--r-- | lib/dns.c | 397 |
1 files changed, 193 insertions, 204 deletions
@@ -31,6 +31,7 @@ | |||
31 | #include "libmf.h" | 31 | #include "libmf.h" |
32 | #include "dns.h" | 32 | #include "dns.h" |
33 | #include "mailutils/alloc.h" | 33 | #include "mailutils/alloc.h" |
34 | #include "mailutils/argcv.h" | ||
34 | 35 | ||
35 | struct mx_buffer { | 36 | struct mx_buffer { |
36 | unsigned pref; | 37 | unsigned pref; |
@@ -70,8 +71,10 @@ static dns_status | |||
70 | _getmx(const char *host, unsigned char *answer, size_t answer_size, | 71 | _getmx(const char *host, unsigned char *answer, size_t answer_size, |
71 | struct mxbuf *mxbuf, unsigned long *pttl) | 72 | struct mxbuf *mxbuf, unsigned long *pttl) |
72 | { | 73 | { |
73 | int i, n, nmx; | 74 | struct mx_buffer *mx_buffer = NULL; |
74 | struct mx_buffer mx_buffer[MAXMXCOUNT]; | 75 | size_t mx_max = 0; |
76 | size_t nmx = 0; | ||
77 | int i, n; | ||
75 | HEADER *hp; | 78 | HEADER *hp; |
76 | unsigned char *eom, *cp; | 79 | unsigned char *eom, *cp; |
77 | unsigned short qdcount, ancount; | 80 | unsigned short qdcount, ancount; |
@@ -149,23 +152,28 @@ _getmx(const char *host, unsigned char *answer, size_t answer_size, | |||
149 | tname, sizeof tname)) < 0) | 152 | tname, sizeof tname)) < 0) |
150 | break; | 153 | break; |
151 | cp += n; | 154 | cp += n; |
155 | if (nmx == mx_max) | ||
156 | mx_buffer = mu_2nrealloc(mx_buffer, | ||
157 | &mx_max, | ||
158 | sizeof(mx_buffer[0])); | ||
159 | |||
152 | mx_buffer[nmx].pref = pref; | 160 | mx_buffer[nmx].pref = pref; |
153 | mx_buffer[nmx].name = strdup(tname); | 161 | mx_buffer[nmx].name = mu_strdup(tname); |
154 | mu_debug(debug_handle, MU_DEBUG_TRACE2, | 162 | mu_debug(debug_handle, MU_DEBUG_TRACE2, |
155 | ("MX %u %s", mx_buffer[nmx].pref, | 163 | ("MX %u %s", mx_buffer[nmx].pref, |
156 | mx_buffer[nmx].name)); | 164 | mx_buffer[nmx].name)); |
157 | if (++nmx >= mxbuf->mx_max) | 165 | nmx++; |
158 | break; | ||
159 | } | 166 | } |
160 | 167 | ||
161 | /* Sort according to preference value */ | 168 | /* Sort according to preference value */ |
162 | qsort(mx_buffer, nmx, sizeof mx_buffer[0], comp_pref); | 169 | qsort(mx_buffer, nmx, sizeof mx_buffer[0], comp_pref); |
163 | 170 | ||
164 | /* Prepare return value */ | 171 | /* Prepare return value */ |
165 | mxbuf_init(mxbuf); | 172 | mxbuf_init(mxbuf, nmx); |
166 | for (i = 0; i < nmx; i++) | 173 | for (i = 0; i < nmx; i++) |
167 | mxbuf->mx_buf[i] = mx_buffer[i].name; | 174 | mxbuf->mx_buf[i] = mx_buffer[i].name; |
168 | mxbuf->mx_cnt = nmx; | 175 | mxbuf->mx_cnt = i; |
176 | free(mx_buffer); | ||
169 | return dns_success; | 177 | return dns_success; |
170 | } | 178 | } |
171 | 179 | ||
@@ -211,28 +219,23 @@ dns_get_mx_records(const char *host, int maxdepth, struct mxbuf *mxbuf, | |||
211 | } | 219 | } |
212 | 220 | ||
213 | if (host) { | 221 | if (host) { |
214 | unsigned char *answer = malloc(MAXPACKET); | 222 | unsigned char *answer = mu_alloc(MAXPACKET); |
215 | if (!answer) | 223 | const char *p; |
216 | status = dns_failure; | 224 | int depth; |
217 | else { | ||
218 | const char *p; | ||
219 | int depth; | ||
220 | 225 | ||
221 | for (p = host, depth = 0; p && depth < maxdepth; | 226 | for (p = host, depth = 0; p && depth < maxdepth; |
222 | p++, depth++) { | 227 | p++, depth++) { |
223 | if (ttl) | 228 | if (ttl) |
224 | *ttl = ~(unsigned long)0; | 229 | *ttl = ~(unsigned long)0; |
225 | status = _getmx(p, answer, MAXPACKET, mxbuf, | 230 | status = _getmx(p, answer, MAXPACKET, mxbuf, ttl); |
226 | ttl); | 231 | if (status == dns_success |
227 | if (status == dns_success | 232 | || status == dns_temp_failure) |
228 | || status == dns_temp_failure) | 233 | break; |
229 | break; | 234 | p = strchr(p, '.'); |
230 | p = strchr(p, '.'); | 235 | if (!p) |
231 | if (!p) | 236 | break; |
232 | break; | ||
233 | } | ||
234 | free(answer); | ||
235 | } | 237 | } |
238 | free(answer); | ||
236 | } | 239 | } |
237 | MUTEX_UNLOCK(dns_mutex); | 240 | MUTEX_UNLOCK(dns_mutex); |
238 | free(hbuf); | 241 | free(hbuf); |
@@ -240,20 +243,24 @@ dns_get_mx_records(const char *host, int maxdepth, struct mxbuf *mxbuf, | |||
240 | } | 243 | } |
241 | 244 | ||
242 | void | 245 | void |
243 | mxbuf_init(struct mxbuf *mxbuf) | 246 | mxbuf_init(struct mxbuf *mxbuf, size_t nmx) |
244 | { | 247 | { |
245 | if (!(mxbuf->mx_flags & MXF_MAX)) | ||
246 | mxbuf->mx_max = MAXMXCOUNT; | ||
247 | if (mxbuf->mx_flags & MXF_REUSE) { | 248 | if (mxbuf->mx_flags & MXF_REUSE) { |
248 | int i; | 249 | size_t i; |
249 | 250 | ||
250 | for (i = 0; i < mxbuf->mx_max && mxbuf->mx_buf[i]; i++) { | 251 | for (i = 0; i < mxbuf->mx_cnt; i++) { |
251 | free(mxbuf->mx_buf[i]); | 252 | free(mxbuf->mx_buf[i]); |
252 | mxbuf->mx_buf[i] = NULL; | 253 | mxbuf->mx_buf[i] = NULL; |
253 | } | 254 | } |
255 | if (nmx > mxbuf->mx_max) { | ||
256 | mxbuf->mx_buf = | ||
257 | mu_realloc(mxbuf->mx_buf, | ||
258 | nmx * sizeof(mxbuf->mx_buf[0])); | ||
259 | mxbuf->mx_max = nmx; | ||
260 | } | ||
254 | } else { | 261 | } else { |
255 | mxbuf->mx_buf = mu_calloc(mxbuf->mx_max, | 262 | mxbuf->mx_buf = mu_calloc(nmx, sizeof(mxbuf->mx_buf[0])); |
256 | sizeof(mxbuf->mx_buf[0])); | 263 | mxbuf->mx_max = nmx; |
257 | mxbuf->mx_flags |= MXF_REUSE; | 264 | mxbuf->mx_flags |= MXF_REUSE; |
258 | } | 265 | } |
259 | mxbuf->mx_cnt = 0; | 266 | mxbuf->mx_cnt = 0; |
@@ -267,7 +274,10 @@ mxbuf_free(struct mxbuf *mxbuf) | |||
267 | 274 | ||
268 | for (i = 0; i < mxbuf->mx_max && mxbuf->mx_buf[i]; i++) | 275 | for (i = 0; i < mxbuf->mx_max && mxbuf->mx_buf[i]; i++) |
269 | free(mxbuf->mx_buf[i]); | 276 | free(mxbuf->mx_buf[i]); |
277 | free(mxbuf->mx_buf); | ||
270 | mxbuf->mx_buf = NULL; | 278 | mxbuf->mx_buf = NULL; |
279 | mxbuf->mx_flags &= ~MXF_REUSE; | ||
280 | mxbuf->mx_cnt = mxbuf->mx_max = 0; | ||
271 | } | 281 | } |
272 | } | 282 | } |
273 | 283 | ||
@@ -275,6 +285,44 @@ mxbuf_free(struct mxbuf *mxbuf) | |||
275 | #define LOOKUP_SUCCESS 0 | 285 | #define LOOKUP_SUCCESS 0 |
276 | #define LOOKUP_CNAME 1 | 286 | #define LOOKUP_CNAME 1 |
277 | 287 | ||
288 | void | ||
289 | dns_reply_free(struct dns_reply *r) | ||
290 | { | ||
291 | if (r->base) { | ||
292 | size_t i; | ||
293 | for (i = 0; i < r->count; i++) | ||
294 | free(r->base[i]); | ||
295 | free(r->base); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | static void | ||
300 | dns_reply_append(struct dns_reply *r, void *ptr, size_t len, int last) | ||
301 | { | ||
302 | if (r->count == r->max) | ||
303 | r->base = mu_2nrealloc(r->base, | ||
304 | &r->max, | ||
305 | sizeof(r->base[0])); | ||
306 | if (last && r->count) { | ||
307 | while (r->last_len + len > r->last_max) | ||
308 | r->base[r->count-1] = | ||
309 | mu_2nrealloc(r->base[r->count-1], | ||
310 | &r->last_max, | ||
311 | 1); | ||
312 | } else if (ptr == NULL) { | ||
313 | r->base[r->count] = NULL; | ||
314 | return; | ||
315 | } else { | ||
316 | r->base[r->count] = mu_alloc(len); | ||
317 | r->count++; | ||
318 | r->last_len = 0; | ||
319 | r->last_max = len; | ||
320 | } | ||
321 | |||
322 | memcpy((char*)r->base[r->count-1] + r->last_len, ptr, len); | ||
323 | r->last_len += len; | ||
324 | } | ||
325 | |||
278 | struct loop_data { | 326 | struct loop_data { |
279 | int qtype; /* Type of the query */ | 327 | int qtype; /* Type of the query */ |
280 | char *name; /* Key to look up */ | 328 | char *name; /* Key to look up */ |
@@ -285,9 +333,7 @@ struct loop_data { | |||
285 | size_t answer_size; /* Size of answer buffer */ | 333 | size_t answer_size; /* Size of answer buffer */ |
286 | 334 | ||
287 | /* Return data: */ | 335 | /* Return data: */ |
288 | char *hbuf; /* Return buffer */ | 336 | struct dns_reply repl; |
289 | size_t hbsize; /* Size of return buffer */ | ||
290 | size_t hbcount; /* Number of items returned */ | ||
291 | 337 | ||
292 | time_t ttl; /* TTL value */ | 338 | time_t ttl; /* TTL value */ |
293 | dns_status status; /* Status */ | 339 | dns_status status; /* Status */ |
@@ -431,20 +477,11 @@ cname_loop_body(struct loop_data *lp) | |||
431 | if (bp + n >= nbuf + blen) { | 477 | if (bp + n >= nbuf + blen) { |
432 | mu_debug(debug_handle, MU_DEBUG_TRACE0, | 478 | mu_debug(debug_handle, MU_DEBUG_TRACE0, |
433 | ("size (%d) too big", n)); | 479 | ("size (%d) too big", n)); |
480 | } else if (n != sizeof(GACOPYZ_UINT32_T)) { | ||
481 | mu_debug(debug_handle, MU_DEBUG_TRACE0, | ||
482 | ("unsupported address size: %d", n)); | ||
434 | } else { | 483 | } else { |
435 | if (n != sizeof(GACOPYZ_UINT32_T)) { | 484 | dns_reply_append(&lp->repl, cp, n, 0); |
436 | mu_debug(debug_handle, MU_DEBUG_TRACE0, | ||
437 | ("unsupported address size: %d", | ||
438 | n)); | ||
439 | } else if (lp->hbcount * sizeof(GACOPYZ_UINT32_T) >= lp-> |