Commit e1ff419c authored by Simon Kelley's avatar Simon Kelley

Complete AXFR support

parent ee86ce68
...@@ -84,6 +84,12 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n ...@@ -84,6 +84,12 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
struct auth_zone *zone = NULL; struct auth_zone *zone = NULL;
struct subnet *subnet = NULL; struct subnet *subnet = NULL;
char *cut; char *cut;
struct mx_srv_record *rec, *move, **up;
struct txt_record *txt;
struct interface_name *intr;
struct naptr *na;
struct all_addr addr;
struct cname *a;
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
return 0; return 0;
...@@ -99,12 +105,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n ...@@ -99,12 +105,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
{ {
unsigned short flag = 0; unsigned short flag = 0;
int found = 0; int found = 0;
struct mx_srv_record *rec, *move, **up;
struct txt_record *txt;
struct interface_name *intr;
struct naptr *na;
struct all_addr addr;
struct cname *a;
/* save pointer to name for copying into answers */ /* save pointer to name for copying into answers */
nameoffset = p - (unsigned char *)header; nameoffset = p - (unsigned char *)header;
...@@ -345,29 +345,32 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n ...@@ -345,29 +345,32 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
flag = F_IPV6; flag = F_IPV6;
#endif #endif
if (qtype == T_SOA && !cut) if (!cut)
{
nxdomain = 0;
if (qtype == T_SOA)
{ {
soa = 1; /* inhibits auth section */ soa = 1; /* inhibits auth section */
found = 1; found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>"); log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
} }
else if (qtype == T_AXFR)
if (qtype == T_AXFR && !cut)
{ {
soa = 1; /* inhibits auth section */ soa = 1; /* inhibits auth section */
ns = 1; /* ensure we include NS records! */
axfr = 1; axfr = 1;
found = 1; found = 1;
axfroffset = nameoffset; axfroffset = nameoffset;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>"); log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
} }
else if (qtype == T_NS)
if (qtype == T_NS && !cut)
{ {
ns = 1; /* inhibits auth section */ ns = 1; /* inhibits auth section */
found = 1; found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>"); log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
} }
}
if (!option_bool(OPT_DHCP_FQDN) && cut) if (!option_bool(OPT_DHCP_FQDN) && cut)
{ {
...@@ -423,6 +426,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n ...@@ -423,6 +426,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (auth) if (auth)
{ {
char *authname; char *authname;
int newoffset, offset = 0;
if (!subnet) if (!subnet)
authname = zone->domain; authname = zone->domain;
...@@ -464,32 +468,158 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n ...@@ -464,32 +468,158 @@ 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 */ /* handle NS and SOA in auth section or for explicit queries */
if ((anscount != 0 || ns) && newoffset = ansp - (unsigned char *)header;
if (((anscount == 0 && !ns) || soa) &&
add_resource_record(header, limit, &trunc, 0, &ansp, add_resource_record(header, limit, &trunc, 0, &ansp,
daemon->auth_ttl, NULL, T_NS, C_IN, "d", authname, daemon->authserver)) daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
authname, daemon->authserver, daemon->hostmaster,
daemon->soa_sn, daemon->soa_refresh,
daemon->soa_retry, daemon->soa_expiry,
daemon->auth_ttl))
{
offset = newoffset;
if (soa)
anscount++;
else
authcount++;
}
if (anscount != 0 || ns)
{
struct name_list *secondary;
newoffset = ansp - (unsigned char *)header;
if (add_resource_record(header, limit, &trunc, -offset, &ansp,
daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
{ {
if (offset == 0)
offset = newoffset;
if (ns) if (ns)
anscount++; anscount++;
else else
authcount++; authcount++;
} }
if ((anscount == 0 || soa) && if (!subnet)
add_resource_record(header, limit, &trunc, 0, &ansp, for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll", if (add_resource_record(header, limit, &trunc, offset, &ansp,
authname, daemon->authserver, daemon->hostmaster, daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
daemon->soa_sn, daemon->soa_refresh,
daemon->soa_retry, daemon->soa_expiry,
daemon->auth_ttl))
{ {
if (soa) if (ns)
anscount++; anscount++;
else else
authcount++; authcount++;
} }
}
if (axfr) if (axfr)
{ {
for (rec = daemon->mxnames; rec; rec = rec->next)
if (in_zone(zone, rec->name, &cut))
{
if (cut)
*cut = 0;
if (rec->issrv)
{
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
rec->priority, rec->weight, rec->srvport, rec->target))
anscount++;
}
else
{
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
anscount++;
}
/* restore config data */
if (cut)
*cut = '.';
}
for (txt = daemon->rr; txt; txt = txt->next)
if (in_zone(zone, txt->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (txt = daemon->txt; txt; txt = txt->next)
if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (na = daemon->naptr; na; na = na->next)
if (in_zone(zone, na->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (intr = daemon->int_names; intr; intr = intr->next)
if (in_zone(zone, intr->name, &cut) && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addr))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (a = daemon->cnames; a; a = a->next)
if (in_zone(zone, a->alias, &cut))
{
strcpy(name, a->target);
if (!strchr(name, '.'))
{
strcat(name, ".");
strcat(name, zone->domain);
}
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL,
T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
anscount++;
}
cache_enumerate(1); cache_enumerate(1);
while ((crecp = cache_enumerate(0))) while ((crecp = cache_enumerate(0)))
{ {
...@@ -525,24 +655,16 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n ...@@ -525,24 +655,16 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
qtype = T_AAAA; qtype = T_AAAA;
#endif #endif
if (cut) if (cut)
{
*cut = 0; *cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN, daemon->auth_ttl, NULL, qtype, C_IN,
(crecp->flags & F_IPV4) ? "4" : "6", name, &crecp->addr)) (crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &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++; anscount++;
} }
} }
} }
} }
}
/* repeat SOA as last record */ /* repeat SOA as last record */
if (add_resource_record(header, limit, &trunc, axfroffset, &ansp, if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
...@@ -555,7 +677,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n ...@@ -555,7 +677,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
} }
} }
/* done all questions, set up header and return length of result */ /* done all questions, set up header and return length of result */
/* clear authoritative and truncated flags, set QR flag */ /* clear authoritative and truncated flags, set QR flag */
......
...@@ -756,6 +756,7 @@ extern struct daemon { ...@@ -756,6 +756,7 @@ extern struct daemon {
char *username, *groupname, *scriptuser; char *username, *groupname, *scriptuser;
char *luascript; char *luascript;
char *authserver, *authinterface, *hostmaster; char *authserver, *authinterface, *hostmaster;
struct name_list *secondary_forward_server;
int group_set, osport; int group_set, osport;
char *domain_suffix; char *domain_suffix;
struct cond_domain *cond_domain; struct cond_domain *cond_domain;
...@@ -901,7 +902,7 @@ size_t resize_packet(struct dns_header *header, size_t plen, ...@@ -901,7 +902,7 @@ size_t resize_packet(struct dns_header *header, size_t plen,
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3); 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, int add_resource_record(struct dns_header *header, char *limit, int *truncp,
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, ...); int *offset, unsigned short type, unsigned short class, char *format, ...);
unsigned char *skip_questions(struct dns_header *header, size_t plen); unsigned char *skip_questions(struct dns_header *header, size_t plen);
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes); char *name, int isExtract, int extrabytes);
......
...@@ -420,6 +420,9 @@ void lease_update_dns(int force) ...@@ -420,6 +420,9 @@ void lease_update_dns(int force)
if (daemon->port != 0 && (dns_dirty || force)) if (daemon->port != 0 && (dns_dirty || force))
{ {
/* force transfer to authoritative secondaries */
daemon->soa_sn++;
cache_unhash_dhcp(); cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
......
...@@ -125,6 +125,7 @@ struct myoption { ...@@ -125,6 +125,7 @@ struct myoption {
#define LOPT_AUTHSERV 314 #define LOPT_AUTHSERV 314
#define LOPT_AUTHTTL 315 #define LOPT_AUTHTTL 315
#define LOPT_AUTHSOA 316 #define LOPT_AUTHSOA 316
#define LOPT_AUTHSFS 317
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
...@@ -255,6 +256,7 @@ static const struct myoption opts[] = ...@@ -255,6 +256,7 @@ static const struct myoption opts[] =
{ "auth-server", 1, 0, LOPT_AUTHSERV }, { "auth-server", 1, 0, LOPT_AUTHSERV },
{ "auth-ttl", 1, 0, LOPT_AUTHTTL }, { "auth-ttl", 1, 0, LOPT_AUTHTTL },
{ "auth-soa", 1, 0, LOPT_AUTHSOA }, { "auth-soa", 1, 0, LOPT_AUTHSOA },
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
{ NULL, 0, 0, 0 } { NULL, 0, 0, 0 }
}; };
...@@ -391,6 +393,7 @@ static struct { ...@@ -391,6 +393,7 @@ static struct {
{ LOPT_AUTHZONE, ARG_DUP, "<domain>,<subnet>[,<subnet>]", gettext_noop("Domain to export to global DNS"), NULL }, { LOPT_AUTHZONE, ARG_DUP, "<domain>,<subnet>[,<subnet>]", gettext_noop("Domain to export to global DNS"), NULL },
{ LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL }, { LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },
{ LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritive zone information"), NULL }, { LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritive zone information"), NULL },
{ LOPT_AUTHSFS, ARG_ONE, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
{ 0, 0, NULL, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
...@@ -1542,6 +1545,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ...@@ -1542,6 +1545,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break; break;
case LOPT_AUTHSFS: /* --auth-sec-servers */
{
struct name_list *new;
do {
comma = split(arg);
new = safe_malloc(sizeof(struct name_list));
new->name = opt_string_alloc(arg);
new->next = daemon->secondary_forward_server;
daemon->secondary_forward_server = new;
arg = comma;
} while (arg);
break;
}
case LOPT_AUTHZONE: /* --auth-zone */ case LOPT_AUTHZONE: /* --auth-zone */
{ {
struct auth_zone *new; struct auth_zone *new;
......
...@@ -1186,7 +1186,7 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, ...@@ -1186,7 +1186,7 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
} }
int add_resource_record(struct dns_header *header, char *limit, int *truncp, 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, ...) unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
{ {
va_list ap; va_list ap;
unsigned char *sav, *p = *pp; unsigned char *sav, *p = *pp;
...@@ -1206,7 +1206,9 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int ...@@ -1206,7 +1206,9 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
} }
else else
{ {
p = do_rfc1035_name(p, va_arg(ap, char *)); char *name = va_arg(ap, char *);
if (name)
p = do_rfc1035_name(p, name);
if (nameoffset < 0) if (nameoffset < 0)
{ {
PUTSHORT(-nameoffset | 0xc000, p); PUTSHORT(-nameoffset | 0xc000, p);
...@@ -1699,7 +1701,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1699,7 +1701,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
ans = found = 1; ans = found = 1;
if (!dryrun) if (!dryrun)
{ {
unsigned int offset; int offset;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>"); log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_MX, C_IN, "sd", rec->weight, rec->target)) &offset, T_MX, C_IN, "sd", rec->weight, rec->target))
...@@ -1737,7 +1739,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1737,7 +1739,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
found = ans = 1; found = ans = 1;
if (!dryrun) if (!dryrun)
{ {
unsigned int offset; int offset;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>"); log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_SRV, C_IN, "sssd", &offset, T_SRV, C_IN, "sssd",
......
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