Commit d56a604a authored by Simon Kelley's avatar Simon Kelley

CNAMEs can now point to interface names.

parent 8c0b73d3
...@@ -140,6 +140,10 @@ version 2.67 ...@@ -140,6 +140,10 @@ version 2.67
Add --quiet-dhcp, --quiet-dhcp6 and --quiet-ra. Thanks to Add --quiet-dhcp, --quiet-dhcp6 and --quiet-ra. Thanks to
Kevin Darbyshire-Bryant for the initial patch. 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 version 2.66
Add the ability to act as an authoritative DNS Add the ability to act as an authoritative DNS
......
...@@ -497,7 +497,7 @@ Return an NAPTR DNS record, as specified in RFC3403. ...@@ -497,7 +497,7 @@ Return an NAPTR DNS record, as specified in RFC3403.
Return a CNAME record which indicates that <cname> is really Return a CNAME record which indicates that <cname> is really
<target>. There are significant limitations on the target; it must be a <target>. There are significant limitations on the target; it must be a
DNS name which is known to dnsmasq from /etc/hosts (or additional 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. .B --cname.
If the target does not satisfy this If the target does not satisfy this
criteria, the whole cname is ignored. The cname must be unique, but it criteria, the whole cname is ignored. The cname must be unique, but it
......
...@@ -24,7 +24,7 @@ static struct crec *new_chain = NULL; ...@@ -24,7 +24,7 @@ static struct crec *new_chain = NULL;
static int cache_inserted = 0, cache_live_freed = 0, insert_error; static int cache_inserted = 0, cache_live_freed = 0, insert_error;
static union bigname *big_free = NULL; static union bigname *big_free = NULL;
static int bignames_left, hash_size; static int bignames_left, hash_size;
static int uid = 0; static int uid = 1;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
static struct keydata *keyblock_free = NULL; static struct keydata *keyblock_free = NULL;
#endif #endif
...@@ -178,6 +178,9 @@ static void cache_free(struct crec *crecp) ...@@ -178,6 +178,9 @@ static void cache_free(struct crec *crecp)
crecp->flags &= ~F_REVERSE; crecp->flags &= ~F_REVERSE;
crecp->uid = uid++; /* invalidate CNAMES pointing to this. */ crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
if (uid == -1)
uid++;
if (cache_tail) if (cache_tail)
cache_tail->next = crecp; cache_tail->next = crecp;
else else
...@@ -235,6 +238,16 @@ char *cache_get_name(struct crec *crecp) ...@@ -235,6 +238,16 @@ char *cache_get_name(struct crec *crecp)
return crecp->name.sname; 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) struct crec *cache_enumerate(int init)
{ {
static int bucket; static int bucket;
...@@ -260,14 +273,14 @@ struct crec *cache_enumerate(int init) ...@@ -260,14 +273,14 @@ struct crec *cache_enumerate(int init)
static int is_outdated_cname_pointer(struct crec *crecp) 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; return 0;
/* NB. record may be reused as DS or DNSKEY, where uid is /* NB. record may be reused as DS or DNSKEY, where uid is
overloaded for something completely different */ overloaded for something completely different */
if (crecp->addr.cname.cache && if (crecp->addr.cname.target.cache &&
(crecp->addr.cname.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) && (crecp->addr.cname.target.cache->flags & (F_IPV4 | F_IPV6 | F_CNAME)) &&
crecp->addr.cname.uid == crecp->addr.cname.cache->uid) crecp->addr.cname.uid == crecp->addr.cname.target.cache->uid)
return 0; return 0;
return 1; return 1;
...@@ -680,9 +693,9 @@ static void add_hosts_cname(struct crec *target) ...@@ -680,9 +693,9 @@ static void add_hosts_cname(struct crec *target)
if (hostname_isequal(cache_get_name(target), a->target) && if (hostname_isequal(cache_get_name(target), a->target) &&
(crec = whine_malloc(sizeof(struct crec)))) (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->name.namep = a->alias;
crec->addr.cname.cache = target; crec->addr.cname.target.cache = target;
crec->addr.cname.uid = target->uid; crec->addr.cname.uid = target->uid;
cache_hash(crec); cache_hash(crec);
add_hosts_cname(crec); /* handle chains */ add_hosts_cname(crec); /* handle chains */
...@@ -901,6 +914,8 @@ void cache_reload(void) ...@@ -901,6 +914,8 @@ void cache_reload(void)
struct hostsfile *ah; struct hostsfile *ah;
struct host_record *hr; struct host_record *hr;
struct name_list *nl; struct name_list *nl;
struct cname *a;
struct interface_name *intr;
cache_inserted = cache_live_freed = 0; cache_inserted = cache_live_freed = 0;
...@@ -927,6 +942,20 @@ void cache_reload(void) ...@@ -927,6 +942,20 @@ void cache_reload(void)
up = &cache->hash_next; 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 */ /* borrow the packet buffer for a temporary by-address hash */
memset(daemon->packet, 0, daemon->packet_buff_sz); memset(daemon->packet, 0, daemon->packet_buff_sz);
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *); revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
...@@ -1019,13 +1048,13 @@ static void add_dhcp_cname(struct crec *target, time_t ttd) ...@@ -1019,13 +1048,13 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
if (aliasc) 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) if (ttd == 0)
aliasc->flags |= F_IMMORTAL; aliasc->flags |= F_IMMORTAL;
else else
aliasc->ttd = ttd; aliasc->ttd = ttd;
aliasc->name.namep = a->alias; aliasc->name.namep = a->alias;
aliasc->addr.cname.cache = target; aliasc->addr.cname.target.cache = target;
aliasc->addr.cname.uid = target->uid; aliasc->addr.cname.uid = target->uid;
cache_hash(aliasc); cache_hash(aliasc);
add_dhcp_cname(aliasc, ttd); add_dhcp_cname(aliasc, ttd);
...@@ -1173,7 +1202,7 @@ void dump_cache(time_t now) ...@@ -1173,7 +1202,7 @@ void dump_cache(time_t now)
{ {
a = ""; a = "";
if (!is_outdated_cname_pointer(cache)) if (!is_outdated_cname_pointer(cache))
a = cache_get_name(cache->addr.cname.cache); a = cache_get_cname_target(cache);
} }
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
else if (cache->flags & F_DNSKEY) else if (cache->flags & F_DNSKEY)
......
...@@ -337,8 +337,11 @@ struct crec { ...@@ -337,8 +337,11 @@ struct crec {
union { union {
struct all_addr addr; struct all_addr addr;
struct { struct {
union {
struct crec *cache; struct crec *cache;
int uid; struct interface_name *int_name;
} target;
int uid; /* -1 if union is interface-name */
} cname; } cname;
struct { struct {
struct keydata *keydata; struct keydata *keydata;
...@@ -941,6 +944,7 @@ struct in_addr a_record_from_hosts(char *name, time_t now); ...@@ -941,6 +944,7 @@ struct in_addr a_record_from_hosts(char *name, time_t now);
void cache_unhash_dhcp(void); void cache_unhash_dhcp(void);
void dump_cache(time_t now); void dump_cache(time_t now);
char *cache_get_name(struct crec *crecp); char *cache_get_name(struct crec *crecp);
char *cache_get_cname_target(struct crec *crecp);
struct crec *cache_enumerate(int init); struct crec *cache_enumerate(int init);
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
struct keydata *keydata_alloc(char *data, size_t len); struct keydata *keydata_alloc(char *data, size_t len);
......
...@@ -1042,10 +1042,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t ...@@ -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); newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
if (newc) if (newc)
{ {
newc->addr.cname.cache = NULL; newc->addr.cname.target.cache = NULL;
if (cpp) if (cpp)
{ {
cpp->addr.cname.cache = newc; cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid; cpp->addr.cname.uid = newc->uid;
} }
} }
...@@ -1085,7 +1085,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t ...@@ -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); newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
if (newc && cpp) if (newc && cpp)
{ {
cpp->addr.cname.cache = newc; cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid; cpp->addr.cname.uid = newc->uid;
} }
cpp = NULL; cpp = NULL;
...@@ -1112,7 +1112,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t ...@@ -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); newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
if (newc && cpp) if (newc && cpp)
{ {
cpp->addr.cname.cache = newc; cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid; cpp->addr.cname.uid = newc->uid;
} }
} }
...@@ -1720,7 +1720,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1720,7 +1720,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
} }
/* interface name stuff */ /* interface name stuff */
intname_restart:
for (intr = daemon->int_names; intr; intr = intr->next) for (intr = daemon->int_names; intr; intr = intr->next)
if (hostname_isequal(name, intr->name)) if (hostname_isequal(name, intr->name))
break; break;
...@@ -1784,16 +1784,22 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1784,16 +1784,22 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (crecp->flags & F_CNAME) if (crecp->flags & F_CNAME)
{ {
char *cname_target = cache_get_cname_target(crecp);
if (!dryrun) if (!dryrun)
{ {
log_query(crecp->flags, name, NULL, record_source(crecp->uid)); log_query(crecp->flags, name, NULL, record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset, 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++; anscount++;
} }
strcpy(name, cache_get_name(crecp->addr.cname.cache)); strcpy(name, cname_target);
/* check if target interface_name */
if (crecp->addr.cname.uid == -1)
goto intname_restart;
else
goto cname_restart; goto cname_restart;
} }
...@@ -1856,7 +1862,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -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)); log_query(crecp->flags, name, NULL, record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset, 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++; anscount++;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment