master.c revision 15a44745412679c30a6d022733925af70a38b715
/*
* Copyright (C) 1999, 2000 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: master.c,v 1.59 2000/07/27 09:46:12 tale Exp $ */
#include <config.h>
#include <dns/callbacks.h>
#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/rdatatype.h>
/*
* Grow the number of dns_rdatalist_t (RDLSZ) and dns_rdata_t (RDSZ) structures
* by these sizes when we need to.
*
* RDLSZ reflects the number of different types with the same name expected.
* RDSZ reflects the number of rdata expected at a give name that can fit into
* 64k.
*/
#define RDLSZ 32
#define RDSZ 512
#define NBUFS 4
#define MAXWIRESZ 255
/*
* Target buffer size and minimum target size.
* MINTSIZ must be big enough to hold the largest rdata record.
*
* TSIZ >= MINTSIZ
*/
/*
* max message size - header - root - type - class - ttl - rdlen
*/
/*
* Size for tokens in the presentation format,
* The largest tokens are the base64 blocks in KEY and CERT records,
* Largest key allowed is about 1372 bytes but
* there is no fixed upper bound on CERT records.
* 2K is too small for some X.509s, 8K is overkill.
*/
/*
* Master file loading state that persists across $INCLUDEs.
*/
typedef struct {
} loadctx_t;
static isc_result_t
static isc_result_t
dns_name_t *);
static isc_boolean_t
static dns_rdatalist_t *
static dns_rdata_t *
isc_mem_t *);
static isc_boolean_t
do { \
switch (result) { \
case ISC_R_SUCCESS: \
break; \
case ISC_R_UNEXPECTED: \
goto cleanup; \
default: \
goto error_cleanup; \
} \
} while (0)
#define WARNUNEXPECTEDEOF(lexer) \
do { \
if (isc_lex_isfile(lexer)) \
"%s:%lu: file does not end with newline", \
} while (0)
static inline isc_result_t
{
if (result != ISC_R_SUCCESS) {
switch (result) {
case ISC_R_NOMEMORY:
return (ISC_R_NOMEMORY);
default:
"isc_lex_gettoken() failed: %s",
return (ISC_R_UNEXPECTED);
}
/*NOTREACHED*/
}
"dns_master_load: %s:%lu: unexpected end of %s",
"line" : "file");
return (ISC_R_UNEXPECTEDEND);
}
return (ISC_R_SUCCESS);
}
static void
ctx->default_ttl = 0;
}
static isc_result_t
{
isc_uint32_t ttl_offset = 0;
char *include_file = NULL;
int rdlcount = 0;
int rdlcount_save = 0;
int rdatalist_size = 0;
int rdcount = 0;
int rdcount_save = 0;
int rdata_size = 0;
unsigned char *target_mem = NULL;
int target_size = TSIZ;
int glue_in_use = -1;
int current_in_use = -1;
int origin_in_use = -1;
int new_in_use;
/*
* Allocate target_size of buffer space. This is greater than twice
* the maximum individual RR data size.
*/
if (target_mem == NULL) {
goto error_cleanup;
}
do {
if (read_till_eol)
continue;
}
continue; /* blank line */
}
if (read_till_eol)
continue;
/*
* Still working on the same name.
*/
/*
* "$" Support.
*
* "$ORIGIN" and "$INCLUDE" can both take domain names.
* The processing of "$ORIGIN" and "$INCLUDE" extends
* across the normal domain name processing.
*/
"$ORIGIN") == 0) {
"$TTL") == 0) {
result =
if (result != ISC_R_SUCCESS)
goto cleanup;
"%s: %s:%lu: "
"$TTL %lu > MAXTTL, "
"setting $TTL to 0",
"dns_master_load",
}
continue;
"$INCLUDE") == 0) {
if (ttl_offset != 0) {
"%s: %s:%lu: $INCLUDE "
"may not be used with $DATE",
"dns_master_load",
goto cleanup;
}
if (include_file != NULL)
if (include_file == NULL) {
goto error_cleanup;
}
/*
* No origin field.
*/
top,
ctx,
mctx);
if (result != ISC_R_SUCCESS)
goto cleanup;
continue;
}
/*
* There is an origin field. Fall through
* to domain name processing code and do
* the actual inclusion later.
*/
"$DATE") == 0) {
if (result != ISC_R_SUCCESS)
goto error_cleanup;
if (dump_time != dump_time64) {
"%s: %s:%lu: "
"$DATE outside epoch",
"dns_master_load",
goto cleanup;
}
if (dump_time > current_time) {
"%s: %s:%lu: "
"$DATE in future, using current date",
"dns_master_load",
}
continue;
"$", 1) == 0) {
"%s: %s:%lu: "
"unknown $ directive '%s'",
"dns_master_load",
goto cleanup;
}
/*
* Normal processing resumes.
*
* Find a free name buffer.
*/
if (!name_in_use[new_in_use])
break;
if (result != ISC_R_SUCCESS)
goto error_cleanup;
/*
* Finish $ORIGIN / $INCLUDE processing if required.
*/
if (finish_origin) {
if (origin_in_use != -1)
continue;
}
if (finish_include) {
top,
&new_name,
ctx,
mctx);
if (result != ISC_R_SUCCESS)
goto cleanup;
continue;
}
/*
* "$" Processing Finished
*/
/*
* If we are processing glue and the new name does
* not match the current glue name, commit the glue
* and pop stacks leaving us in 'normal' processing
* state. Linked lists are undone by commit().
*/
&new_name) != 0) {
if (result != ISC_R_SUCCESS)
goto cleanup;
if (glue_in_use != -1)
glue_in_use = -1;
}
/*
* If we are in 'normal' processing state and the new
* name does not match the current name, see if the
* new name is for glue and treat it as such,
* otherwise we have a new name so commit what we
* have.
*/
if (!in_glue && (!current_known ||
if (current_has_delegation &&
} else {
¤t_name, top);
if (result != ISC_R_SUCCESS)
goto cleanup;
rdcount = 0;
rdlcount = 0;
if (current_in_use != -1)
= ISC_FALSE;
}
}
} else {
"%s:%lu: isc_lex_gettoken() returned "
"unexpeced token type (%d)",
goto cleanup;
}
/*
* Find TTL, class and type. Both TTL and class are optional
* and may occur in any order if they exist. TTL and class
* come before type which must exist.
*
* [<TTL>] [<class>] <type> <RDATA>
* [<class>] [<TTL>] <type> <RDATA>
*/
type = 0;
rdclass = 0;
if (initialws) {
continue; /* blank line */
}
continue;
}
if (!current_known) {
"%s: %s:%lu: No current owner name",
"dns_master_load",
goto cleanup;
}
}
== ISC_R_SUCCESS)
== ISC_R_SUCCESS) {
"%s: %s:%lu: "
"TTL %lu > MAXTTL, "
"setting TTL to 0",
"dns_master_load",
}
/*
* BIND 4 / 8 'USE_SOA_MINIMUM' could be set here.
*/
"%s: %s:%lu: no TTL specified",
"dns_master_load",
goto cleanup;
} else if (ctx->default_ttl_known) {
"%s: %s:%lu: "
"using RFC 1035 TTL semantics",
"dns_master_load",
}
"isc_lex_gettoken() returned unexpected token type");
goto cleanup;
}
if (rdclass == 0 &&
== ISC_R_SUCCESS)
"isc_lex_gettoken() returned unexpected token type");
goto cleanup;
}
if (result != ISC_R_SUCCESS)
goto cleanup;
/*
* If the class specified does not match the zone's class
* print out a error message and exit.
*/
char buf1[32];
char buf2[32];
if (result != ISC_R_SUCCESS) {
"dns_rdataclass_totext() failed: %s",
goto cleanup;
}
if (result != ISC_R_SUCCESS) {
"dns_rdataclass_totext() failed: %s",
goto cleanup;
}
"%s: %s:%lu: class (%.*s) != "
"zone class (%.*s)",
"dns_master_load",
goto cleanup;
}
if (age_ttl) {
/*
* Adjust the TTL for $DATE. If the RR has already
* expired, ignore it without even parsing the rdata
* part (good for performance, bad for catching
* syntax errors).
*/
continue;
}
}
/*
* Find a rdata structure.
*/
if (rdcount == rdata_size) {
goto error_cleanup;
}
rdata_size += RDSZ;
}
/*
* Read rdata contents.
*/
if (result != ISC_R_SUCCESS)
goto cleanup;
if (type == dns_rdatatype_sig)
else
covers = 0;
/*
* Find type in rdatalist.
* If it does not exist create new one and prepend to list
* as this will mimimise list traversal.
*/
if (in_glue)
else
break;
}
if (rdlcount == rdatalist_size) {
mctx);
if (new_rdatalist == NULL) {
goto error_cleanup;
}
rdatalist_size += RDLSZ;
}
if (in_glue)
else
"%s: %s:%lu: "
"TTL set to prior TTL (%lu)",
"dns_master_load",
}
/*
* If the new rdata is not on the list add it.
*
* If the new rdata is on the list do not worry about
* recovering the space it is using in target as it will be
* recovered when we next call commit. The worst that can
* happen is that we make a few extra calls to commit.
*/
rdcount++;
}
/*
* We must have at least 64k as rdlen is 16 bits.
* If we don't commit everything we have so far.
*/
¤t_name, top);
if (result != ISC_R_SUCCESS)
goto cleanup;
top);
if (result != ISC_R_SUCCESS)
goto cleanup;
rdcount = 0;
rdlcount = 0;
}
} while (!done);
/*
* Commit what has not yet been committed.
*/
if (result != ISC_R_SUCCESS)
goto cleanup;
if (result != ISC_R_SUCCESS)
goto cleanup;
else
goto cleanup;
}
rdatalist_size * sizeof *rdatalist);
if (target_mem != NULL)
if (include_file != NULL)
return (result);
}
static isc_result_t
{
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
{
loadctx_init(&ctx);
}
{
loadctx_init(&ctx);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
{
loadctx_init(&ctx);
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
/*
* Grow the slab of dns_rdatalist_t structures.
* Re-link glue and current list.
*/
static dns_rdatalist_t *
{
int rdlcount = 0;
return (NULL);
}
rdlcount++;
}
}
rdlcount++;
}
return (new);
}
/*
* Grow the slab of rdata structs.
* Re-link the current and glue chains.
*/
static dns_rdata_t *
{
int rdcount = 0;
return (NULL);
/*
* Copy current relinking.
*/
}
rdcount++;
}
}
/*
* Copy glue relinking.
*/
}
rdcount++;
}
}
return (new);
}
/*
* Convert each element from a rdatalist_t to rdataset then call commit.
* Unlink each element as we go.
*/
static isc_result_t
{
return (ISC_R_SUCCESS);
/*
* Ignore out-of-zone data.
*/
"%s: %s:%lu: "
"ignoring out-of-zone data",
"dns_master_load",
}
do {
if (!ignore) {
&dataset));
if (result != ISC_R_SUCCESS)
return (result);
}
return (ISC_R_SUCCESS);
}
/*
* Returns ISC_TRUE if one of the NS rdata's contains 'owner'.
*/
static isc_boolean_t
/*
* Find NS rrset.
*/
break;
}
return (ISC_FALSE);
return (ISC_TRUE);
}
return (ISC_FALSE);
}
/*
* Returns ISC_TRUE if the 'rdata' is already on 'rdatalist'.
*/
static isc_boolean_t
return (ISC_TRUE);
}
return (ISC_FALSE);
}