diff --git a/src/dnsmasq/dnsmasq.h b/src/dnsmasq/dnsmasq.h index 7428b7f62..286d7c228 100644 --- a/src/dnsmasq/dnsmasq.h +++ b/src/dnsmasq/dnsmasq.h @@ -282,7 +282,8 @@ struct event_desc { #define OPT_CACHE_RR 71 #define OPT_LOCALHOST_SERVICE 72 #define OPT_LOG_PROTO 73 -#define OPT_LAST 74 +#define OPT_NO_0x20 74 +#define OPT_LAST 75 #define OPTION_BITS (sizeof(unsigned int)*8) #define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) ) diff --git a/src/dnsmasq/forward.c b/src/dnsmasq/forward.c index cf553288c..5e51f5fe9 100644 --- a/src/dnsmasq/forward.c +++ b/src/dnsmasq/forward.c @@ -338,7 +338,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr, forward->new_id = get_id(); header->id = ntohs(forward->new_id); - forward->encode_bitmap = rand32(); + forward->encode_bitmap = option_bool(OPT_NO_0x20) ? 0 : rand32(); p = (unsigned char *)(header+1); if (!extract_name(header, plen, &p, NULL, EXTR_NAME_FLIP, forward->encode_bitmap)) goto reply; @@ -2146,7 +2146,7 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, sending replies containing questions and bogus answers. Try another server, or give up */ p = (unsigned char *)(header+1); - if (extract_name(header, rsize, &p, daemon->namebuff, EXTR_NAME_NOCASE, 4) != 1) + if (extract_name(header, rsize, &p, daemon->namebuff, EXTR_NAME_COMPARE, 4) != 1) continue; GETSHORT(rtype, p); GETSHORT(rclass, p); @@ -3225,22 +3225,35 @@ static struct frec *lookup_frec(char *target, int class, int rrtype, int id, int (header = blockdata_retrieve(f->stash, f->stash_len, NULL))) { unsigned char *p = (unsigned char *)(header+1); - int hclass, hrrtype; + int hclass, hrrtype, rc; /* Case sensitive compare for DNS-0x20 encoding. */ - if (extract_name(header, f->stash_len, &p, target, EXTR_NAME_NOCASE, 4) != 1) - continue; - - GETSHORT(hrrtype, p); - GETSHORT(hclass, p); - - /* type checked by flags for DNSSEC queries. */ - if (rrtype != -1 && rrtype != hrrtype) - continue; - - if (class != hclass) - continue; - + if ((rc = extract_name(header, f->stash_len, &p, target, option_bool(OPT_NO_0x20) ? EXTR_NAME_COMPARE : EXTR_NAME_NOCASE, 4))) + { + GETSHORT(hrrtype, p); + GETSHORT(hclass, p); + + /* type checked by flags for DNSSEC queries. */ + if (rrtype != -1 && rrtype != hrrtype) + continue; + + if (class != hclass) + continue; + } + + if (rc != 1) + { + static int warned = 0; + + if (rc == 3 && !warned) + { + my_syslog(LOG_WARNING, _("Case mismatch in DNS reply - check bit 0x20 encoding.")); + warned = 1; + } + + continue; + } + return f; } diff --git a/src/dnsmasq/option.c b/src/dnsmasq/option.c index 4f8bcf14d..9c850a9be 100644 --- a/src/dnsmasq/option.c +++ b/src/dnsmasq/option.c @@ -197,6 +197,7 @@ struct myoption { #define LOPT_MAX_PROCS 384 #define LOPT_DNSSEC_LIMITS 385 #define LOPT_PXE_OPT 386 +#define LOPT_NO_ENCODE 387 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -251,6 +252,7 @@ static const struct myoption opts[] = { "local-ttl", 1, 0, 'T' }, { "no-negcache", 0, 0, 'N' }, { "no-round-robin", 0, 0, LOPT_NORR }, + { "no-0x20-encode", 0, 0, LOPT_NO_ENCODE }, { "cache-rr", 1, 0, LOPT_CACHE_RR }, { "addn-hosts", 1, 0, 'H' }, { "hostsdir", 1, 0, LOPT_HOST_INOTIFY }, @@ -595,6 +597,7 @@ static struct { { LOPT_UMBRELLA, ARG_ONE, "[=]", gettext_noop("Send Cisco Umbrella identifiers including remote IP."), NULL }, { LOPT_QUIET_TFTP, OPT_QUIET_TFTP, NULL, gettext_noop("Do not log routine TFTP."), NULL }, { LOPT_NORR, OPT_NORR, NULL, gettext_noop("Suppress round-robin ordering of DNS records."), NULL }, + { LOPT_NO_ENCODE, OPT_NO_0x20, NULL, gettext_noop("Suppress DNS bit 0x20 encoding."), NULL }, { LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL }, { LOPT_CACHE_RR, ARG_DUP, "", gettext_noop("Cache this DNS resource record type."), NULL }, { LOPT_MAX_PROCS, ARG_ONE, "", gettext_noop("Maximum number of concurrent tcp connections."), NULL }, diff --git a/src/dnsmasq/rfc1035.c b/src/dnsmasq/rfc1035.c index 4db992d4f..557b92a36 100644 --- a/src/dnsmasq/rfc1035.c +++ b/src/dnsmasq/rfc1035.c @@ -25,6 +25,7 @@ return = 0 -> error return = 1 -> extract OK, compare OK, flip OK return = 2 -> extract OK, compare failed. + return = 3 -> extract OK, compare failed but only on case. */ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, char *name, int func, unsigned int parm) @@ -141,9 +142,21 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, if (case_insens && c2 >= 'A' && c2 <= 'Z') c2 += 'a' - 'A'; + + if (!case_insens && retvalue != 2 && c1 != c2) + { + if (c1 >= 'A' && c1 <= 'Z') + c1 += 'a' - 'A'; + + if (c2 >= 'A' && c2 <= 'Z') + c2 += 'a' - 'A'; + + if (c1 == c2) + retvalue = 3; + } if (c1 != c2) - retvalue = 2; + retvalue = 2; } }