mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
First cut at zone transfer.
This commit is contained in:
169
src/auth.c
169
src/auth.c
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
|
||||
static struct subnet *filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
|
||||
{
|
||||
struct subnet *subnet;
|
||||
@@ -44,6 +45,31 @@ static struct subnet *filter_zone(struct auth_zone *zone, int flag, struct all_a
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int in_zone(struct auth_zone *zone, char *name, char **cut)
|
||||
{
|
||||
size_t namelen = strlen(name);
|
||||
size_t domainlen = strlen(zone->domain);
|
||||
|
||||
if (cut)
|
||||
*cut = NULL;
|
||||
|
||||
if (namelen >= domainlen &&
|
||||
hostname_isequal(zone->domain, &name[namelen - domainlen]))
|
||||
{
|
||||
|
||||
if (namelen == domainlen)
|
||||
return 1;
|
||||
|
||||
if (name[namelen - domainlen - 1] == '.')
|
||||
{
|
||||
if (cut)
|
||||
*cut = &name[namelen - domainlen - 1];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now)
|
||||
@@ -51,12 +77,13 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp;
|
||||
int qtype, qclass;
|
||||
unsigned int nameoffset;
|
||||
int nameoffset, axfroffset = 0;
|
||||
int q, anscount = 0, authcount = 0;
|
||||
struct crec *crecp;
|
||||
int auth = 1, trunc = 0, nxdomain = 1, soa = 0, ns = 0;
|
||||
int auth = 1, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
|
||||
struct auth_zone *zone = NULL;
|
||||
struct subnet *subnet = NULL;
|
||||
char *cut;
|
||||
|
||||
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
|
||||
return 0;
|
||||
@@ -70,7 +97,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
size_t domainlen, namelen;
|
||||
unsigned short flag = 0;
|
||||
int found = 0;
|
||||
struct mx_srv_record *rec, *move, **up;
|
||||
@@ -92,7 +118,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (qclass != C_IN)
|
||||
continue;
|
||||
|
||||
|
||||
if (qtype == T_PTR)
|
||||
{
|
||||
if (!(flag = in_arpa_name_2_addr(name, &addr)))
|
||||
@@ -107,9 +133,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
domainlen = strlen(zone->domain);
|
||||
|
||||
|
||||
if (flag == F_IPV4)
|
||||
{
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
@@ -123,10 +147,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (intr)
|
||||
{
|
||||
namelen = strlen(intr->name);
|
||||
|
||||
if (namelen >= domainlen && hostname_isequal(zone->domain, &intr->name[namelen - domainlen]) &&
|
||||
(namelen == domainlen || intr->name[namelen - domainlen - 1] == '.'))
|
||||
if (in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
@@ -158,17 +179,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
T_PTR, C_IN, "d", name))
|
||||
anscount++;
|
||||
}
|
||||
else if (crecp->flags & (F_DHCP | F_HOSTS))
|
||||
else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))
|
||||
{
|
||||
namelen = strlen(name);
|
||||
|
||||
if (namelen > domainlen + 1 &&
|
||||
name[namelen - domainlen - 1] != '.')
|
||||
continue;
|
||||
if (namelen < domainlen ||
|
||||
!hostname_isequal(zone->domain, &name[namelen - domainlen]))
|
||||
continue; /* wrong domain */
|
||||
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -188,16 +200,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
cname_restart:
|
||||
namelen = strlen(name);
|
||||
|
||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||
{
|
||||
domainlen = strlen(zone->domain);
|
||||
if (namelen >= domainlen &&
|
||||
hostname_isequal(zone->domain, &name[namelen - domainlen]) &&
|
||||
(namelen == domainlen || name[namelen - domainlen - 1] == '.'))
|
||||
break;
|
||||
}
|
||||
if (in_zone(zone, name, &cut))
|
||||
break;
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
@@ -340,14 +345,23 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
flag = F_IPV6;
|
||||
#endif
|
||||
|
||||
if (qtype == T_SOA && namelen == domainlen)
|
||||
if (qtype == T_SOA && !cut)
|
||||
{
|
||||
soa = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
|
||||
}
|
||||
|
||||
if (qtype == T_NS && namelen == domainlen)
|
||||
if (qtype == T_AXFR && !cut)
|
||||
{
|
||||
soa = 1; /* inhibits auth section */
|
||||
axfr = 1;
|
||||
found = 1;
|
||||
axfroffset = nameoffset;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
|
||||
}
|
||||
|
||||
if (qtype == T_NS && !cut)
|
||||
{
|
||||
ns = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
@@ -355,9 +369,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
|
||||
if (!option_bool(OPT_DHCP_FQDN) && namelen > domainlen + 1)
|
||||
if (!option_bool(OPT_DHCP_FQDN) && cut)
|
||||
{
|
||||
name[namelen - domainlen - 1] = 0; /* remove domain part */
|
||||
*cut = 0; /* remove domain part */
|
||||
|
||||
if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
|
||||
{
|
||||
@@ -367,9 +381,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
nxdomain = 0;
|
||||
if ((crecp->flags & flag) && filter_zone(zone, flag, &(crecp->addr.addr)))
|
||||
{
|
||||
name[namelen - domainlen - 1] = '.'; /* restore domain part */
|
||||
*cut = '.'; /* restore domain part */
|
||||
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
|
||||
name[namelen - domainlen - 1] = 0; /* remove domain part */
|
||||
*cut = 0; /* remove domain part */
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
@@ -379,7 +393,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
|
||||
}
|
||||
|
||||
name[namelen - domainlen - 1] = '.'; /* restore domain part */
|
||||
*cut = '.'; /* restore domain part */
|
||||
}
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
|
||||
@@ -408,11 +422,16 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
/* Add auth section */
|
||||
if (auth)
|
||||
{
|
||||
char *authname;
|
||||
|
||||
if (!subnet)
|
||||
name = zone->domain;
|
||||
authname = zone->domain;
|
||||
else
|
||||
{
|
||||
/* handle NS and SOA for PTR records */
|
||||
|
||||
authname = name;
|
||||
|
||||
if (!subnet->is6)
|
||||
{
|
||||
in_addr_t a = ntohl(subnet->addr4.s_addr) >> 8;
|
||||
@@ -447,7 +466,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
/* handle NS and SOA in auth section or for explicit queries */
|
||||
if ((anscount != 0 || ns) &&
|
||||
add_resource_record(header, limit, &trunc, 0, &ansp,
|
||||
daemon->auth_ttl, NULL, T_NS, C_IN, "d", name, daemon->authserver))
|
||||
daemon->auth_ttl, NULL, T_NS, C_IN, "d", authname, daemon->authserver))
|
||||
{
|
||||
if (ns)
|
||||
anscount++;
|
||||
@@ -458,7 +477,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if ((anscount == 0 || soa) &&
|
||||
add_resource_record(header, limit, &trunc, 0, &ansp,
|
||||
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
|
||||
name, daemon->authserver, daemon->hostmaster,
|
||||
authname, daemon->authserver, daemon->hostmaster,
|
||||
daemon->soa_sn, daemon->soa_refresh,
|
||||
daemon->soa_retry, daemon->soa_expiry,
|
||||
daemon->auth_ttl))
|
||||
@@ -468,6 +487,74 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
else
|
||||
authcount++;
|
||||
}
|
||||
|
||||
if (axfr)
|
||||
{
|
||||
cache_enumerate(1);
|
||||
while ((crecp = cache_enumerate(0)))
|
||||
{
|
||||
if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
|
||||
!(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
|
||||
(crecp->flags & F_FORWARD))
|
||||
{
|
||||
if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
|
||||
{
|
||||
char *cache_name = cache_get_name(crecp);
|
||||
if (!strchr(cache_name, '.') && filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))
|
||||
{
|
||||
qtype = T_A;
|
||||
#ifdef HAVE_IPV6
|
||||
if (crecp->flags & F_IPV6)
|
||||
qtype = T_AAAA;
|
||||
#endif
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
(crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
|
||||
{
|
||||
strcpy(name, cache_get_name(crecp));
|
||||
if (in_zone(zone, name, &cut) && filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))
|
||||
{
|
||||
qtype = T_A;
|
||||
#ifdef HAVE_IPV6
|
||||
if (crecp->flags & F_IPV6)
|
||||
qtype = T_AAAA;
|
||||
#endif
|
||||
if (cut)
|
||||
{
|
||||
*cut = 0;
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
(crecp->flags & F_IPV4) ? "4" : "6", name, &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
(crecp->flags & F_IPV4) ? "4" : "6", &crecp->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* repeat SOA as last record */
|
||||
if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
|
||||
daemon->authserver, daemon->hostmaster,
|
||||
daemon->soa_sn, daemon->soa_refresh,
|
||||
daemon->soa_retry, daemon->soa_expiry,
|
||||
daemon->auth_ttl))
|
||||
anscount++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* done all questions, set up header and return length of result */
|
||||
@@ -495,6 +582,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
23
src/cache.c
23
src/cache.c
@@ -235,6 +235,29 @@ char *cache_get_name(struct crec *crecp)
|
||||
return crecp->name.sname;
|
||||
}
|
||||
|
||||
struct crec *cache_enumerate(int init)
|
||||
{
|
||||
static int bucket;
|
||||
static struct crec *cache;
|
||||
|
||||
if (init)
|
||||
{
|
||||
bucket = 0;
|
||||
cache = NULL;
|
||||
}
|
||||
else if (cache && cache->hash_next)
|
||||
cache = cache->hash_next;
|
||||
else
|
||||
{
|
||||
cache = NULL;
|
||||
while (bucket < hash_size)
|
||||
if ((cache = hash_table[bucket++]))
|
||||
break;
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
static int is_outdated_cname_pointer(struct crec *crecp)
|
||||
{
|
||||
if (!(crecp->flags & F_CNAME))
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#define T_OPT 41
|
||||
#define T_TKEY 249
|
||||
#define T_TSIG 250
|
||||
#define T_AXFR 252
|
||||
#define T_MAILB 253
|
||||
#define T_ANY 255
|
||||
|
||||
|
||||
@@ -870,6 +870,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);
|
||||
struct crec *cache_enumerate(int init);
|
||||
char *get_domain(struct in_addr addr);
|
||||
#ifdef HAVE_IPV6
|
||||
char *get_domain6(struct in6_addr *addr);
|
||||
@@ -899,7 +900,7 @@ size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
unsigned int nameoffset, unsigned char **pp, unsigned long ttl,
|
||||
int nameoffset, unsigned char **pp, unsigned long ttl,
|
||||
unsigned int *offset, unsigned short type, unsigned short class, char *format, ...);
|
||||
unsigned char *skip_questions(struct dns_header *header, size_t plen);
|
||||
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
|
||||
@@ -1185,7 +1185,7 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -1200,14 +1200,19 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, uns
|
||||
|
||||
va_start(ap, format); /* make ap point to 1st unamed argument */
|
||||
|
||||
if (nameoffset != 0)
|
||||
if (nameoffset > 0)
|
||||
{
|
||||
PUTSHORT(nameoffset | 0xc000, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
p = do_rfc1035_name(p, va_arg(ap, char *));
|
||||
*p++ = 0;
|
||||
if (nameoffset < 0)
|
||||
{
|
||||
PUTSHORT(-nameoffset | 0xc000, p);
|
||||
}
|
||||
else
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
PUTSHORT(type, p);
|
||||
@@ -1312,7 +1317,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
unsigned char *p, *ansp, *pheader;
|
||||
int qtype, qclass;
|
||||
struct all_addr addr;
|
||||
unsigned int nameoffset;
|
||||
int nameoffset;
|
||||
unsigned short flag;
|
||||
int q, ans, anscount = 0, addncount = 0;
|
||||
int dryrun = 0, sec_reqd = 0;
|
||||
|
||||
Reference in New Issue
Block a user