From c1bb85048b4551445ecda00b30717e479c16b2d0 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Wed, 11 Aug 2004 18:40:17 +0100 Subject: [PATCH] import of dnsmasq-2.12.tar.gz --- CHANGELOG | 15 ++++++++ FAQ | 9 +++++ dnsmasq-rh.spec | 2 +- dnsmasq-suse.spec | 2 +- dnsmasq.conf.example | 13 ++++--- src/cache.c | 92 ++++++++++++++++++++++++++++++++++---------- src/config.h | 2 +- src/dnsmasq.h | 8 ++-- src/forward.c | 39 ++++++++++--------- src/isc.c | 8 +--- src/lease.c | 8 +--- src/rfc1035.c | 23 +++++++---- 12 files changed, 150 insertions(+), 71 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9967655..b8cdbe8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1142,4 +1142,19 @@ version 2.11 Set source interface when replying to IPv6 UDP queries. This is needed to cope with link-local addresses. +version 2.12 + Added extra checks to ensure that DHCP created DNS entries + cannot generate multiple DNS address->name entries. Thanks to + Stefan Monnier for finding the exact set of configuration + options which could create this. + + Don't set the the filterwin2k option in the example config + file and add warnings that is breaks Kerberos. Thanks to + Simon Josefsson and Timothy Folks for pointing that out. + + Log types of incoming queries as well as source and domain. + + Log NODATA replies generated as a result of the + finlterwin2k option. + diff --git a/FAQ b/FAQ index f535275..00e68e7 100644 --- a/FAQ +++ b/FAQ @@ -268,4 +268,13 @@ A: The DNS spec says that the reply to a DNS query must come from the (address,port) pair when dnsmasq has bound (wildcard,port), hence the ability to explicitly turn off wildcard binding. +Q: Why doesn't Kerberos work/why can't I get sensible answers to + queries for SRV records. +A: Probably because you have the "filterwin2k" option set. Note that + it was on by default in example configuration files included in + versions before 2.12, so you might have it set on without + realising. + + + diff --git a/dnsmasq-rh.spec b/dnsmasq-rh.spec index 4973d42..bf3486a 100644 --- a/dnsmasq-rh.spec +++ b/dnsmasq-rh.spec @@ -5,7 +5,7 @@ ############################################################################### Name: dnsmasq -Version: 2.11 +Version: 2.12 Release: 1 Copyright: GPL Group: System Environment/Daemons diff --git a/dnsmasq-suse.spec b/dnsmasq-suse.spec index 9899ecf..7d05868 100644 --- a/dnsmasq-suse.spec +++ b/dnsmasq-suse.spec @@ -5,7 +5,7 @@ ############################################################################### Name: dnsmasq -Version: 2.11 +Version: 2.12 Release: 1 Copyright: GPL Group: Productivity/Networking/DNS/Servers diff --git a/dnsmasq.conf.example b/dnsmasq.conf.example index 2bd8b51..7fdd24a 100644 --- a/dnsmasq.conf.example +++ b/dnsmasq.conf.example @@ -12,7 +12,7 @@ #selfmx #localmx -# The following three options make you a better netizen, since they +# The following two options make you a better netizen, since they # tell dnsmasq to filter out queries which the public DNS cannot # answer, and which load the servers (especially the root servers) # uneccessarily. If you have a dial-on-demand link they also stop @@ -20,13 +20,16 @@ # Never forward plain names (with a dot or domain part) domain-needed -# Reply to reverse queries for addresses in the non-routed address -# space with the dotted.quad address +# Never forward addresses in the non-routed address spaces. bogus-priv -# Filter useless windows-originated DNS requests -filterwin2k +# Uncomment this to filter useless windows-originated DNS requests +# which can trigger dial-on-demand links needlessly. +# Note that (amongst other things) this blocks all SRV requests, +# so don't use it if you use eg Kerberos. +#filterwin2k + # Change this line if you want dns to get its upstream servers from # somewhere other that /etc/resolv.conf #resolv-file= diff --git a/src/cache.c b/src/cache.c index 4a01dc9..ff672df 100644 --- a/src/cache.c +++ b/src/cache.c @@ -226,7 +226,7 @@ void cache_insert(char *name, struct all_addr *addr, union bigname *big_name = NULL; int freed_all = flags & F_REVERSE; - log_query(flags | F_UPSTREAM, name, addr); + log_query(flags | F_UPSTREAM, name, addr, 0); /* name is needed as workspace by log_query in this case */ if ((flags & F_NEG) && (flags & F_REVERSE)) @@ -633,36 +633,42 @@ void cache_unhash_dhcp(void) dhcp_inuse = NULL; } -void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd, unsigned short flags) +void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd) { struct crec *crec; - + unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE; + if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4))) { if (crec->flags & F_HOSTS) { if (crec->addr.addr.addr4.s_addr != host_address->s_addr) syslog(LOG_WARNING, "not naming DHCP lease for %s because it clashes with an /etc/hosts entry.", host_name); + return; } else if (!(crec->flags & F_DHCP)) { - if (crec->flags & F_NEG) + if (!(crec->flags & F_NEG)) { - /* name may have been searched for before being allocated to DHCP and - therefore got a negative cache entry. If so delete it and continue. */ - cache_scan_free(host_name, NULL, 0, F_IPV4 | F_FORWARD); - goto newrec; + syslog(LOG_WARNING, "not naming DHCP lease for %s because it clashes with a cached name.", host_name); + return; } - else - syslog(LOG_WARNING, "not naming DHCP lease for %s because it clashes with a cached name.", cache_get_name(crec)); + + /* name may have been searched for before being allocated to DHCP and + therefore got a negative cache entry. If so delete it and continue. */ + cache_scan_free(host_name, NULL, 0, F_IPV4 | F_FORWARD); } - return; } - if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)) && (crec->flags & F_NEG)) - cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE); - - newrec: + if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4))) + { + if (crec->flags & F_NEG) + cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE); + else + /* avoid multiple reverse mappings */ + flags &= ~F_REVERSE; + } + if ((crec = dhcp_spare)) dhcp_spare = dhcp_spare->prev; else /* need new one */ @@ -670,7 +676,7 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t if (crec) /* malloc may fail */ { - crec->flags = F_DHCP | F_FORWARD | F_IPV4 | flags; + crec->flags = flags; if (ttd == 0) crec->flags |= F_IMMORTAL; else @@ -734,20 +740,23 @@ void dump_cache(int debug, int cache_size) cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))) ; #endif } - - } + } } -void log_query(unsigned short flags, char *name, struct all_addr *addr) + +void log_query(unsigned short flags, char *name, struct all_addr *addr, unsigned short type) { char *source; char *verb = "is"; + char types[20]; char addrbuff[ADDRSTRLEN]; - + if (!log_queries) return; + strcpy(types, " "); + if (flags & F_NEG) { if (flags & F_REVERSE) @@ -796,6 +805,47 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr) } else if (flags & F_QUERY) { + unsigned int i; + static struct { + unsigned int type; + char *name; + } typestr[] = { + { 1, "A" }, + { 2, "NS" }, + { 5, "CNAME" }, + { 6, "SOA" }, + { 10, "NULL" }, + { 11, "WKS" }, + { 12, "PTR" }, + { 13, "HINFO" }, + { 15, "MX" }, + { 16, "TXT" }, + { 22, "NSAP" }, + { 23, "NSAP_PTR" }, + { 24, "SIG" }, + { 25, "KEY" }, + { 28, "AAAA" }, + { 33, "SRV" }, + { 36, "KX" }, + { 37, "CERT" }, + { 38, "A6" }, + { 39, "DNAME" }, + { 41, "OPT" }, + { 250, "TSIG" }, + { 251, "IXFR" }, + { 252, "AXFR" }, + { 253, "MAILB" }, + { 254, "MAILA" }, + { 255, "ANY" } + }; + + if (type != 0) + { + sprintf(types, "[type=%d] ", type); + for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++) + if (typestr[i].type == type) + sprintf(types,"[%s] ", typestr[i].name); + } source = "query"; verb = "from"; } @@ -803,7 +853,7 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr) source = "cached"; if ((flags & F_FORWARD) | (flags & F_NEG)) - syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, addrbuff); + syslog(LOG_DEBUG, "%s %s%s%s %s", source, name, types, verb, addrbuff); else if (flags & F_REVERSE) syslog(LOG_DEBUG, "%s %s is %s", source, addrbuff, name); } diff --git a/src/config.h b/src/config.h index 753dfaa..6b352cc 100644 --- a/src/config.h +++ b/src/config.h @@ -12,7 +12,7 @@ /* Author's email: simon@thekelleys.org.uk */ -#define VERSION "2.11" +#define VERSION "2.12" #define FTABSIZ 150 /* max number of outstanding requests */ #define MAX_PROCS 20 /* max no children for TCP requests */ diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 4c50bfb..ce8d934 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -322,7 +322,7 @@ struct udp_dhcp_packet { /* cache.c */ void cache_init(int cachesize, int log); -void log_query(unsigned short flags, char *name, struct all_addr *addr); +void log_query(unsigned short flags, char *name, struct all_addr *addr, unsigned short type); struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr, time_t now, unsigned short prot); @@ -333,14 +333,14 @@ void cache_start_insert(void); void cache_insert(char *name, struct all_addr *addr, time_t now, unsigned long ttl, unsigned short flags); void cache_reload(int opts, char *buff, char *domain_suffix, char *addn_hosts); -void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, - time_t ttd, unsigned short flags); +void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd); void cache_unhash_dhcp(void); void dump_cache(int debug, int size); char *cache_get_name(struct crec *crecp); /* rfc1035.c */ -unsigned short extract_request(HEADER *header, unsigned int qlen, char *name); +unsigned short extract_request(HEADER *header, unsigned int qlen, + char *name, unsigned short *typep); int setup_reply(HEADER *header, unsigned int qlen, struct all_addr *addrp, unsigned short flags, unsigned long local_ttl); diff --git a/src/forward.c b/src/forward.c index b21e9fc..a7c0acb 100644 --- a/src/forward.c +++ b/src/forward.c @@ -135,7 +135,7 @@ unsigned short search_servers(struct server *servers, unsigned int options, stru *type = SERV_FOR_NODOTS; flags = 0; if (serv->flags & SERV_NO_ADDR) - flags = F_NOERR; + flags = F_NXDOMAIN; else if ((serv->flags & SERV_LITERAL_ADDRESS) && (sflag & qtype)) { flags = sflag; @@ -160,7 +160,7 @@ unsigned short search_servers(struct server *servers, unsigned int options, stru matchlen = domainlen; flags = 0; if (serv->flags & SERV_NO_ADDR) - flags = F_NOERR; + flags = F_NXDOMAIN; else if ((serv->flags & SERV_LITERAL_ADDRESS) && ((sflag | F_QUERY ) & qtype)) { flags = qtype; @@ -174,18 +174,18 @@ unsigned short search_servers(struct server *servers, unsigned int options, stru } } - if (flags & ~F_NOERR) /* flags set here means a literal found */ + if (flags & ~F_NXDOMAIN) /* flags set here means a literal found */ { if (flags & F_QUERY) - log_query(F_CONFIG | F_FORWARD | F_NEG, qdomain, NULL); + log_query(F_CONFIG | F_FORWARD | F_NEG, qdomain, NULL, 0); else - log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp); + log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp, 0); } else if (qtype && (options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.')) - flags = F_NXDOMAIN; + flags = F_NOERR; if (flags & (F_NOERR | F_NXDOMAIN)) - log_query(F_CONFIG | F_FORWARD | F_NEG | qtype | (flags & F_NXDOMAIN), qdomain, NULL); + log_query(F_CONFIG | F_FORWARD | F_NEG | qtype | (flags & F_NXDOMAIN), qdomain, NULL, 0); return flags; } @@ -202,7 +202,7 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr, int forwardall = 0, type = 0; struct all_addr *addrp = NULL; unsigned short flags = 0; - unsigned short gotname = extract_request(header, (unsigned int)plen, dnamebuff); + unsigned short gotname = extract_request(header, (unsigned int)plen, dnamebuff, NULL); struct server *start = NULL; /* may be recursion not speced or no servers available. */ @@ -282,11 +282,11 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr, strcpy(dnamebuff, "query"); if (start->addr.sa.sa_family == AF_INET) log_query(F_SERVER | F_IPV4 | F_FORWARD, dnamebuff, - (struct all_addr *)&start->addr.in.sin_addr); + (struct all_addr *)&start->addr.in.sin_addr, 0); #ifdef HAVE_IPV6 else log_query(F_SERVER | F_IPV6 | F_FORWARD, dnamebuff, - (struct all_addr *)&start->addr.in6.sin6_addr); + (struct all_addr *)&start->addr.in6.sin6_addr, 0); #endif forwarded = 1; forward->sentto = start; @@ -422,6 +422,7 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re { HEADER *header = (HEADER *)packet; union mysockaddr source_addr; + unsigned short type; struct iname *tmp; struct all_addr dst_addr; int check_dst = !(options & OPT_NOWILD); @@ -551,15 +552,15 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re } } - if (extract_request(header, (unsigned int)n, namebuff)) + if (extract_request(header, (unsigned int)n, namebuff, &type)) { if (listen->family == AF_INET) log_query(F_QUERY | F_IPV4 | F_FORWARD, namebuff, - (struct all_addr *)&source_addr.in.sin_addr); + (struct all_addr *)&source_addr.in.sin_addr, type); #ifdef HAVE_IPV6 else log_query(F_QUERY | F_IPV6 | F_FORWARD, namebuff, - (struct all_addr *)&source_addr.in6.sin6_addr); + (struct all_addr *)&source_addr.in6.sin6_addr, type); #endif } @@ -619,6 +620,7 @@ char *tcp_request(int confd, struct mx_record *mxnames, unsigned short edns_pktsz) { int size = 0, m; + unsigned short qtype, gotname; unsigned char c1, c2; /* Max TCP packet + slop */ char *packet = malloc(65536 + MAXDNAME + RRFIXEDSZ); @@ -637,7 +639,7 @@ char *tcp_request(int confd, struct mx_record *mxnames, header = (HEADER *)packet; - if (extract_request(header, (unsigned int)size, namebuff)) + if ((gotname = extract_request(header, (unsigned int)size, namebuff, &qtype))) { union mysockaddr peer_addr; socklen_t peer_len = sizeof(union mysockaddr); @@ -646,11 +648,11 @@ char *tcp_request(int confd, struct mx_record *mxnames, { if (peer_addr.sa.sa_family == AF_INET) log_query(F_QUERY | F_IPV4 | F_FORWARD, namebuff, - (struct all_addr *)&peer_addr.in.sin_addr); + (struct all_addr *)&peer_addr.in.sin_addr, qtype); #ifdef HAVE_IPV6 else log_query(F_QUERY | F_IPV6 | F_FORWARD, namebuff, - (struct all_addr *)&peer_addr.in6.sin6_addr); + (struct all_addr *)&peer_addr.in6.sin6_addr, qtype); #endif } } @@ -662,7 +664,6 @@ char *tcp_request(int confd, struct mx_record *mxnames, if (m == 0) { unsigned short flags = 0; - unsigned short gotname = extract_request(header, (unsigned int)size, namebuff); struct all_addr *addrp = NULL; int type = 0; char *domain = NULL; @@ -731,11 +732,11 @@ char *tcp_request(int confd, struct mx_record *mxnames, strcpy(namebuff, "query"); if (last_server->addr.sa.sa_family == AF_INET) log_query(F_SERVER | F_IPV4 | F_FORWARD, namebuff, - (struct all_addr *)&last_server->addr.in.sin_addr); + (struct all_addr *)&last_server->addr.in.sin_addr, 0); #ifdef HAVE_IPV6 else log_query(F_SERVER | F_IPV6 | F_FORWARD, namebuff, - (struct all_addr *)&last_server->addr.in6.sin6_addr); + (struct all_addr *)&last_server->addr.in6.sin6_addr, 0); #endif /* There's no point in updating the cache, since this process will exit and diff --git a/src/isc.c b/src/isc.c index a807eab..f96e9e3 100644 --- a/src/isc.c +++ b/src/isc.c @@ -236,12 +236,8 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname) for (lease = leases; lease; lease = lease->next) { if (lease->fqdn) - { - cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires, F_REVERSE); - cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires, 0); - } - else - cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires, F_REVERSE); + cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires); + cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires); } } diff --git a/src/lease.c b/src/lease.c index fa74df4..a5dd1c8 100644 --- a/src/lease.c +++ b/src/lease.c @@ -176,12 +176,8 @@ void lease_update_dns(void) for (lease = leases; lease; lease = lease->next) { if (lease->fqdn) - { - cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires, F_REVERSE); - cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires, 0); - } - else if (lease->hostname) - cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires, F_REVERSE); + cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires); + cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires); } dns_dirty = 0; diff --git a/src/rfc1035.c b/src/rfc1035.c index d75a68b..0c0ba8a 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -650,11 +650,14 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name, /* If the packet holds exactly one query return 1 and leave the name from the query in name. */ -unsigned short extract_request(HEADER *header,unsigned int qlen, char *name) +unsigned short extract_request(HEADER *header,unsigned int qlen, char *name, unsigned short *typep) { unsigned char *p = (unsigned char *)(header+1); int qtype, qclass; + if (typep) + *typep = 0; + if (ntohs(header->qdcount) != 1 || header->opcode != QUERY) return 0; /* must be exactly one query. */ @@ -666,6 +669,9 @@ unsigned short extract_request(HEADER *header,unsigned int qlen, char *name) if (qclass == C_IN) { + if (typep) + *typep = qtype; + if (qtype == T_A) return F_IPV4; if (qtype == T_AAAA) @@ -885,7 +891,10 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec { if ((options & OPT_FILTER) && (qtype == T_SOA || qtype == T_SRV || (qtype == T_ANY && strchr(name, '_')))) - ans = 1; + { + ans = 1; + log_query(F_CONFIG | F_NEG, name, &addr, 0); + } else { if (qtype == T_PTR || qtype == T_ANY) @@ -898,7 +907,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec ans = 1; if (!dryrun) { - log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, name, &addr); + log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, name, &addr, 0); nxdomain = 1; } } @@ -914,7 +923,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec ans = 1; if (!dryrun) { - log_query(crecp->flags & ~F_FORWARD, name, &addr); + log_query(crecp->flags & ~F_FORWARD, name, &addr, 0); auth = 0; if (crecp->flags & F_NXDOMAIN) nxdomain = 1; @@ -939,7 +948,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec ansp = add_text_record(nameoffset, ansp, ttl, 0, T_PTR, cache_get_name(crecp)); - log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr); + log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr, 0); anscount++; /* if last answer exceeded packet size, give up */ @@ -981,7 +990,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec ans = 1; if (!dryrun) { - log_query(crecp->flags, name, NULL); + log_query(crecp->flags, name, NULL, 0); auth = 0; if (crecp->flags & F_NXDOMAIN) nxdomain = 1; @@ -1001,7 +1010,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec if (!(crecp->flags & (F_HOSTS | F_DHCP))) auth = 0; - log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr); + log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr, 0); /* copy question as first part of answer (use compression) */ PUTSHORT(nameoffset | 0xc000, ansp); -- 2.39.2