]>
git.ipfire.org Git - people/ms/dnsmasq.git/blob - src/rfc1035.c
1 /* dnsmasq is Copyright (c) 2000 Simon Kelley
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
15 static int extract_name(HEADER
*header
, unsigned int plen
, unsigned char **pp
,
16 unsigned char *name
, int isExtract
)
18 unsigned char *cp
= name
, *p
= *pp
, *p1
= NULL
;
19 unsigned int j
, l
, hops
= 0;
24 unsigned int label_type
= l
& 0xc0;
25 if (label_type
== 0xc0) /* pointer */
27 if (p
- (unsigned char *)header
+ 1u >= plen
)
33 if (l
>= (unsigned int)plen
)
36 if (!p1
) /* first jump, save location to go back to */
39 hops
++; /* break malicious infinite loops */
43 p
= l
+ (unsigned char *)header
;
45 else if (label_type
== 0x80)
46 return 0; /* reserved */
47 else if (label_type
== 0x40)
49 unsigned int count
, digs
;
52 return 0; /* we only understand bitstrings */
55 return 0; /* Cannot compare bitsrings */
60 digs
= ((count
-1)>>2)+1;
62 /* output is \[x<hex>/siz]. which is digs+9 chars */
63 if (cp
- name
+ digs
+ 9 >= MAXDNAME
)
65 if (p
- (unsigned char *)header
+ ((count
-1)>>3) + 1u >= plen
)
71 for (j
=0; j
<digs
; j
++)
79 *cp
++ = dig
< 10 ? dig
+ '0' : dig
+ 'A' - 10;
81 cp
+= sprintf(cp
, "/%d]", count
);
82 /* do this here to overwrite the zero char from sprintf */
86 { /* label_type = 0 -> label. */
87 if (cp
- name
+ l
+ 1 >= MAXDNAME
)
89 if (p
- (unsigned char *)header
+ 1u >= plen
)
91 for(j
=0; j
<l
; j
++, p
++)
101 unsigned char c1
= *cp
, c2
= *p
;
108 if (c1
>= 'A' && c1
<= 'Z')
110 if (c2
>= 'A' && c2
<= 'Z')
121 if (*cp
!= 0 && *cp
++ != '.')
125 if ((unsigned int)(p
- (unsigned char *)header
) >= plen
)
130 *--cp
= 0; /* terminate: lose final period */
132 if (p1
) /* we jumped via compression */
140 /* Max size of input string (for IPv6) is 75 chars.) */
141 #define MAXARPANAME 75
142 static int in_arpa_name_2_addr(char *namein
, struct all_addr
*addrp
)
145 char name
[MAXARPANAME
+1], *cp1
;
146 unsigned char *addr
= (unsigned char *)addrp
;
147 char *lastchunk
= NULL
, *penchunk
= NULL
;
149 if (strlen(namein
) > MAXARPANAME
)
152 memset(addrp
, 0, sizeof(struct all_addr
));
154 /* turn name into a series of asciiz strings */
155 /* j counts no of labels */
156 for(j
= 1,cp1
= name
; *namein
; cp1
++, namein
++)
159 penchunk
= lastchunk
;
172 if (hostname_isequal(lastchunk
, "arpa") && hostname_isequal(penchunk
, "in-addr"))
175 /* address arives as a name of the form
176 www.xxx.yyy.zzz.in-addr.arpa
177 some of the low order address octets might be missing
178 and should be set to zero. */
179 for (cp1
= name
; cp1
!= penchunk
; cp1
+= strlen(cp1
)+1)
181 /* check for digits only (weeds out things like
182 50.0/24.67.28.64.in-addr.arpa which are used
183 as CNAME targets according to RFC 2317 */
185 for (cp
= cp1
; *cp
; cp
++)
186 if (!isdigit((int)*cp
))
198 else if (hostname_isequal(penchunk
, "ip6") &&
199 (hostname_isequal(lastchunk
, "int") || hostname_isequal(lastchunk
, "arpa")))
202 Address arrives as 0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.ip6.[int|arpa]
203 or \[xfedcba9876543210fedcba9876543210/128].ip6.[int|arpa]
205 Note that most of these the various reprentations are obsolete and
206 left-over from the many DNS-for-IPv6 wars. We support all the formats
207 that we can since there is no reason not to.
210 if (*name
== '\\' && *(name
+1) == '[' &&
211 (*(name
+2) == 'x' || *(name
+2) == 'X'))
213 for (j
= 0, cp1
= name
+3; *cp1
&& isxdigit(*cp1
) && j
< 32; cp1
++, j
++)
219 addr
[j
/2] |= strtol(xdig
, NULL
, 16);
221 addr
[j
/2] = strtol(xdig
, NULL
, 16) << 4;
224 if (*cp1
== '/' && j
== 32)
229 for (cp1
= name
; cp1
!= penchunk
; cp1
+= strlen(cp1
)+1)
231 if (*(cp1
+1) || !isxdigit((int)*cp1
))
234 for (j
= sizeof(struct all_addr
)-1; j
>0; j
--)
235 addr
[j
] = (addr
[j
] >> 4) | (addr
[j
-1] << 4);
236 addr
[0] = (addr
[0] >> 4) | (strtol(cp1
, NULL
, 16) << 4);
247 static unsigned char *skip_questions(HEADER
*header
, unsigned int plen
)
249 int q
, qdcount
= ntohs(header
->qdcount
);
250 unsigned char *ansp
= (unsigned char *)(header
+1);
252 for (q
=0; q
<qdcount
; q
++)
256 unsigned int label_type
= (*ansp
) & 0xc0;
258 if ((unsigned int)(ansp
- (unsigned char *)header
) >= plen
)
261 if (label_type
== 0xc0)
263 /* pointer for compression. */
267 else if (label_type
== 0x80)
268 return NULL
; /* reserved */
269 else if (label_type
== 0x40)
271 /* Extended label type */
274 if (((*ansp
++) & 0x3f) != 1)
275 return NULL
; /* we only understand bitstrings */
277 count
= *(ansp
++); /* Bits in bitstring */
279 if (count
== 0) /* count == 0 means 256 bits */
282 ansp
+= ((count
-1)>>3)+1;
285 { /* label type == 0 Bottom six bits is length */
286 unsigned int len
= (*ansp
++) & 0x3f;
288 break; /* zero length label marks the end. */
293 ansp
+= 4; /* class and type */
295 if ((unsigned int)(ansp
- (unsigned char *)header
) > plen
)
301 /* is addr in the non-globally-routed IP space? */
302 static int private_net(struct all_addr
*addrp
)
304 struct in_addr addr
= *(struct in_addr
*)addrp
;
305 if (inet_netof(addr
) == 0xA ||
306 (inet_netof(addr
) >= 0xAC10 && inet_netof(addr
) < 0xAC20) ||
307 (inet_netof(addr
) >> 8) == 0xC0A8)
313 static unsigned char *add_text_record(unsigned int nameoffset
, unsigned char *p
,
314 unsigned long ttl
, unsigned short pref
,
315 unsigned short type
, char *name
)
317 unsigned char *sav
, *cp
;
320 PUTSHORT(nameoffset
| 0xc000, p
);
323 PUTLONG(ttl
, p
); /* TTL */
326 PUTSHORT(0, p
); /* dummy RDLENGTH */
334 for (j
=0; *name
&& (*name
!= '.'); name
++, j
++)
342 PUTSHORT(j
, sav
); /* Real RDLENGTH */
347 /* On receiving an NXDOMAIN or NODATA reply, determine which names are known
348 not to exist for negative caching. name if a working buffer passed in. */
349 void extract_neg_addrs(HEADER
*header
, unsigned int qlen
, char *name
, time_t now
)
352 int i
, found_soa
= 0;
353 int qtype
, qclass
, rdlen
;
354 unsigned long ttl
, minttl
= 0;
355 unsigned short flags
= F_NEG
;
357 if (header
->rcode
== NXDOMAIN
)
360 /* there may be more than one question with some questions
361 answered. We don't generate negative entries from those. */
362 if (ntohs(header
->ancount
) != 0)
365 if (!(p
= skip_questions(header
, qlen
)))
366 return; /* bad packet */
368 /* we first need to find SOA records, to get min TTL, then we
369 add a NEG cache entry for each question. */
371 for (i
=0; i
<ntohs(header
->nscount
); i
++)
373 if (!extract_name(header
, qlen
, &p
, name
, 1))
374 return; /* bad packet */
381 if ((qclass
== C_IN
) && (qtype
== T_SOA
))
385 if (!extract_name(header
, qlen
, &p
, name
, 1))
388 if (!extract_name(header
, qlen
, &p
, name
, 1))
390 GETLONG(dummy
, p
); /* SERIAL */
391 GETLONG(dummy
, p
); /* REFRESH */
392 GETLONG(dummy
, p
); /* RETRY */
393 GETLONG(dummy
, p
); /* EXPIRE */
399 else if (ttl
< minttl
)
401 GETLONG(ttl
, p
); /* minTTL */
408 if ((unsigned int)(p
- (unsigned char *)header
) > qlen
)
409 return; /* bad packet */
413 return; /* failed to find SOA */
415 cache_start_insert();
417 p
= (unsigned char *)(header
+1);
419 for (i
=0; i
<ntohs(header
->qdcount
); i
++)
421 struct all_addr addr
;
424 if (!extract_name(header
, qlen
, &p
, name
, 1))
425 return; /* bad packet */
430 if (qclass
== C_IN
&& qtype
== T_PTR
&& (is_arpa
= in_arpa_name_2_addr(name
, &addr
)))
431 cache_insert(name
, &addr
, now
, minttl
, is_arpa
| F_REVERSE
| flags
);
432 else if (qclass
== C_IN
&& qtype
== T_A
)
433 cache_insert(name
, NULL
, now
, minttl
, F_IPV4
| F_FORWARD
| flags
);
435 else if (qclass
== C_IN
&& qtype
== T_AAAA
)
436 cache_insert(name
, NULL
, now
, minttl
, F_IPV6
| F_FORWARD
| flags
);
443 void extract_addresses(HEADER
*header
, unsigned int qlen
, char *name
, time_t now
)
445 unsigned char *p
, *psave
, *endrr
;
446 int qtype
, qclass
, rdlen
;
450 /* skip over questions */
451 if (!(p
= skip_questions(header
, qlen
)))
452 return; /* bad packet */
454 cache_start_insert();
458 for (i
=0; i
<ntohs(header
->ancount
); i
++)
460 unsigned char *origname
= p
;
461 if (!extract_name(header
, qlen
, &p
, name
, 1))
462 return; /* bad packet */
470 if ((unsigned int)(endrr
- (unsigned char *)header
) > qlen
)
471 return; /* bad packet */
479 if (qtype
== T_A
) /* A record. */
480 cache_insert(name
, (struct all_addr
*)p
, now
,
481 ttl
, F_IPV4
| F_FORWARD
);
483 else if (qtype
== T_AAAA
) /* IPV6 address record. */
484 cache_insert(name
, (struct all_addr
*)p
, now
,
485 ttl
, F_IPV6
| F_FORWARD
);
487 else if (qtype
== T_PTR
)
490 struct all_addr addr
;
491 int name_encoding
= in_arpa_name_2_addr(name
, &addr
);
494 if (!extract_name(header
, qlen
, &p
, name
, 1))
495 return; /* bad packet */
496 cache_insert(name
, &addr
, now
,
497 ttl
, name_encoding
| F_REVERSE
);
500 else if (qtype
== T_CNAME
)
502 /* CNAME, search whole answer section again */
503 unsigned char *endrr1
;
506 unsigned char *targp
= p
;
508 p
= psave
; /* rewind p */
509 for (j
=0; j
<ntohs(header
->ancount
); j
++)
512 unsigned char *tmp
= targp
;
513 /* copy since it gets altered by extract_name */
514 /* get CNAME target each time round */
515 if (!extract_name(header
, qlen
, &tmp
, name
, 1))
516 return; /* bad packet */
517 /* compare this name with target of CNAME in name buffer */
518 if (!(res
= extract_name(header
, qlen
, &p
, name
, 0)))
519 return; /* bad packet */
527 if ((unsigned int)(endrr1
- (unsigned char *)header
) > qlen
)
528 return; /* bad packet */
530 /* is this RR name same as target of CNAME */
531 if ((qclass
!= C_IN
) || (res
== 2))
537 /* match, use name of CNAME, data from this RR
538 use min TTL of two */
543 /* get orig. name back again */
545 if (!extract_name(header
, qlen
, &tmp
, name
, 1))
548 if (qtype
== T_A
) /* A record. */
549 cache_insert(name
, (struct all_addr
*)p
, now
,
550 cttl
, F_IPV4
| F_FORWARD
);
552 else if (qtype
== T_AAAA
) /* IPV6 address record. */
553 cache_insert(name
, (struct all_addr
*)p
, now
,
554 cttl
, F_IPV6
| F_FORWARD
);
556 else if (qtype
== T_PTR
)
558 /* PTR record extract address from CNAME name */
559 struct all_addr addr
;
560 int name_encoding
= in_arpa_name_2_addr(name
, &addr
);
563 if (!extract_name(header
, qlen
, &p
, name
, 1))
564 return; /* bad packet */
565 cache_insert(name
, &addr
, now
, cttl
,
566 name_encoding
| F_REVERSE
);
578 /* If the packet holds exactly one query
579 return 1 and leave the name from the query in name. */
581 unsigned short extract_request(HEADER
*header
,unsigned int qlen
, char *name
)
583 unsigned char *p
= (unsigned char *)(header
+1);
586 if (ntohs(header
->qdcount
) != 1 || header
->opcode
!= QUERY
)
587 return 0; /* must be exactly one query. */
589 if (!extract_name(header
, qlen
, &p
, name
, 1))
590 return 0; /* bad packet */
602 return F_IPV4
| F_IPV6
;
609 int setup_reply(HEADER
*header
, unsigned int qlen
,
610 struct all_addr
*addrp
, unsigned short flags
, unsigned long ttl
)
612 unsigned char *p
= skip_questions(header
, qlen
);
614 header
->qr
= 1; /* response */
615 header
->aa
= 0; /* authoritive */
616 header
->ra
= 1; /* recursion if available */
617 header
->tc
= 0; /* not truncated */
618 header
->nscount
= htons(0);
619 header
->arcount
= htons(0);
620 header
->ancount
= htons(0); /* no answers unless changed below*/
622 header
->rcode
= SERVFAIL
; /* couldn't get memory */
623 else if (flags
== F_NOERR
|| flags
== F_QUERY
)
624 header
->rcode
= NOERROR
; /* empty domain */
625 else if (flags
== F_NXDOMAIN
)
626 header
->rcode
= NXDOMAIN
;
627 else if (p
&& flags
== F_IPV4
)
628 { /* we know the address */
629 header
->rcode
= NOERROR
;
630 header
->ancount
= htons(1);
632 PUTSHORT (sizeof(HEADER
) | 0xc000, p
);
635 PUTLONG(ttl
, p
); /* TTL */
636 PUTSHORT(INADDRSZ
, p
);
637 memcpy(p
, addrp
, INADDRSZ
);
641 else if (p
&& flags
== F_IPV6
)
643 header
->rcode
= NOERROR
;
644 header
->ancount
= htons(1);
646 PUTSHORT (sizeof(HEADER
) | 0xc000, p
);
649 PUTLONG(ttl
, p
); /* TTL */
650 PUTSHORT(IN6ADDRSZ
, p
);
651 memcpy(p
, addrp
, IN6ADDRSZ
);
655 else /* nowhere to forward to */
656 header
->rcode
= REFUSED
;
658 return p
- (unsigned char *)header
;
662 /* Is the packet a reply with the answer address equal to addr?
663 If so mung is into an NXDOMAIN reply and also put that information
665 int check_for_bogus_wildcard(HEADER
*header
, unsigned int qlen
, char *name
,
666 struct bogus_addr
*baddr
, time_t now
)
669 int i
, qtype
, qclass
, rdlen
;
671 struct bogus_addr
*baddrp
;
673 /* skip over questions */
674 if (!(p
= skip_questions(header
, qlen
)))
675 return 0; /* bad packet */
677 for (i
=0; i
<ntohs(header
->ancount
); i
++)
679 if (!extract_name(header
, qlen
, &p
, name
, 1))
680 return 0; /* bad packet */
687 if (qclass
== C_IN
&& qtype
== T_A
)
688 for (baddrp
= baddr
; baddrp
; baddrp
= baddrp
->next
)
689 if (memcmp(&baddrp
->addr
, p
, INADDRSZ
) == 0)
691 /* Found a bogus address. Mangle the packet into an NXDOMAIN reply */
693 header
->ra
= 1; /* recursion if available */
694 header
->nscount
= htons(0);
695 header
->arcount
= htons(0);
696 header
->ancount
= htons(0);
697 header
->rcode
= NXDOMAIN
;
699 cache_start_insert();
700 cache_insert(name
, NULL
, now
, ttl
, F_IPV4
| F_FORWARD
| F_NEG
| F_NXDOMAIN
| F_CONFIG
);
712 /* return zero if we can't answer from cache, or packet size if we can */
713 int answer_request(HEADER
*header
, char *limit
, unsigned int qlen
, char *mxname
,
714 char *mxtarget
, unsigned int options
, time_t now
,
715 unsigned long local_ttl
, char *name
)
717 unsigned char *p
, *ansp
;
718 int qtype
, qclass
, is_arpa
;
719 struct all_addr addr
;
720 unsigned int nameoffset
;
721 int q
, qdcount
= ntohs(header
->qdcount
);
722 int ans
, anscount
= 0;
724 int nxdomain
= 0, auth
= 1;
726 if (!qdcount
|| header
->opcode
!= QUERY
)
729 /* determine end of question section (we put answers there) */
730 if (!(ansp
= skip_questions(header
, qlen
)))
731 return 0; /* bad packet */
733 /* now process each question, answers go in RRs after the question */
734 p
= (unsigned char *)(header
+1);
736 for (q
=0; q
<qdcount
; q
++)
738 /* save pointer to name for copying into answers */
739 nameoffset
= p
- (unsigned char *)header
;
741 /* now extract name as .-concatenated string into name */
742 if (!extract_name(header
, qlen
, &p
, name
, 1))
743 return 0; /* bad packet */
745 /* see if it's w.z.y.z.in-addr.arpa format */
747 is_arpa
= in_arpa_name_2_addr(name
, &addr
);
752 ans
= 0; /* have we answered this question */
754 if (qclass
== C_CHAOS
)
755 /* special query to get version. */
760 if (hostname_isequal(name
, "version.bind"))
761 sprintf(name
, "dnsmasq-%s", VERSION
);
762 else if (hostname_isequal(name
, "authors.bind"))
763 sprintf(name
, "Simon Kelley");
767 PUTSHORT(nameoffset
| 0xc000, ansp
);
768 PUTSHORT(T_TXT
, ansp
);
769 PUTSHORT(C_CHAOS
, ansp
);
771 PUTSHORT(len
+1, ansp
);
773 memcpy(ansp
, name
, len
);
778 if (((unsigned char *)limit
- ansp
) < 0)
784 else if (qclass
!= C_IN
)
785 return 0; /* we can't answer non-inet queries */
789 if ((options
& OPT_FILTER
) && (qtype
== T_SOA
|| qtype
== T_SRV
))
792 if (qtype
== T_PTR
|| qtype
== T_ANY
)
795 while ((crecp
= cache_find_by_addr(crecp
, &addr
, now
, is_arpa
)))
798 /* Return 0 ttl for DHCP entries, which might change
799 before the lease expires. */
800 if (crecp
->flags
& (F_IMMORTAL
| F_DHCP
))
803 ttl
= crecp
->ttd
- now
;
805 /* don't answer wildcard queries with data not from /etc/hosts
807 if (qtype
== T_ANY
&& !(crecp
->flags
& (F_HOSTS
| F_DHCP
)))
811 if (crecp
->flags
& F_NEG
)
813 log_query(crecp
->flags
& ~F_FORWARD
, name
, &addr
);
815 if (crecp
->flags
& F_NXDOMAIN
)
820 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
)))
822 ansp
= add_text_record(nameoffset
, ansp
, ttl
, 0, T_PTR
,
823 cache_get_name(crecp
));
825 log_query(crecp
->flags
& ~F_FORWARD
, cache_get_name(crecp
), &addr
);
828 /* if last answer exceeded packet size, give up */
829 if (((unsigned char *)limit
- ansp
) < 0)
834 /* if not in cache, enabled and private IPV4 address, fake up answer */
835 if (ans
== 0 && is_arpa
== F_IPV4
&&
836 (options
& OPT_BOGUSPRIV
) &&
839 struct in_addr addr4
= *((struct in_addr
*)&addr
);
840 ansp
= add_text_record(nameoffset
, ansp
, local_ttl
, 0, T_PTR
, inet_ntoa(addr4
));
841 log_query(F_CONFIG
| F_REVERSE
| F_IPV4
, inet_ntoa(addr4
), &addr
);
845 if (((unsigned char *)limit
- ansp
) < 0)
850 if (qtype
== T_A
|| qtype
== T_ANY
)
852 /* T_ANY queries for hostnames with underscores are spam
853 from win2k - don't forward them. */
854 if ((options
& OPT_FILTER
) &&
856 (strchr(name
, '_') != NULL
))
861 while ((crecp
= cache_find_by_name(crecp
, name
, now
, F_IPV4
)))
864 if (crecp
->flags
& (F_IMMORTAL
| F_DHCP
))
867 ttl
= crecp
->ttd
- now
;
869 /* don't answer wildcard queries with data not from /etc/hosts
871 if (qtype
== T_ANY
&& !(crecp
->flags
& (F_HOSTS
| F_DHCP
)))
874 /* If we have negative cache entry, it's OK
875 to return no answer. */
878 if (crecp
->flags
& F_NEG
)
880 log_query(crecp
->flags
, name
, NULL
);
882 if (crecp
->flags
& F_NXDOMAIN
)
887 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
)))
889 log_query(crecp
->flags
& ~F_REVERSE
, name
, &crecp
->addr
);
891 /* copy question as first part of answer (use compression) */
892 PUTSHORT(nameoffset
| 0xc000, ansp
);
894 PUTSHORT(C_IN
, ansp
);
895 PUTLONG(ttl
, ansp
); /* TTL */
897 PUTSHORT(INADDRSZ
, ansp
);
898 memcpy(ansp
, &crecp
->addr
, INADDRSZ
);
902 if (((unsigned char *)limit
- ansp
) < 0)
911 if (qtype
== T_AAAA
|| qtype
== T_ANY
)
913 /* T_ANY queries for hostnames with underscores are spam
914 from win2k - don't forward them. */
915 if ((options
& OPT_FILTER
) &&
917 && (strchr(name
, '_') != NULL
))
922 while ((crecp
= cache_find_by_name(crecp
, name
, now
, F_IPV6
)))
925 if (crecp
->flags
& (F_IMMORTAL
| F_DHCP
))
928 ttl
= crecp
->ttd
- now
;
930 /* don't answer wildcard queries with data not from /etc/hosts
932 if (qtype
== T_ANY
&& !(crecp
->flags
& (F_HOSTS
| F_DHCP
)))
935 /* If we have negative cache entry, it's OK
936 to return no answer. */
939 if (crecp
->flags
& F_NEG
)
941 log_query(crecp
->flags
, name
, NULL
);
943 if (crecp
->flags
& F_NXDOMAIN
)
948 if (!(crecp
->flags
& (F_HOSTS
| F_DHCP
)))
950 log_query(crecp
->flags
& ~F_REVERSE
, name
, &crecp
->addr
);
952 /* copy question as first part of answer (use compression) */
953 PUTSHORT(nameoffset
| 0xc000, ansp
);
954 PUTSHORT(T_AAAA
, ansp
);
955 PUTSHORT(C_IN
, ansp
);
956 PUTLONG(ttl
, ansp
); /* TTL */
958 PUTSHORT(IN6ADDRSZ
, ansp
);
959 memcpy(ansp
, &crecp
->addr
, IN6ADDRSZ
);
963 if (((unsigned char *)limit
- ansp
) < 0)
971 if (qtype
== T_MX
|| qtype
== T_ANY
)
973 if (mxname
&& hostname_isequal(name
, mxname
))
975 ansp
= add_text_record(nameoffset
, ansp
, local_ttl
, 1, T_MX
, mxtarget
);
979 else if ((options
& (OPT_SELFMX
| OPT_LOCALMX
)) &&
980 cache_find_by_name(NULL
, name
, now
, F_HOSTS
| F_DHCP
))
982 ansp
= add_text_record(nameoffset
, ansp
, local_ttl
, 1, T_MX
,
983 (options
& OPT_SELFMX
) ? name
: mxtarget
);
987 if (((unsigned char *)limit
- ansp
) < 0)
991 if (qtype
== T_MAILB
)
992 ans
= 1, nxdomain
= 1;
997 return 0; /* failed to answer a question */
1001 /* done all questions, set up header and return length of result */
1002 header
->qr
= 1; /* response */
1003 header
->aa
= auth
; /* authoritive - only hosts and DHCP derived names. */
1004 header
->ra
= 1; /* recursion if available */
1005 header
->tc
= 0; /* truncation */
1006 if (anscount
== 0 && nxdomain
)
1007 header
->rcode
= NXDOMAIN
;
1009 header
->rcode
= NOERROR
; /* no error */
1010 header
->ancount
= htons(anscount
);
1011 header
->nscount
= htons(0);
1012 header
->arcount
= htons(0);
1013 return ansp
- (unsigned char *)header
;