From d56a604a9600c08d4a863527d549713c07f0186d Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 11 Oct 2013 14:39:03 +0100 Subject: [PATCH] CNAMEs can now point to interface names. --- CHANGELOG | 4 ++++ man/dnsmasq.8 | 2 +- src/cache.c | 53 +++++++++++++++++++++++++++++++++++++++------------ src/dnsmasq.h | 8 ++++++-- src/rfc1035.c | 24 ++++++++++++++--------- 5 files changed, 67 insertions(+), 24 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b04fbd7..3919d1d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -140,6 +140,10 @@ version 2.67 Add --quiet-dhcp, --quiet-dhcp6 and --quiet-ra. Thanks to Kevin Darbyshire-Bryant for the initial patch. + Allow A/AAAA records created by --interface-name to be the + target of --cname. Thanks to Hadmut Danisch for the + suggestion. + version 2.66 Add the ability to act as an authoritative DNS diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 6bcd2f9..123c98f 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -497,7 +497,7 @@ Return an NAPTR DNS record, as specified in RFC3403. Return a CNAME record which indicates that is really . There are significant limitations on the target; it must be a DNS name which is known to dnsmasq from /etc/hosts (or additional -hosts files), from DHCP or from another +hosts files), from DHCP, from --interface-name or from another .B --cname. If the target does not satisfy this criteria, the whole cname is ignored. The cname must be unique, but it diff --git a/src/cache.c b/src/cache.c index 6fdeba2..6247cab 100644 --- a/src/cache.c +++ b/src/cache.c @@ -24,7 +24,7 @@ static struct crec *new_chain = NULL; static int cache_inserted = 0, cache_live_freed = 0, insert_error; static union bigname *big_free = NULL; static int bignames_left, hash_size; -static int uid = 0; +static int uid = 1; #ifdef HAVE_DNSSEC static struct keydata *keyblock_free = NULL; #endif @@ -76,7 +76,7 @@ void cache_init(void) { struct crec *crecp; int i; - + bignames_left = daemon->cachesize/10; if (daemon->cachesize > 0) @@ -177,7 +177,10 @@ static void cache_free(struct crec *crecp) crecp->flags &= ~F_FORWARD; crecp->flags &= ~F_REVERSE; crecp->uid = uid++; /* invalidate CNAMES pointing to this. */ - + + if (uid == -1) + uid++; + if (cache_tail) cache_tail->next = crecp; else @@ -235,6 +238,16 @@ char *cache_get_name(struct crec *crecp) return crecp->name.sname; } +char *cache_get_cname_target(struct crec *crecp) +{ + if (crecp->addr.cname.uid != -1) + return cache_get_name(crecp->addr.cname.target.cache); + + return crecp->addr.cname.target.int_name->name; +} + + + struct crec *cache_enumerate(int init) { static int bucket; @@ -260,14 +273,14 @@ struct crec *cache_enumerate(int init) static int is_outdated_cname_pointer(struct crec *crecp) { - if (!(crecp->flags & F_CNAME)) + if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == -1) return 0; /* NB. record may be reused as DS or DNSKEY, where uid is overloaded for something completely different */ - if (crecp->addr.cname.cache && - (crecp->addr.cname.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) && - crecp->addr.cname.uid == crecp->addr.cname.cache->uid) + if (crecp->addr.cname.target.cache && + (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) && + crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid) return 0; return 1; @@ -680,9 +693,9 @@ static void add_hosts_cname(struct crec *target) if (hostname_isequal(cache_get_name(target), a->target) && (crec = whine_malloc(sizeof(struct crec)))) { - crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME; + crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME; crec->name.namep = a->alias; - crec->addr.cname.cache = target; + crec->addr.cname.target.cache = target; crec->addr.cname.uid = target->uid; cache_hash(crec); add_hosts_cname(crec); /* handle chains */ @@ -901,6 +914,8 @@ void cache_reload(void) struct hostsfile *ah; struct host_record *hr; struct name_list *nl; + struct cname *a; + struct interface_name *intr; cache_inserted = cache_live_freed = 0; @@ -927,6 +942,20 @@ void cache_reload(void) up = &cache->hash_next; } + /* Add CNAMEs to interface_names to the cache */ + for (a = daemon->cnames; a; a = a->next) + for (intr = daemon->int_names; intr; intr = intr->next) + if (hostname_isequal(a->target, intr->name)) + { + struct crec *aliasc = safe_malloc(sizeof(struct crec)); + aliasc->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG; + aliasc->name.namep = a->alias; + aliasc->addr.cname.target.int_name = intr; + aliasc->addr.cname.uid = -1; + cache_hash(aliasc); + add_hosts_cname(aliasc); /* handle chains */ + } + /* borrow the packet buffer for a temporary by-address hash */ memset(daemon->packet, 0, daemon->packet_buff_sz); revhashsz = daemon->packet_buff_sz / sizeof(struct crec *); @@ -1019,13 +1048,13 @@ static void add_dhcp_cname(struct crec *target, time_t ttd) if (aliasc) { - aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME; + aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME | F_CONFIG; if (ttd == 0) aliasc->flags |= F_IMMORTAL; else aliasc->ttd = ttd; aliasc->name.namep = a->alias; - aliasc->addr.cname.cache = target; + aliasc->addr.cname.target.cache = target; aliasc->addr.cname.uid = target->uid; cache_hash(aliasc); add_dhcp_cname(aliasc, ttd); @@ -1173,7 +1202,7 @@ void dump_cache(time_t now) { a = ""; if (!is_outdated_cname_pointer(cache)) - a = cache_get_name(cache->addr.cname.cache); + a = cache_get_cname_target(cache); } #ifdef HAVE_DNSSEC else if (cache->flags & F_DNSKEY) diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 24676ed..272d0a2 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -337,8 +337,11 @@ struct crec { union { struct all_addr addr; struct { - struct crec *cache; - int uid; + union { + struct crec *cache; + struct interface_name *int_name; + } target; + int uid; /* -1 if union is interface-name */ } cname; struct { struct keydata *keydata; @@ -941,6 +944,7 @@ struct in_addr a_record_from_hosts(char *name, time_t now); void cache_unhash_dhcp(void); void dump_cache(time_t now); char *cache_get_name(struct crec *crecp); +char *cache_get_cname_target(struct crec *crecp); struct crec *cache_enumerate(int init); #ifdef HAVE_DNSSEC struct keydata *keydata_alloc(char *data, size_t len); diff --git a/src/rfc1035.c b/src/rfc1035.c index 5e7fe95..7c1c30d 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -1042,10 +1042,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD); if (newc) { - newc->addr.cname.cache = NULL; + newc->addr.cname.target.cache = NULL; if (cpp) { - cpp->addr.cname.cache = newc; + cpp->addr.cname.target.cache = newc; cpp->addr.cname.uid = newc->uid; } } @@ -1085,7 +1085,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD); if (newc && cpp) { - cpp->addr.cname.cache = newc; + cpp->addr.cname.target.cache = newc; cpp->addr.cname.uid = newc->uid; } cpp = NULL; @@ -1112,7 +1112,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags); if (newc && cpp) { - cpp->addr.cname.cache = newc; + cpp->addr.cname.target.cache = newc; cpp->addr.cname.uid = newc->uid; } } @@ -1720,7 +1720,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, } /* interface name stuff */ - + intname_restart: for (intr = daemon->int_names; intr; intr = intr->next) if (hostname_isequal(name, intr->name)) break; @@ -1784,17 +1784,23 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, if (crecp->flags & F_CNAME) { + char *cname_target = cache_get_cname_target(crecp); + if (!dryrun) { log_query(crecp->flags, name, NULL, record_source(crecp->uid)); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, - T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache))) + T_CNAME, C_IN, "d", cname_target)) anscount++; } - strcpy(name, cache_get_name(crecp->addr.cname.cache)); - goto cname_restart; + strcpy(name, cname_target); + /* check if target interface_name */ + if (crecp->addr.cname.uid == -1) + goto intname_restart; + else + goto cname_restart; } if (crecp->flags & F_NEG) @@ -1856,7 +1862,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, log_query(crecp->flags, name, NULL, record_source(crecp->uid)); if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crec_ttl(crecp, now), &nameoffset, - T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache))) + T_CNAME, C_IN, "d", cache_get_cname_target(crecp))) anscount++; } }