mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 06:25:31 +00:00
Add KEY, SIG and NSAP rdata type. SIG is not complete.
Add master file reader, master.c master.h, incomplete. gen.c was not generate correct include file, SWITCHXXX macros were being terminated early if last RR type was class specific. Added base64 support to rdata.c.
This commit is contained in:
457
lib/dns/master.c
Normal file
457
lib/dns/master.c
Normal file
@@ -0,0 +1,457 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <isc/lex.h>
|
||||
#include <isc/list.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/assertions.h>
|
||||
|
||||
#include <dns/master.h>
|
||||
#include <dns/types.h>
|
||||
#include <dns/result.h>
|
||||
#include <dns/rdatalist.h>
|
||||
#include <dns/rdataset.h>
|
||||
#include <dns/rdataclass.h>
|
||||
#include <dns/rdatatype.h>
|
||||
#include <dns/rdata.h>
|
||||
|
||||
typedef ISC_LIST(dns_rdatalist_t) rdatalist_head_t;
|
||||
|
||||
static dns_result_t commit(rdatalist_head_t *, dns_name_t *,
|
||||
dns_result_t (*)(dns_name_t *,
|
||||
dns_rdataset_t *));
|
||||
static isc_boolean_t is_glue(rdatalist_head_t *, dns_name_t *);
|
||||
static dns_rdatalist_t *grow_rdatalist(int, dns_rdatalist_t *, int,
|
||||
rdatalist_head_t *,
|
||||
rdatalist_head_t *,
|
||||
isc_mem_t *mctx);
|
||||
static dns_rdata_t *grow_rdata(int, dns_rdata_t *, int,
|
||||
rdatalist_head_t *, rdatalist_head_t *,
|
||||
isc_mem_t *);
|
||||
|
||||
|
||||
dns_result_t
|
||||
dns_load_master(char *master_file, dns_name_t *origin,
|
||||
dns_rdataclass_t zclass, dns_result_t (*callback)(),
|
||||
isc_mem_t *mctx)
|
||||
{
|
||||
dns_rdataclass_t class;
|
||||
dns_rdatatype_t type;
|
||||
unsigned long ttl = 0;
|
||||
dns_name_t current_name;
|
||||
dns_name_t glue_name;
|
||||
dns_name_t new_name;
|
||||
isc_boolean_t ttl_known = ISC_FALSE;
|
||||
isc_boolean_t current_known = ISC_FALSE;
|
||||
isc_boolean_t in_glue = ISC_FALSE;
|
||||
isc_boolean_t current_has_delegation = ISC_FALSE;
|
||||
isc_boolean_t done = ISC_FALSE;
|
||||
isc_token_t token;
|
||||
isc_lex_t *lex = NULL;
|
||||
dns_result_t result = DNS_R_UNEXPECTED;
|
||||
rdatalist_head_t glue_list;
|
||||
rdatalist_head_t current_list;
|
||||
unsigned int options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF;
|
||||
dns_rdatalist_t *this;
|
||||
dns_rdatalist_t *rdatalist = NULL;
|
||||
dns_rdatalist_t *new_rdatalist;
|
||||
int rdlcount = 0;
|
||||
int rdlcount_save = 0;
|
||||
int rdatalist_size = 0;
|
||||
isc_result_t lexres;
|
||||
isc_buffer_t buffer;
|
||||
isc_buffer_t target;
|
||||
isc_buffer_t target_save;
|
||||
dns_rdata_t *rdata = NULL;
|
||||
dns_rdata_t *new_rdata;
|
||||
int rdcount = 0;
|
||||
int rdcount_save = 0;
|
||||
int rdata_size = 0;
|
||||
unsigned char *target_mem = NULL;
|
||||
int target_size = 64*1024;
|
||||
|
||||
dns_name_init(¤t_name, NULL);
|
||||
dns_name_init(&glue_name, NULL);
|
||||
|
||||
ISC_LIST_INIT(glue_list);
|
||||
ISC_LIST_INIT(current_list);
|
||||
|
||||
if (isc_lex_create(mctx, 256, &lex) != ISC_R_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
if (isc_lex_openfile(lex, master_file) != ISC_R_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
target_mem = isc_mem_get(mctx, target_size);
|
||||
if (target_mem == NULL) {
|
||||
result = DNS_R_NOSPACE;
|
||||
goto cleanup;
|
||||
}
|
||||
isc_buffer_init(&target, target_mem, target_size,
|
||||
ISC_BUFFERTYPE_BINARY);
|
||||
target_save = target;
|
||||
do {
|
||||
options = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
|
||||
ISC_LEXOPT_INITIALWS | ISC_LEXOPT_DNSMULTILINE;
|
||||
lexres = isc_lex_gettoken(lex, options, &token);
|
||||
if (lexres != ISC_R_SUCCESS) {
|
||||
result = DNS_R_UNEXPECTED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (token.type == isc_tokentype_eof) {
|
||||
done = ISC_TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token.type == isc_tokentype_eol)
|
||||
continue; /* blank line */
|
||||
|
||||
if (token.type == isc_tokentype_initialws) {
|
||||
if (!current_known) {
|
||||
result = DNS_R_UNKNOWN;
|
||||
goto cleanup;
|
||||
}
|
||||
/* still working on the same name */
|
||||
} else if (token.type == isc_tokentype_string) {
|
||||
|
||||
/* XXX "$" Support */
|
||||
|
||||
dns_name_init(&new_name, NULL);
|
||||
isc_buffer_init(&buffer, token.value.as_region.base,
|
||||
token.value.as_region.length,
|
||||
ISC_BUFFERTYPE_TEXT);
|
||||
isc_buffer_add(&buffer, token.value.as_region.length);
|
||||
isc_buffer_setactive(&buffer,
|
||||
token.value.as_region.length);
|
||||
/* XXX name memory */
|
||||
result = dns_name_fromtext(&new_name, &buffer,
|
||||
origin, ISC_FALSE, &target);
|
||||
|
||||
if (result != DNS_R_SUCCESS)
|
||||
goto cleanup;
|
||||
/*
|
||||
* commit glue and pop stacks
|
||||
*/
|
||||
if (in_glue && dns_name_compare(&glue_name,
|
||||
&new_name) != 0) {
|
||||
result = commit(&glue_list,
|
||||
&glue_name, callback);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
goto cleanup;
|
||||
dns_name_invalidate(&glue_name);
|
||||
in_glue = ISC_FALSE;
|
||||
rdcount = rdcount_save;
|
||||
rdlcount = rdlcount_save;
|
||||
target = target_save;
|
||||
}
|
||||
|
||||
if (!current_known ||
|
||||
dns_name_compare(¤t_name, &new_name) != 0) {
|
||||
if (current_has_delegation &&
|
||||
is_glue(¤t_list, &new_name)) {
|
||||
in_glue = ISC_TRUE;
|
||||
rdcount_save = rdcount;
|
||||
rdlcount_save = rdlcount;
|
||||
target_save = target;
|
||||
glue_name = new_name;
|
||||
} else {
|
||||
result = commit(¤t_list,
|
||||
¤t_name,
|
||||
callback);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
goto cleanup;
|
||||
rdcount = 0;
|
||||
rdlcount = 0;
|
||||
current_name = new_name;
|
||||
current_known = ISC_TRUE;
|
||||
current_has_delegation = ISC_FALSE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = DNS_R_UNEXPECTED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
type = 0;
|
||||
class = 0;
|
||||
|
||||
options = ISC_LEXOPT_NUMBER | ISC_LEXOPT_DNSMULTILINE;
|
||||
if (isc_lex_gettoken(lex, options, &token) != ISC_R_SUCCESS) {
|
||||
result = DNS_R_UNEXPECTED;
|
||||
goto cleanup;
|
||||
}
|
||||
options = ISC_LEXOPT_DNSMULTILINE;
|
||||
|
||||
if (token.type == isc_tokentype_number) {
|
||||
ttl = token.value.as_ulong;
|
||||
ttl_known = ISC_TRUE;
|
||||
if (isc_lex_gettoken(lex, options, &token) !=
|
||||
ISC_R_SUCCESS) {
|
||||
result = DNS_R_UNEXPECTED;
|
||||
goto cleanup;
|
||||
}
|
||||
} else if (!ttl_known) {
|
||||
result = DNS_R_UNEXPECTED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (token.type != isc_tokentype_string) {
|
||||
result = DNS_R_UNEXPECTED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (dns_rdataclass_fromtext(&class, &token.value.as_textregion)
|
||||
== DNS_R_SUCCESS) {
|
||||
|
||||
if (isc_lex_gettoken(lex, options, &token) !=
|
||||
ISC_R_SUCCESS) {
|
||||
result = DNS_R_UNEXPECTED;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (token.type != isc_tokentype_string) {
|
||||
result = DNS_R_UNEXPECTED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (dns_rdatatype_fromtext(&type, &token.value.as_textregion)
|
||||
!= DNS_R_SUCCESS) {
|
||||
result = DNS_R_UNEXPECTED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (class != 0 && class != zclass) {
|
||||
result = DNS_R_UNEXPECTED;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (type == 2 && !in_glue)
|
||||
current_has_delegation = ISC_TRUE;
|
||||
if (in_glue)
|
||||
this = ISC_LIST_HEAD(glue_list);
|
||||
else
|
||||
this = ISC_LIST_HEAD(current_list);
|
||||
|
||||
while ((this = ISC_LIST_HEAD(current_list)) != NULL) {
|
||||
if (this->type == type)
|
||||
break;
|
||||
this = ISC_LIST_NEXT(this, link);
|
||||
}
|
||||
if (this == NULL) {
|
||||
if (rdlcount == rdatalist_size) {
|
||||
new_rdatalist =
|
||||
grow_rdatalist(rdatalist_size + 32,
|
||||
rdatalist,
|
||||
rdatalist_size,
|
||||
¤t_list,
|
||||
&glue_list,
|
||||
mctx);
|
||||
if (new_rdatalist == NULL) {
|
||||
result = DNS_R_NOSPACE;
|
||||
goto cleanup;
|
||||
}
|
||||
rdatalist = new_rdatalist;
|
||||
rdatalist_size += 32;
|
||||
}
|
||||
this = &rdatalist[rdlcount++];
|
||||
this->type = type;
|
||||
this->class = zclass;
|
||||
this->ttl = ttl;
|
||||
ISC_LIST_INIT(this->rdata);
|
||||
ISC_LINK_INIT(this, link);
|
||||
if (in_glue)
|
||||
ISC_LIST_PREPEND(glue_list, this, link);
|
||||
else
|
||||
ISC_LIST_PREPEND(current_list, this, link);
|
||||
}
|
||||
if (rdcount == rdata_size) {
|
||||
new_rdata = grow_rdata(rdata_size + 512, rdata,
|
||||
rdata_size, ¤t_list,
|
||||
&glue_list, mctx);
|
||||
if (new_rdata == NULL) {
|
||||
result = DNS_R_NOSPACE;
|
||||
goto cleanup;
|
||||
}
|
||||
rdata_size += 512;
|
||||
rdata = new_rdata;
|
||||
}
|
||||
result = dns_rdata_fromtext(&rdata[rdcount], class, type,
|
||||
lex, origin, ISC_FALSE, &target);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
goto cleanup;
|
||||
ISC_LIST_PREPEND(this->rdata, &rdata[rdcount], link);
|
||||
rdcount++;
|
||||
} while (!done);
|
||||
result = commit(¤t_list, ¤t_name, callback);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
goto cleanup;
|
||||
result = commit(&glue_list, &glue_name, callback);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
goto cleanup;
|
||||
result = DNS_R_SUCCESS;
|
||||
|
||||
cleanup:
|
||||
if (lex != NULL) {
|
||||
isc_lex_close(lex);
|
||||
isc_lex_destroy(&lex);
|
||||
}
|
||||
while ((this = ISC_LIST_HEAD(current_list)) != NULL)
|
||||
ISC_LIST_UNLINK(current_list, this, link);
|
||||
while ((this = ISC_LIST_HEAD(glue_list)) != NULL)
|
||||
ISC_LIST_UNLINK(glue_list, this, link);
|
||||
if (rdatalist != NULL)
|
||||
isc_mem_put(mctx, rdatalist,
|
||||
rdatalist_size * sizeof *rdatalist);
|
||||
if (rdata != NULL)
|
||||
isc_mem_put(mctx, rdata, rdata_size * sizeof *rdata);
|
||||
if (target_mem)
|
||||
isc_mem_put(mctx, target_mem, target_size);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static dns_rdatalist_t *
|
||||
grow_rdatalist(int new_len, dns_rdatalist_t *old, int old_len,
|
||||
rdatalist_head_t *current, rdatalist_head_t *glue,
|
||||
isc_mem_t *mctx)
|
||||
{
|
||||
dns_rdatalist_t *new;
|
||||
int rdlcount = 0;
|
||||
ISC_LIST(dns_rdatalist_t) save;
|
||||
dns_rdatalist_t *this;
|
||||
|
||||
new = isc_mem_get(mctx, new_len * sizeof *new);
|
||||
if (new == NULL)
|
||||
return (NULL);
|
||||
|
||||
ISC_LIST_INIT(save);
|
||||
this = ISC_LIST_HEAD(*current);
|
||||
while ((this = ISC_LIST_HEAD(*current)) != NULL) {
|
||||
ISC_LIST_UNLINK(*current, this, link);
|
||||
ISC_LIST_APPEND(save, this, link);
|
||||
}
|
||||
while ((this = ISC_LIST_HEAD(save)) != NULL) {
|
||||
ISC_LIST_UNLINK(save, this, link);
|
||||
new[rdlcount] = *this;
|
||||
ISC_LIST_APPEND(*current, &new[rdlcount], link);
|
||||
rdlcount++;
|
||||
}
|
||||
|
||||
ISC_LIST_INIT(save);
|
||||
this = ISC_LIST_HEAD(*glue);
|
||||
while ((this = ISC_LIST_HEAD(*glue)) != NULL) {
|
||||
ISC_LIST_UNLINK(*glue, this, link);
|
||||
ISC_LIST_APPEND(save, this, link);
|
||||
}
|
||||
while ((this = ISC_LIST_HEAD(save)) != NULL) {
|
||||
ISC_LIST_UNLINK(save, this, link);
|
||||
new[rdlcount] = *this;
|
||||
ISC_LIST_APPEND(*glue, &new[rdlcount], link);
|
||||
rdlcount++;
|
||||
}
|
||||
|
||||
INSIST(rdlcount == old_len);
|
||||
if (old != NULL)
|
||||
isc_mem_put(mctx, old, old_len * sizeof *old);
|
||||
return (new);
|
||||
}
|
||||
|
||||
static dns_rdata_t *
|
||||
grow_rdata(int new_len, dns_rdata_t *old, int old_len,
|
||||
rdatalist_head_t *current, rdatalist_head_t *glue,
|
||||
isc_mem_t *mctx)
|
||||
{
|
||||
dns_rdata_t *new;
|
||||
int rdcount = 0;
|
||||
ISC_LIST(dns_rdata_t) save;
|
||||
dns_rdatalist_t *this;
|
||||
dns_rdata_t *rdata;
|
||||
|
||||
new = isc_mem_get(mctx, new_len * sizeof *new);
|
||||
if (new == NULL)
|
||||
return (NULL);
|
||||
memset(new, 0, new_len * sizeof *new);
|
||||
/* copy current relinking */
|
||||
this = ISC_LIST_HEAD(*current);
|
||||
while (this != NULL) {
|
||||
ISC_LIST_INIT(save);
|
||||
while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
|
||||
ISC_LIST_UNLINK(this->rdata, rdata, link);
|
||||
ISC_LIST_APPEND(save, rdata, link);
|
||||
}
|
||||
while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
|
||||
ISC_LIST_UNLINK(save, rdata, link);
|
||||
new[rdcount] = *rdata;
|
||||
ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
|
||||
rdcount++;
|
||||
}
|
||||
this = ISC_LIST_NEXT(this, link);
|
||||
}
|
||||
/* copy glue relinking */
|
||||
this = ISC_LIST_HEAD(*glue);
|
||||
while (this != NULL) {
|
||||
ISC_LIST_INIT(save);
|
||||
while ((rdata = ISC_LIST_HEAD(this->rdata)) != NULL) {
|
||||
ISC_LIST_UNLINK(this->rdata, rdata, link);
|
||||
ISC_LIST_APPEND(save, rdata, link);
|
||||
}
|
||||
while ((rdata = ISC_LIST_HEAD(save)) != NULL) {
|
||||
ISC_LIST_UNLINK(save, rdata, link);
|
||||
new[rdcount] = *rdata;
|
||||
ISC_LIST_APPEND(this->rdata, &new[rdcount], link);
|
||||
rdcount++;
|
||||
}
|
||||
this = ISC_LIST_NEXT(this, link);
|
||||
}
|
||||
INSIST(rdcount == old_len);
|
||||
if (old != NULL)
|
||||
isc_mem_put(mctx, old, old_len * sizeof *old);
|
||||
return (new);
|
||||
}
|
||||
|
||||
static dns_result_t
|
||||
commit(rdatalist_head_t *head, dns_name_t *owner, dns_result_t (*callback)()) {
|
||||
dns_rdatalist_t *this;
|
||||
dns_rdataset_t dataset;
|
||||
dns_result_t result;
|
||||
|
||||
while ((this = ISC_LIST_HEAD(*head)) != NULL) {
|
||||
|
||||
dns_rdataset_init(&dataset);
|
||||
dns_rdatalist_tordataset(this, &dataset);
|
||||
result = ((*callback)(owner, &dataset));
|
||||
if (result != DNS_R_SUCCESS)
|
||||
return (result);
|
||||
ISC_LIST_UNLINK(*head, this, link);
|
||||
}
|
||||
return (DNS_R_SUCCESS);
|
||||
}
|
||||
|
||||
static isc_boolean_t
|
||||
is_glue(rdatalist_head_t *head, dns_name_t *owner) {
|
||||
dns_rdatalist_t *this;
|
||||
dns_rdata_t *rdata;
|
||||
isc_region_t region;
|
||||
dns_name_t name;
|
||||
|
||||
/* find NS rrset */
|
||||
this = ISC_LIST_HEAD(*head);
|
||||
while (this != NULL) {
|
||||
if (this->type == 2)
|
||||
break;
|
||||
this = ISC_LIST_NEXT(this, link);
|
||||
}
|
||||
if (this == NULL)
|
||||
return (ISC_FALSE);
|
||||
|
||||
rdata = ISC_LIST_HEAD(this->rdata);
|
||||
while (rdata != NULL) {
|
||||
dns_name_init(&name, NULL);
|
||||
dns_rdata_toregion(rdata, ®ion);
|
||||
dns_name_fromregion(&name, ®ion);
|
||||
if (dns_name_compare(&name, owner) == 0)
|
||||
return (ISC_TRUE);
|
||||
}
|
||||
return (ISC_FALSE);
|
||||
}
|
Reference in New Issue
Block a user