aboutsummaryrefslogtreecommitdiff
path: root/lib/dns.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dns.c')
-rw-r--r--lib/dns.c397
1 files changed, 193 insertions, 204 deletions
diff --git a/lib/dns.c b/lib/dns.c
index e23e9ce7..73c23649 100644
--- a/lib/dns.c
+++ b/lib/dns.c
@@ -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
35struct mx_buffer { 36struct 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
242void 245void
243mxbuf_init(struct mxbuf *mxbuf) 246mxbuf_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
288void
289dns_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
299static void
300dns_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
278struct loop_data { 326struct 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->