1 #include "opendmarc_internal.h"
2
3 /* libbsd if found */
4 #ifdef USE_BSD_H
5 # include <bsd/string.h>
6 #endif /* USE_BSD_H */
7
8 /* libstrl if needed */
9 #ifdef USE_STRL_H
10 # include <strl.h>
11 #endif /* USE_STRL_H */
12
13 /* opendmarc_strl if needed */
14 #ifdef USE_DMARCSTRL_H
15 # include <opendmarc_strl.h>
16 #endif /* USE_DMARCSTRL_H */
17
18 #include <netdb.h>
19
20 #include "dmarc.h"
21
22 #if WITH_SPF && ! HAVE_SPF2_H
23 /*
24 ** Beware that some Linux versions incorrectly define
25 ** MAXHOSTNAMELEN as 64, but DNS lookups require a length
26 ** of 255. So we don't use MAXHOSTNAMELEN here.
27 */
28 #define MAXDNSHOSTNAME 256
29 #ifndef MAXPACKET
30 # define MAXPACKET (8192)
31 #endif
32 #ifndef T_SPF
33 # define T_SPF (99)
34 #endif
35
36 /***************************************************************************************************
37 ** opendmarc_spf_dns_lookup_a_actual -- Looks type of address that is sought
38 **
39 ** Arguments:
40 ** domain -- the domain name to look up.
41 ** sought -- type of lookup A or AAAA
42 ** ary -- array of strings containing list of IP addresses
43 ** cnt -- Pointer to count of lines in array
44 ** Returns:
45 ** ary -- on success
46 ** NULL -- otherise, and place the h_errno error into reply
47 ** Side Effects:
48 ** Makes a connection to the local name server and blocks
49 ** waiting for a reply.
50 ***************************************************************************************************/
51
52 char **
opendmarc_spf_dns_lookup_a_actual(char * domain,int sought,char ** ary,int * cnt)53 opendmarc_spf_dns_lookup_a_actual(char *domain, int sought, char **ary, int *cnt)
54 {
55 char * bp;
56 u_char * cp;
57 u_char * eom = NULL;
58 char hbuf[MAXDNSHOSTNAME];
59 char namebuf[MAXDNSHOSTNAME + 1];
60 u_char a_buf[MAXPACKET];
61 struct in_addr in;
62 uint32_t a;
63 HEADER hdr;
64 int k;
65 short l = 0;
66 int class = -1;
67 int acnt = -1;
68 int qdcnt = -1;
69 u_short type = 0;
70 u_long ttl = 0;
71 #if HAVE_RES_NINIT
72 struct __res_state resp;
73 #endif /* HAVE_RES_NINIT */
74
75 /*
76 * If a null or empy domain was given to us, just say it
77 * was not found.
78 */
79 if (domain == NULL || *domain == '\0')
80 {
81 return NULL;
82 }
83
84 #ifdef HAVE_RES_NINIT
85 memset(&resp, '\0', sizeof resp);
86 res_ninit(&resp);
87 #endif /* HAVE_RES_NINIT */
88 /*
89 * Copy the domain so we can scribble on it. The orginal
90 * may point to a static string.
91 */
92 (void) memcpy(hbuf, domain, sizeof hbuf);
93 bp = hbuf;
94
95 /*
96 * Make sure host ends in a dot to short circuit lookups
97 */
98 bp = hbuf + strlen(hbuf) - 1;
99 if (*bp != '.')
100 *++bp = '.';
101 *++bp = '\0';
102 /*
103 * Make sure host does not begin with a dot.
104 */
105 bp = hbuf;
106 if (*bp == '.')
107 ++bp;
108
109 #ifdef HAVE_RES_NINIT
110 k = res_nquery(&resp, bp, C_IN, sought, a_buf, sizeof a_buf);
111 #ifdef HAVE_RES_NDESTROY
112 res_ndestroy(&resp);
113 #else
114 res_nclose(&resp);
115 #endif
116 #else /* HAVE_RES_NINIT */
117 k = res_query(bp, C_IN, sought, a_buf, sizeof a_buf);
118 #endif /* HAVE_RES_NINIT */
119 if (k < 0)
120 {
121 return NULL;
122 }
123 if (k > (int)(sizeof a_buf))
124 {
125 k = sizeof a_buf;
126 }
127 (void) memcpy(&hdr, a_buf, sizeof hdr);
128 cp = (u_char *)&a_buf + HFIXEDSZ;
129 eom = (u_char *)&a_buf + k;
130
131 (void) memset(namebuf, '\0', sizeof namebuf);
132 /* skip question part of response -- we know what we asked */
133 for (qdcnt = ntohs(hdr.qdcount); qdcnt > 0; qdcnt--)
134 {
135 k = dn_expand((unsigned char *) &a_buf, eom, cp, namebuf, sizeof namebuf);
136 cp += k;
137 if (cp + INT16SZ + INT16SZ > eom)
138 {
139 return NULL;
140 }
141 GETSHORT(type, cp);
142 GETSHORT(class, cp);
143 }
144 if (hdr.rcode != NOERROR)
145 {
146 return NULL;
147 }
148 acnt = ntohs((unsigned short) hdr.ancount);
149 if (acnt == 0)
150 {
151 return NULL;
152 }
153 while (--acnt >= 0 && cp < eom)
154 {
155 if ((k = dn_expand((unsigned char *) &a_buf, eom, cp,
156 namebuf, sizeof namebuf)) < 0)
157 {
158 break;
159 }
160 cp += k;
161
162 GETSHORT(type, cp);
163 GETSHORT(class, cp);
164 GETLONG(ttl, cp);
165 GETSHORT(l, cp);
166 if (type == T_CNAME)
167 {
168 /* CNAME; walk past the expanded name and continue */
169 char cname[MAXDNSHOSTNAME + 1];
170
171 k = dn_expand((u_char *) &a_buf, eom, cp,
172 cname, MAXDNSHOSTNAME);
173 cp += k;
174 continue;
175 }
176 else if (type != sought)
177 {
178 /* not a type we want; skip the rest and continue */
179 cp += l;
180 continue;
181 }
182 else if (type == T_A)
183 {
184 GETLONG(a, cp);
185 a = htonl(a);
186 (void) memcpy(&in.s_addr, &a, sizeof(uint32_t));
187 (void) memset(hbuf, '\0', sizeof hbuf);
188 (void) strncpy(hbuf, inet_ntoa(in), sizeof hbuf);
189 ary = opendmarc_util_pushnargv(hbuf, ary, cnt);
190 }
191 #ifdef T_AAAA
192 else if (type == T_AAAA)
193 {
194 struct in6_addr s6;
195
196 /* just to be sure... */
197 if (l != sizeof s6.s6_addr)
198 {
199 cp += l;
200 continue;
201 }
202
203 (void) memcpy(&s6.s6_addr, cp, sizeof s6.s6_addr);
204 (void) memset(hbuf, '\0', sizeof hbuf);
205 inet_ntop(AF_INET6, &s6.s6_addr, hbuf, sizeof hbuf - 1);
206 ary = opendmarc_util_pushnargv(hbuf, ary, cnt);
207 }
208 #endif /* T_AAAA */
209 }
210 return ary;
211 }
212
213 /***************************************************************************************************
214 ** opendmarc_spf_dns_lookup_a -- Looks up the IPv4 and IPv6 addresses of the domain
215 **
216 ** Arguments:
217 ** domain -- the domain name to look up.
218 ** ary -- array of strings containing list of IP addresses
219 ** cnt -- Pointer to count of lines in array
220 ** Returns:
221 ** ary -- on success
222 ** NULL -- otherwise, and place the h_errno error into reply
223 ** Side Effects:
224 ** Makes a connection to the local name server and blocks
225 ** waiting for a reply.
226 ***************************************************************************************************/
227 char **
opendmarc_spf_dns_lookup_a(char * domain,char ** ary,int * cnt)228 opendmarc_spf_dns_lookup_a(char *domain, char **ary, int *cnt)
229 {
230 bool found = FALSE;
231 char **a_retp;
232 char **aaaa_retp;
233
234 a_retp = opendmarc_spf_dns_lookup_a_actual(domain, T_A, ary, cnt);
235 if (a_retp != (char **) NULL)
236 {
237 ary = a_retp;
238 found = TRUE;
239 }
240
241 #ifdef T_AAAA
242 aaaa_retp = opendmarc_spf_dns_lookup_a_actual(domain, T_AAAA, ary, cnt);
243 if (aaaa_retp != (char **) NULL)
244 {
245 ary = aaaa_retp;
246 found = TRUE;
247 }
248 #endif /* T_AAAA */
249
250 return *cnt > 0 ? ary : NULL;
251 }
252
253 /***************************************************************************************************
254 ** opendmarc_spf_dns_lookup_mx -- Looks up the MX records for a domain
255 **
256 ** Arguments:
257 ** domain -- The domain name to look up.
258 ** ary -- Array of strings containing list MX hosts
259 ## Note that spf only cares if they exist.
260 ** cnt -- Pointer to count of lines in array
261 ** Returns:
262 ** ary -- on success
263 ** NULL -- otherise, and place the h_errno error into reply
264 ** Side Effects:
265 ** Makes a connection to the local name server and blocks
266 ** waiting for a reply.
267 ***************************************************************************************************/
268 char **
opendmarc_spf_dns_lookup_mx(char * domain,char ** ary,int * cnt)269 opendmarc_spf_dns_lookup_mx(char *domain, char **ary, int *cnt)
270 {
271 register u_char *eob, *cp;
272 register int k;
273 u_char buf[BUFSIZ];
274 HEADER *hp;
275 union {
276 HEADER h;
277 u_char u[PACKETSZ];
278 } q;
279 int acnt, qdcnt;
280 u_short pref;
281 u_short type;
282 u_long ttl;
283 #if HAVE_RES_NINIT
284 struct __res_state resp;
285 #endif /* HAVE_RES_NINIT */
286
287 if (domain == NULL)
288 {
289 return NULL;
290 }
291
292 #ifdef HAVE_RES_NINIT
293 memset(&resp, '\0', sizeof resp);
294 res_ninit(&resp);
295 k = res_nquery(&resp, domain, C_IN, T_MX, (u_char *) &q, sizeof(q));
296 #ifdef HAVE_RES_NDESTROY
297 res_ndestroy(&resp);
298 #else
299 res_nclose(&resp);
300 #endif
301 #else /* HAVE_RES_NINIT */
302 k = res_query(domain, C_IN, T_MX, (u_char *) &q, sizeof(q));
303 #endif /* HAVE_RES_NINIT */
304
305 if (k < 0)
306 {
307 return NULL;
308 }
309 hp = &(q.h);
310 cp = q.u + HFIXEDSZ;
311 eob = q.u + k;
312
313 for (qdcnt = ntohs(hp->qdcount); qdcnt--; cp += k + QFIXEDSZ)
314 if ((k = dn_skipname(cp, eob)) < 0)
315 {
316 return NULL;
317 }
318
319 acnt = ntohs(hp->ancount);
320 while (--acnt >= 0 && cp < eob)
321 {
322 if ((k = dn_expand(q.u, eob, cp, (char *)buf, BUFSIZ-1)) < 0)
323 break;
324 cp += k;
325 if (cp > eob)
326 break;
327 GETSHORT(type, cp);
328 cp += INT16SZ;
329 GETLONG(ttl, cp);
330 GETSHORT(k, cp);
331 if (type != T_MX)
332 {
333 cp += k;
334 continue;
335 }
336 GETSHORT(pref, cp);
337 if ((k = dn_expand(q.u, eob, cp, (char *)buf, BUFSIZ-1)) < 0)
338 break;
339 cp += k;
340 ary = opendmarc_spf_dns_lookup_a((char *)buf, ary, cnt);
341 }
342 return ary;
343 }
344
345 /***************************************************************************************************
346 ** opendmarc_spf_dns_lookup_ptr -- Looks up IP address to get domain
347 **
348 ** Arguments:
349 ** domain -- The domain name to look up.
350 ** ary -- Array of strings containing list MX hosts
351 ## Note that spf only cares if they exist.
352 ** cnt -- Pointer to count of lines in array
353 ** Returns:
354 ** ary -- on success
355 ** NULL -- otherise, and place the h_errno error into reply
356 ** Side Effects:
357 ** Makes a connection to the local name server and blocks
358 ** waiting for a reply.
359 ***************************************************************************************************/
360 char **
opendmarc_spf_dns_lookup_ptr(char * ip,char ** ary,int * cnt)361 opendmarc_spf_dns_lookup_ptr(char *ip, char **ary, int *cnt)
362 {
363 register u_char *eob, *cp;
364 register int k;
365 u_char buf[BUFSIZ];
366 char ip_buf[512];
367 HEADER *hp;
368 union {
369 HEADER h;
370 u_char u[PACKETSZ];
371 } q;
372 int acnt, qdcnt;
373 u_short type;
374 u_long ttl;
375 char *icp;
376 #if HAVE_RES_NINIT
377 struct __res_state resp;
378 #endif /* HAVE_RES_NINIT */
379
380 if (ip == NULL)
381 {
382 return NULL;
383 }
384 (void) memset(buf, '\0', sizeof buf);
385 (void) memset(ip_buf, '\0', sizeof ip_buf);
386 (void) strlcpy(ip_buf, ip, sizeof ip_buf);
387 icp = strrchr(ip_buf, '.');
388 if (icp == NULL)
389 return NULL;
390 strlcpy((char *)buf, icp+1, sizeof buf);
391 *icp = '\0';
392 icp = strrchr(ip_buf, '.');
393 if (icp == NULL)
394 return NULL;
395 strlcat((char *)buf, ".", sizeof buf);
396 strlcat((char *)buf, icp+1, sizeof buf);
397 *icp = '\0';
398 icp = strrchr(ip_buf, '.');
399 if (icp == NULL)
400 return NULL;
401 strlcat((char *)buf, ".", sizeof buf);
402 strlcat((char *)buf, icp+1, sizeof buf);
403 *icp = '\0';
404 icp = ip_buf;
405 strlcat((char *)buf, ".", sizeof buf);
406 strlcat((char *)buf, icp, sizeof buf);
407 strlcat((char *)buf, ".in-addr.arpa.", sizeof buf);
408
409 #ifdef HAVE_RES_NINIT
410 memset(&resp, '\0', sizeof resp);
411 res_ninit(&resp);
412 k = res_nquery(&resp, (char *)buf, C_IN, T_PTR, (u_char *) &q, sizeof(q));
413 #ifdef HAVE_RES_NDESTROY
414 res_ndestroy(&resp);
415 #else
416 res_nclose(&resp);
417 #endif
418 #else /* HAVE_RES_NINIT */
419 k = res_query((char *)buf, C_IN, T_PTR, (u_char *) &q, sizeof(q));
420 #endif /* HAVE_RES_NINIT */
421
422 if (k < 0)
423 {
424 return NULL;
425 }
426 hp = &(q.h);
427 cp = q.u + HFIXEDSZ;
428 eob = q.u + k;
429
430 for (qdcnt = ntohs(hp->qdcount); qdcnt--; cp += k + QFIXEDSZ)
431 {
432 if ((k = dn_skipname(cp, eob)) < 0)
433 {
434 return NULL;
435 }
436 }
437
438 acnt = ntohs(hp->ancount);
439 while (--acnt >= 0 && cp < eob)
440 {
441 char ptr[MAXDNSHOSTNAME + 1];
442
443 if ((k = dn_expand(q.u, eob, cp, (char *)buf, BUFSIZ-1)) < 0)
444 break;
445 cp += k;
446 if (cp > eob)
447 break;
448 GETSHORT(type, cp);
449 cp += INT16SZ;
450 GETLONG(ttl, cp);
451 GETSHORT(k, cp);
452
453 k = dn_expand(q.u, eob, cp, ptr, MAXDNSHOSTNAME);
454 ary = opendmarc_util_pushnargv(ptr, ary, cnt);
455 cp += k;
456 continue;
457 }
458 return ary;
459 }
460
461 /***************************************************************
462 ** opendmarc_spf_dns_does_domain_exist -- does an a, aaaa, or mx record exist?
463 **
464 ** Arguments:
465 ** domain -- the domain name to look up.
466 ** reply -- pointer to an integer
467 **
468 ** Returns:
469 ** TRUE -- if any of those records existed.
470 ** FALSE -- otherise, and place the h_errno error
471 ** into reply
472 **
473 ** Side Effects:
474 ** Makes a connection to the local name server and bloks
475 ** waiting for a reply.
476 ***************************************************************/
477 int
opendmarc_spf_dns_does_domain_exist(char * domain,int * reply)478 opendmarc_spf_dns_does_domain_exist(char *domain, int *reply)
479 {
480 HEADER hdr;
481 u_char a_q[MAXPACKET];
482 u_char aaaa_q[MAXPACKET];
483 u_char mx_q[MAXPACKET];
484 int r;
485 int * rp;
486 #if HAVE_RES_NINIT
487 struct __res_state resp;
488 #endif /* HAVE_RES_NINIT */
489
490 if (reply == NULL)
491 rp = &r;
492 else
493 rp = reply;
494
495 if (domain == NULL || *domain == '\0')
496 {
497 *rp = HOST_NOT_FOUND;
498 return FALSE;
499 }
500
501 /*
502 * Make sure the domain exists.
503 */
504 #ifdef HAVE_RES_NINIT
505 memset(&resp, '\0', sizeof resp);
506 res_ninit(&resp);
507 (void) res_nquery(&resp, domain, C_IN, T_A, a_q, sizeof a_q);
508 #ifdef T_AAAA
509 (void) res_nquery(&resp, domain, C_IN, T_AAAA, aaaa_q, sizeof aaaa_q);
510 #endif /* T_AAAA */
511 (void) res_nquery(&resp, domain, C_IN, T_MX, mx_q, sizeof mx_q);
512 #ifdef HAVE_RES_NDESTROY
513 res_ndestroy(&resp);
514 #else
515 res_nclose(&resp);
516 #endif
517 #else /* HAVE_RES_NINIT */
518 (void) res_query(domain, C_IN, T_A, a_q, sizeof a_q);
519 #ifdef T_AAAA
520 (void) res_query(domain, C_IN, T_AAAA, aaaa_q, sizeof aaaa_q);
521 #endif /* T_AAAA */
522 (void) res_query(domain, C_IN, T_MX, mx_q, sizeof mx_q);
523 #endif /* HAVE_RES_NINIT */
524
525 memcpy(&hdr, a_q, sizeof hdr);
526 *rp = hdr.rcode;
527 if (hdr.rcode == NOERROR)
528 return TRUE;
529
530 memcpy(&hdr, aaaa_q, sizeof hdr);
531 *rp = hdr.rcode;
532 if (hdr.rcode == NOERROR)
533 return TRUE;
534
535 memcpy(&hdr, aaaa_q, sizeof hdr);
536 *rp = hdr.rcode;
537 if (hdr.rcode == NOERROR)
538 return TRUE;
539
540 return FALSE;
541 }
542
543 /***************************************************************************************************
544 ** opendmarc_dns_get_record -- looks up and returns the txt record
545 **
546 ** Arguments:
547 ** domain -- the domain name to look up.
548 ** reply -- pointer to an integer
549 ** txt -- where to scribble the found txt record
550 ** txtlen -- size of txt record buffer
551 ** cname -- buffer to hold CNAME if one found
552 ** cnamelen -- size of cname buffer
553 ** spfcheck -- restrict text records returned to just those beginning with v= or spf2.0
554 **
555 ** Returns:
556 ** txt -- on success
557 ** NULL -- otherise, and place the h_errno error
558 ** into reply
559 ** NULL -- if no data, but cname may still contain a hostname
560 **
561 ** Side Effects:
562 ** Makes a connection to the local name server and blocks
563 ** waiting for a reply.
564 ***************************************************************************************************/
565 char *
opendmarc_spf_dns_get_record(char * domain,int * reply,char * txt,size_t txtlen,char * cname,size_t cnamelen,int spfcheck)566 opendmarc_spf_dns_get_record(char *domain, int *reply, char *txt, size_t txtlen, char *cname, size_t cnamelen, int spfcheck)
567 {
568 u_char * eom = NULL;
569 u_char * eop = NULL;
570 u_char * cp = NULL;
571 int k;
572 u_char * p = NULL;
573 int ch = 0;
574 short l = 0;
575 HEADER hdr;
576 int class = -1;
577 int acnt = -1;
578 int qdcnt = -1;
579 u_short type = 0;
580 u_long ttl = 0;
581 char * bp = NULL;
582 int r = 0;
583 int * rp = NULL;
584 u_char txt_buf[MAXPACKET];
585 char hbuf[MAXDNSHOSTNAME];
586 char namebuf[MAXDNSHOSTNAME + 1];
587 #if HAVE_RES_NINIT
588 struct __res_state resp;
589 #endif /* HAVE_RES_NINIT */
590
591 if (reply == NULL)
592 rp = &r;
593 else
594 rp = reply;
595
596 /*
597 * If a null or empy domain was given to us, just say it
598 * was not found.
599 */
600 *rp = 0;
601 if (domain == NULL || *domain == '\0')
602 {
603 *rp = HOST_NOT_FOUND;
604 return NULL;
605 }
606
607 if (cname != NULL && cnamelen > 0)
608 (void) memset(cname, '\0', cnamelen);
609
610 /*
611 * Copy the domain so we can scribble on it. The orginal
612 * may point to a static string.
613 */
614 (void) memcpy(hbuf, domain, sizeof hbuf);
615 bp = hbuf;
616 if (txt != NULL)
617 (void) memset(txt, '\0', txtlen);
618
619 /*
620 * Make sure host ends in a dot to short circuit lookups
621 */
622 bp = hbuf + strlen(hbuf) - 1;
623 if (*bp != '.')
624 *++bp = '.';
625 *++bp = '\0';
626 /*
627 * Make user host does not begin with a dot.
628 */
629 bp = hbuf;
630 if (*bp == '.')
631 ++bp;
632
633 #ifdef HAVE_RES_NINIT
634 memset(&resp, '\0', sizeof resp);
635 res_ninit(&resp);
636 k = res_nquery(&resp, bp, C_IN, T_TXT, txt_buf, sizeof txt_buf);
637 #else /* HAVE_RES_NINIT */
638 k = res_query(bp, C_IN, T_TXT, txt_buf, sizeof txt_buf);
639 #endif /* HAVE_RES_NINIT */
640 if (k < 0)
641 {
642 /*
643 * TXT records apppear more common than SPF records, so
644 * we fall back to SPF instead of looking up SPF first.
645 */
646 if (h_errno == NO_DATA || h_errno == NXDOMAIN)
647 {
648 #ifdef HAVE_RES_NINIT
649 k = res_nquery(&resp, bp, C_IN, T_SPF, txt_buf, sizeof txt_buf);
650 #else /* HAVE_RES_NINIT */
651 k = res_query(bp, C_IN, T_SPF, txt_buf, sizeof txt_buf);
652 #endif /* HAVE_RES_NINIT */
653 if (k >= 0)
654 goto got_spf_record;
655 }
656 *rp = h_errno;
657 #ifdef HAVE_RES_NINIT
658 #ifdef HAVE_RES_NDESTROY
659 res_ndestroy(&resp);
660 #else
661 res_nclose(&resp);
662 #endif
663 #endif /* HAVE_RES_NINIT */
664 return NULL;
665 }
666 got_spf_record:
667 #ifdef HAVE_RES_NINIT
668 #ifdef HAVE_RES_NDESTROY
669 res_ndestroy(&resp);
670 #else
671 res_nclose(&resp);
672 #endif
673 #endif /* HAVE_RES_NINIT */
674
675 if (k > (int)(sizeof txt_buf))
676 k = sizeof txt_buf;
677 (void) memcpy(&hdr, txt_buf, sizeof hdr);
678 cp = (u_char *)&txt_buf + HFIXEDSZ;
679 eom = (u_char *)&txt_buf + k;
680
681 (void) memset(namebuf, '\0', sizeof namebuf);
682 /* skip question part of response -- we know what we asked */
683 for (qdcnt = ntohs(hdr.qdcount); qdcnt > 0; qdcnt--)
684 {
685 (void) dn_expand((unsigned char *) &txt_buf, eom, cp, namebuf, sizeof namebuf);
686 if ((k = dn_skipname(cp, eom)) < 0)
687 {
688 *rp = NO_DATA;
689 return NULL;
690 }
691 cp += k;
692 if (cp + INT16SZ + INT16SZ > eom)
693 {
694 *rp = NO_DATA;
695 return NULL;
696 }
697 GETSHORT(type, cp);
698 GETSHORT(class, cp);
699 }
700 if (hdr.rcode != NOERROR)
701 {
702 *rp = NO_DATA;
703 return NULL;
704 }
705 acnt = ntohs((unsigned short) hdr.ancount);
706 if (acnt == 0)
707 {
708 *rp = NO_DATA;
709 return NULL;
710 }
711 while (--acnt >= 0 && cp < eom)
712 {
713 if ((k = dn_expand((unsigned char *) &txt_buf, eom, cp,
714 namebuf, sizeof namebuf)) < 0)
715 {
716 *rp = NO_DATA;
717 return NULL;
718 }
719 cp += k;
720
721 if (cp + INT16SZ + INT16SZ > eom)
722 {
723 /* currupt answer */
724 *rp = NO_DATA;
725 return NULL;
726 }
727 GETSHORT(type, cp);
728 GETSHORT(class, cp);
729 if (type == T_CNAME)
730 {
731 /*
732 * CNAMEs are supposed to be invisible, but somtimes
733 * a CNAME points to a TXT record that times out, so
734 * all we get on the initial query is the CNAME.
735 */
736 char xname[MAXDNSHOSTNAME + 1];
737 char * xp;
738 size_t xlen;
739
740 if (cname == NULL || cnamelen == 0)
741 {
742 xp = xname;
743 xlen = sizeof xname;
744 }
745 else
746 {
747 xp = cname;
748 xlen = cnamelen;
749 }
750 k = dn_expand((u_char *) &txt_buf, eom, (u_char *)cname, xp, xlen);
751 cp += k;
752 continue;
753 }
754 else if (type != T_TXT)
755 {
756
757 *rp = NO_DATA;
758 return NULL;
759 }
760 /* we may want to cache the ttl later */
761 GETLONG(ttl, cp);
762
763 if (cp + INT16SZ > eom)
764 {
765 /* no payload length */
766 *rp = NO_DATA;
767 return NULL;
768 }
769 GETSHORT(l, cp);
770
771 if (cp + l > eom)
772 {
773 /* payload length greater than remaining buffer */
774 *rp = NO_DATA;
775 return NULL;
776 }
777 if (txt != NULL)
778 {
779 (void) memset(txt, '\0', txtlen);
780 /*
781 * copy the returned record into txt
782 */
783 p = (u_char *)txt;
784 eop = (u_char *)txt + txtlen -1;
785 while (l > 0 && p < eop)
786 {
787 ch = *cp++;
788 l--;
789 while (ch > 0 && p < eop)
790 {
791 *p++ = *cp++;
792 ch--;
793 l--;
794 }
795 }
796 }
797 if (spfcheck == TRUE)
798 {
799 /*
800 * Honor both SPF and Sender Identity type records
801 * But ignore mfrom/pra, because DMARC uses only SPF records.
802 */
803 if (strstr(txt, "v=spf") != NULL || strncasecmp(txt, "spf2.0", 6) == 0)
804 {
805 *rp = 0;
806 return txt;
807 }
808 }
809 cp += l;
810 continue;
811 }
812 *rp = NO_DATA;
813 return NULL;
814 }
815
816 #endif /* WITH_SPF && ! HAVE_SPF2_H */
817