mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Generalise locally-configured CNAME handling.
It's now possible for the target of a CNAME to be any locally configured RR or even point to a non-existent RR.
This commit is contained in:
@@ -603,12 +603,9 @@ Return a CAA DNS record, as specified in RFC6844.
|
|||||||
.TP
|
.TP
|
||||||
.B --cname=<cname>,[<cname>,]<target>[,<TTL>]
|
.B --cname=<cname>,[<cname>,]<target>[,<TTL>]
|
||||||
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 is a significant limitation on the target; it must be a
|
||||||
DNS name which is known to dnsmasq from /etc/hosts (or additional
|
DNS record which is known to dnsmasq and NOT a DNS record which comes from
|
||||||
hosts files), from DHCP, from \fB--interface-name\fP or from another
|
an upstream server. The cname must be unique, but it
|
||||||
.B --cname.
|
|
||||||
If the target does not satisfy this
|
|
||||||
criteria, the whole cname is ignored. The cname must be unique, but it
|
|
||||||
is permissible to have more than one cname pointing to the same target. Indeed
|
is permissible to have more than one cname pointing to the same target. Indeed
|
||||||
it's possible to declare multiple cnames to a target in a single line, like so:
|
it's possible to declare multiple cnames to a target in a single line, like so:
|
||||||
.B --cname=cname1,cname2,target
|
.B --cname=cname1,cname2,target
|
||||||
|
|||||||
89
src/cache.c
89
src/cache.c
@@ -276,10 +276,10 @@ char *cache_get_name(struct crec *crecp)
|
|||||||
|
|
||||||
char *cache_get_cname_target(struct crec *crecp)
|
char *cache_get_cname_target(struct crec *crecp)
|
||||||
{
|
{
|
||||||
if (crecp->addr.cname.uid != SRC_INTERFACE)
|
if (crecp->addr.cname.uid != SRC_PTR)
|
||||||
return cache_get_name(crecp->addr.cname.target.cache);
|
return cache_get_name(crecp->addr.cname.target.cache);
|
||||||
|
|
||||||
return crecp->addr.cname.target.int_name->name;
|
return crecp->addr.cname.target.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -309,7 +309,7 @@ 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) || crecp->addr.cname.uid == SRC_INTERFACE)
|
if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_PTR)
|
||||||
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
|
||||||
@@ -513,7 +513,7 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho
|
|||||||
{
|
{
|
||||||
/* We're trying to insert a record over one from
|
/* We're trying to insert a record over one from
|
||||||
/etc/hosts or DHCP, or other config. If the
|
/etc/hosts or DHCP, or other config. If the
|
||||||
existing record is for an A or AAAA and
|
existing record is for an A or AAAA or CNAME and
|
||||||
the record we're trying to insert is the same,
|
the record we're trying to insert is the same,
|
||||||
just drop the insert, but don't error the whole process. */
|
just drop the insert, but don't error the whole process. */
|
||||||
if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
|
if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD) && addr)
|
||||||
@@ -956,47 +956,19 @@ struct crec *cache_find_by_addr(struct crec *crecp, union all_addr *addr,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_hosts_cname(struct crec *target)
|
|
||||||
{
|
|
||||||
struct crec *crec;
|
|
||||||
struct cname *a;
|
|
||||||
|
|
||||||
for (a = daemon->cnames; a; a = a->next)
|
|
||||||
if (a->alias[1] != '*' &&
|
|
||||||
hostname_isequal(cache_get_name(target), a->target) &&
|
|
||||||
(crec = whine_malloc(SIZEOF_POINTER_CREC)))
|
|
||||||
{
|
|
||||||
crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
|
|
||||||
crec->ttd = a->ttl;
|
|
||||||
crec->name.namep = a->alias;
|
|
||||||
crec->addr.cname.target.cache = target;
|
|
||||||
next_uid(target);
|
|
||||||
crec->addr.cname.uid = target->uid;
|
|
||||||
crec->uid = UID_NONE;
|
|
||||||
cache_hash(crec);
|
|
||||||
make_non_terminals(crec);
|
|
||||||
|
|
||||||
add_hosts_cname(crec); /* handle chains */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrlen,
|
static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrlen,
|
||||||
unsigned int index, struct crec **rhash, int hashsz)
|
unsigned int index, struct crec **rhash, int hashsz)
|
||||||
{
|
{
|
||||||
struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
|
struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
|
||||||
int i, nameexists = 0;
|
int i;
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
|
|
||||||
/* Remove duplicates in hosts files. */
|
/* Remove duplicates in hosts files. */
|
||||||
if (lookup && (lookup->flags & F_HOSTS))
|
if (lookup && (lookup->flags & F_HOSTS) && memcmp(&lookup->addr, addr, addrlen) == 0)
|
||||||
{
|
|
||||||
nameexists = 1;
|
|
||||||
if (memcmp(&lookup->addr, addr, addrlen) == 0)
|
|
||||||
{
|
{
|
||||||
free(cache);
|
free(cache);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Ensure there is only one address -> name mapping (first one trumps)
|
/* Ensure there is only one address -> name mapping (first one trumps)
|
||||||
We do this by steam here, The entries are kept in hash chains, linked
|
We do this by steam here, The entries are kept in hash chains, linked
|
||||||
@@ -1048,10 +1020,6 @@ static void add_hosts_entry(struct crec *cache, union all_addr *addr, int addrle
|
|||||||
memcpy(&cache->addr, addr, addrlen);
|
memcpy(&cache->addr, addr, addrlen);
|
||||||
cache_hash(cache);
|
cache_hash(cache);
|
||||||
make_non_terminals(cache);
|
make_non_terminals(cache);
|
||||||
|
|
||||||
/* don't need to do alias stuff for second and subsequent addresses. */
|
|
||||||
if (!nameexists)
|
|
||||||
add_hosts_cname(cache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int eatspace(FILE *f)
|
static int eatspace(FILE *f)
|
||||||
@@ -1211,7 +1179,6 @@ void cache_reload(void)
|
|||||||
struct host_record *hr;
|
struct host_record *hr;
|
||||||
struct name_list *nl;
|
struct name_list *nl;
|
||||||
struct cname *a;
|
struct cname *a;
|
||||||
struct interface_name *intr;
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
struct ds_config *ds;
|
struct ds_config *ds;
|
||||||
#endif
|
#endif
|
||||||
@@ -1244,22 +1211,19 @@ void cache_reload(void)
|
|||||||
up = &cache->hash_next;
|
up = &cache->hash_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add CNAMEs to interface_names to the cache */
|
/* Add locally-configured CNAMEs to the cache */
|
||||||
for (a = daemon->cnames; a; a = a->next)
|
for (a = daemon->cnames; a; a = a->next)
|
||||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
|
||||||
if (a->alias[1] != '*' &&
|
if (a->alias[1] != '*' &&
|
||||||
hostname_isequal(a->target, intr->name) &&
|
|
||||||
((cache = whine_malloc(SIZEOF_POINTER_CREC))))
|
((cache = whine_malloc(SIZEOF_POINTER_CREC))))
|
||||||
{
|
{
|
||||||
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
|
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
|
||||||
cache->ttd = a->ttl;
|
cache->ttd = a->ttl;
|
||||||
cache->name.namep = a->alias;
|
cache->name.namep = a->alias;
|
||||||
cache->addr.cname.target.int_name = intr;
|
cache->addr.cname.target.name = a->target;
|
||||||
cache->addr.cname.uid = SRC_INTERFACE;
|
cache->addr.cname.uid = SRC_PTR;
|
||||||
cache->uid = UID_NONE;
|
cache->uid = UID_NONE;
|
||||||
cache_hash(cache);
|
cache_hash(cache);
|
||||||
make_non_terminals(cache);
|
make_non_terminals(cache);
|
||||||
add_hosts_cname(cache); /* handle chains */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
@@ -1364,39 +1328,6 @@ void cache_unhash_dhcp(void)
|
|||||||
up = &cache->hash_next;
|
up = &cache->hash_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_dhcp_cname(struct crec *target, time_t ttd)
|
|
||||||
{
|
|
||||||
struct crec *aliasc;
|
|
||||||
struct cname *a;
|
|
||||||
|
|
||||||
for (a = daemon->cnames; a; a = a->next)
|
|
||||||
if (a->alias[1] != '*' &&
|
|
||||||
hostname_isequal(cache_get_name(target), a->target))
|
|
||||||
{
|
|
||||||
if ((aliasc = dhcp_spare))
|
|
||||||
dhcp_spare = dhcp_spare->next;
|
|
||||||
else /* need new one */
|
|
||||||
aliasc = whine_malloc(SIZEOF_POINTER_CREC);
|
|
||||||
|
|
||||||
if (aliasc)
|
|
||||||
{
|
|
||||||
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.target.cache = target;
|
|
||||||
next_uid(target);
|
|
||||||
aliasc->addr.cname.uid = target->uid;
|
|
||||||
aliasc->uid = UID_NONE;
|
|
||||||
cache_hash(aliasc);
|
|
||||||
make_non_terminals(aliasc);
|
|
||||||
add_dhcp_cname(aliasc, ttd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cache_add_dhcp_entry(char *host_name, int prot,
|
void cache_add_dhcp_entry(char *host_name, int prot,
|
||||||
union all_addr *host_address, time_t ttd)
|
union all_addr *host_address, time_t ttd)
|
||||||
{
|
{
|
||||||
@@ -1479,8 +1410,6 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
|||||||
crec->uid = UID_NONE;
|
crec->uid = UID_NONE;
|
||||||
cache_hash(crec);
|
cache_hash(crec);
|
||||||
make_non_terminals(crec);
|
make_non_terminals(crec);
|
||||||
|
|
||||||
add_dhcp_cname(crec, ttd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -287,9 +287,9 @@ union all_addr {
|
|||||||
struct {
|
struct {
|
||||||
union {
|
union {
|
||||||
struct crec *cache;
|
struct crec *cache;
|
||||||
struct interface_name *int_name;
|
char *name;
|
||||||
} target;
|
} target;
|
||||||
unsigned int uid; /* 0 if union is interface-name */
|
unsigned int uid; /* 0 if union is char * */
|
||||||
} cname;
|
} cname;
|
||||||
struct {
|
struct {
|
||||||
struct blockdata *keydata;
|
struct blockdata *keydata;
|
||||||
@@ -483,10 +483,10 @@ struct crec {
|
|||||||
|
|
||||||
#define UID_NONE 0
|
#define UID_NONE 0
|
||||||
/* Values of uid in crecs with F_CONFIG bit set. */
|
/* Values of uid in crecs with F_CONFIG bit set. */
|
||||||
/* cname to uid SRC_INTERFACE are to interface names,
|
/* cname to uid SRC_PTR are to locally-configured CNAME
|
||||||
so use UID_NONE for that to eliminate clashes with
|
so use UID_NONE for that to
|
||||||
any other uid */
|
eliminate clashes with any other uid */
|
||||||
#define SRC_INTERFACE UID_NONE
|
#define SRC_PTR UID_NONE
|
||||||
#define SRC_CONFIG 1
|
#define SRC_CONFIG 1
|
||||||
#define SRC_HOSTS 2
|
#define SRC_HOSTS 2
|
||||||
#define SRC_AH 3
|
#define SRC_AH 3
|
||||||
|
|||||||
@@ -788,7 +788,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
if (newc)
|
if (newc)
|
||||||
{
|
{
|
||||||
newc->addr.cname.target.cache = NULL;
|
newc->addr.cname.target.cache = NULL;
|
||||||
/* anything other than zero, to avoid being mistaken for CNAME to interface-name */
|
/* anything other than zero, to avoid being mistaken for a local CNAME */
|
||||||
newc->addr.cname.uid = 1;
|
newc->addr.cname.uid = 1;
|
||||||
if (cpp)
|
if (cpp)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user