%{
/*
* zyparser.y -- yacc grammar for (DNS) zone files
*
* Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
*
* See LICENSE for the license.
*
*/
#include "config.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "dname.h"
#include "namedb.h"
#include "zonec.h"
/* these need to be global, otherwise they cannot be used inside yacc */
zparser_type *parser;
#ifdef __cplusplus
extern "C"
#endif /* __cplusplus */
int yywrap(void);
/* this hold the nxt bits */
static uint8_t nxtbits[16];
static int dlv_warn = 1;
/* 256 windows of 256 bits (32 bytes) */
/* still need to reset the bastard somewhere */
static uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE];
/* hold the highest rcode seen in a NSEC rdata , BUG #106 */
uint16_t nsec_highest_rcode;
void yyerror(const char *message);
#ifdef NSEC3
/* parse nsec3 parameters and add the (first) rdata elements */
static void
nsec3_add_params(const char* hash_algo_str, const char* flag_str,
const char* iter_str, const char* salt_str, int salt_len);
#endif /* NSEC3 */
%}
%union {
domain_type *domain;
const dname_type *dname;
struct lex_data data;
uint32_t ttl;
uint16_t klass;
uint16_t type;
uint16_t *unknown;
}
/*
* Tokens to represent the known RR types of DNS.
*/
%token <type> T_A T_NS T_MX T_TXT T_CNAME T_AAAA T_PTR T_NXT T_KEY T_SOA T_SIG
%token <type> T_SRV T_CERT T_LOC T_MD T_MF T_MB T_MG T_MR T_NULL T_WKS T_HINFO
%token <type> T_MINFO T_RP T_AFSDB T_X25 T_ISDN T_RT T_NSAP T_NSAP_PTR T_PX
%token <type> T_GPOS T_EID T_NIMLOC T_ATMA T_NAPTR T_KX T_A6 T_DNAME T_SINK
%token <type> T_OPT T_APL T_UINFO T_UID T_GID T_UNSPEC T_TKEY T_TSIG T_IXFR
%token <type> T_AXFR T_MAILB T_MAILA T_DS T_DLV T_SSHFP T_RRSIG T_NSEC T_DNSKEY
%token <type> T_SPF T_NSEC3 T_IPSECKEY T_DHCID T_NSEC3PARAM T_TLSA T_URI
%token <type> T_NID T_L32 T_L64 T_LP T_EUI48 T_EUI64 T_CAA T_CDS T_CDNSKEY
%token <type> T_OPENPGPKEY T_CSYNC T_ZONEMD T_AVC T_SMIMEA T_SVCB T_HTTPS
/* other tokens */
%token DOLLAR_TTL DOLLAR_ORIGIN NL SP
%token <data> QSTR STR PREV BITLAB
%token <ttl> T_TTL
%token <klass> T_RRCLASS
/* unknown RRs */
%token URR
%token <type> T_UTYPE
%type <type> type_and_rdata
%type <domain> owner dname abs_dname
%type <dname> rel_dname label
%type <data> wire_dname wire_abs_dname wire_rel_dname wire_label
%type <data> str concatenated_str_seq str_sp_seq str_dot_seq
%type <data> unquoted_dotted_str dotted_str svcparam svcparams
%type <data> nxt_seq nsec_more
%type <unknown> rdata_unknown
%%
lines: /* empty file */
| lines line
;
line: NL
| sp NL
| PREV NL {} /* Lines containing only whitespace. */
| ttl_directive
{
region_free_all(parser->rr_region);
parser->current_rr.type = 0;
parser->current_rr.rdata_count = 0;
parser->current_rr.rdatas = parser->temporary_rdatas;
parser->error_occurred = 0;
}
| origin_directive
{
region_free_all(parser->rr_region);
parser->current_rr.type = 0;
parser->current_rr.rdata_count = 0;
parser->current_rr.rdatas = parser->temporary_rdatas;
parser->error_occurred = 0;
}
| rr
{ /* rr should be fully parsed */
if (!parser->error_occurred) {
parser->current_rr.rdatas
=(rdata_atom_type *)region_alloc_array_init(
parser->region,
parser->current_rr.rdatas,
parser->current_rr.rdata_count,
sizeof(rdata_atom_type));
process_rr();
}
region_free_all(parser->rr_region);
parser->current_rr.type = 0;
parser->current_rr.rdata_count = 0;
parser->current_rr.rdatas = parser->temporary_rdatas;
parser->error_occurred = 0;
}
| error NL
;
/* needed to cope with ( and ) in arbitrary places */
sp: SP
| sp SP
;
str: STR | QSTR;
trail: NL
| sp NL
;
ttl_directive: DOLLAR_TTL sp str trail
{
parser->default_ttl = zparser_ttl2int($3.str, &(parser->error_occurred));
if (parser->error_occurred == 1) {
parser->default_ttl = DEFAULT_TTL;
parser->error_occurred = 0;
}
}
;
origin_directive: DOLLAR_ORIGIN sp abs_dname trail
{
/* if previous origin is unused, remove it, do not leak it */
if(parser->origin != error_domain && parser->origin != $3) {
/* protect $3 from deletion, because deldomain walks up */
$3->usage ++;
domain_table_deldomain(parser->db, parser->origin);
$3->usage --;
}
parser->origin = $3;
}
| DOLLAR_ORIGIN sp rel_dname trail
{
zc_error_prev_line("$ORIGIN directive requires absolute domain name");
}
;
rr: owner classttl type_and_rdata
{
parser->current_rr.owner = $1;
parser->current_rr.type = $3;
}
;
owner: dname sp
{
parser->prev_dname = $1;
$$ = $1;
}
| PREV
{
$$ = parser->prev_dname;
}
;
classttl: /* empty - fill in the default, def. ttl and IN class */
{
parser->current_rr.ttl = parser->default_ttl;
parser->current_rr.klass = parser->default_class;
}
| T_RRCLASS sp /* no ttl */
{
parser->current_rr.ttl = parser->default_ttl;
parser->current_rr.klass = $1;
}
| T_TTL sp /* no class */
{
parser->current_rr.ttl = $1;
parser->current_rr.klass = parser->default_class;
}
| T_TTL sp T_RRCLASS sp /* the lot */
{
parser->current_rr.ttl = $1;
parser->current_rr.klass = $3;
}
| T_RRCLASS sp T_TTL sp /* the lot - reversed */
{
parser->current_rr.ttl = $3;
parser->current_rr.klass = $1;
}
;
dname: abs_dname
| rel_dname
{
if ($1 == error_dname) {
$$ = error_domain;
} else if(parser->origin == error_domain) {
zc_error("cannot concatenate origin to domain name, because origin failed to parse");
$$ = error_domain;
} else if ($1->name_size + domain_dname(parser->origin)->name_size - 1 > MAXDOMAINLEN) {
zc_error("domain name exceeds %d character limit", MAXDOMAINLEN);
$$ = error_domain;
} else {
$$ = domain_table_insert(
parser->db->domains,
dname_concatenate(
parser->rr_region,
$1,
domain_dname(parser->origin)));
}
}
;
abs_dname: '.'
{
$$ = parser->db->domains->root;
}
| '@'
{
$$ = parser->origin;
}
| rel_dname '.'
{
if ($1 != error_dname) {
$$ = domain_table_insert(parser->db->domains, $1);
} else {
$$ = error_domain;
}
}
;
label: str
{
if ($1.len > MAXLABELLEN) {
zc_error("label exceeds %d character limit", MAXLABELLEN);
$$ = error_dname;
} else if ($1.len <= 0) {
zc_error("zero label length");
$$ = error_dname;
} else {
$$ = dname_make_from_label(parser->rr_region,
(uint8_t *) $1.str,
$1.len);
}
}
| BITLAB
{
zc_error("bitlabels are now deprecated. RFC2673 is obsoleted.");
$$ = error_dname;
}
;
rel_dname: label
| rel_dname '.' label
{
if ($1 == error_dname || $3 == error_dname) {
$$ = error_dname;
} else if ($1->name_size + $3->name_size - 1 > MAXDOMAINLEN) {
zc_error("domain name exceeds %d character limit",
MAXDOMAINLEN);
$$ = error_dname;
} else {
$$ = dname_concatenate(parser->rr_region, $1, $3);
}
}
;
/*
* Some dnames in rdata are handled as opaque blobs
*/
wire_dname: wire_abs_dname
| wire_rel_dname
{
/* terminate in root label and copy the origin in there */
if(parser->origin && domain_dname(parser->origin)) {
$$.len = $1.len + domain_dname(parser->origin)->name_size;
if ($$.len > MAXDOMAINLEN)
zc_error("domain name exceeds %d character limit",
MAXDOMAINLEN);
$$.str = (char *) region_alloc(parser->rr_region, $$.len);
memmove($$.str, $1.str, $1.len);
memmove($$.str + $1.len, dname_name(domain_dname(parser->origin)),
domain_dname(parser->origin)->name_size);
} else {
$$.len = $1.len + 1;
if ($$.len > MAXDOMAINLEN)
zc_error("domain name exceeds %d character limit",
MAXDOMAINLEN);
$$.str = (char *) region_alloc(parser->rr_region, $$.len);
memmove($$.str, $1.str, $1.len);
$$.str[ $1.len ] = 0;
}
}
;
wire_abs_dname: '.'
{
char *result = (char *) region_alloc(parser->rr_region, 1);
result[0] = 0;
$$.str = result;
$$.len = 1;
}
| '@'
{
if(parser->origin && domain_dname(parser->origin)) {
$$.len = domain_dname(parser->origin)->name_size;
$$.str = (char *) region_alloc(parser->rr_region, $$.len);
memmove($$.str, dname_name(domain_dname(parser->origin)), $$.len);
} else {
$$.len = 1;
$$.str = (char *) region_alloc(parser->rr_region, $$.len);
$$.str[0] = 0;
}
}
| wire_rel_dname '.'
{
$$.len = $1.len + 1;
if ($$.len > MAXDOMAINLEN)
zc_error("domain name exceeds %d character limit",
MAXDOMAINLEN);
$$.str = (char *) region_alloc(parser->rr_region, $$.len);
memcpy($$.str, $1.str, $1.len);
$$.str[$1.len] = 0;
}
;
wire_label: str
{
char *result = (char *) region_alloc(parser->rr_region,
$1.len + 1);
if ($1.len > MAXLABELLEN)
zc_error("label exceeds %d character limit", MAXLABELLEN);
/* make label anyway */
result[0] = $1.len;
memmove(result+1, $1.str, $1.len);
$$.str = result;
$$.len = $1.len + 1;
}
;
wire_rel_dname: wire_label
| wire_rel_dname '.' wire_label
{
$$.len = $1.len + $3.len;
if ($$.len > MAXDOMAINLEN)
zc_error("domain name exceeds %d character limit",
MAXDOMAINLEN);
$$.str = (char *) region_alloc(parser->rr_region, $$.len);
memmove($$.str, $1.str, $1.len);
memmove($$.str + $1.len, $3.str, $3.len);
}
;
str_seq: unquoted_dotted_str
{
zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $1.str, $1.len), 1);
}
| QSTR
{
zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $1.str, $1.len), 1);
}
| QSTR unquoted_dotted_str
{
zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $1.str, $1.len), 1);
zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $2.str, $2.len), 0);
}
| str_seq QSTR
{
zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $2.str, $2.len), 0);
}
| str_seq QSTR unquoted_dotted_str
{
zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $2.str, $2.len), 0);
zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $3.str, $3.len), 0);
}
| str_seq sp unquoted_dotted_str
{
zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $3.str, $3.len), 0);
}
| str_seq sp QSTR
{
zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $3.str, $3.len), 0);
}
| str_seq sp QSTR unquoted_dotted_str
{
zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $3.str, $3.len), 0);
zadd_rdata_txt_wireformat(zparser_conv_text(parser->rr_region, $4.str, $4.len), 0);
}
;
/*
* Generate a single string from multiple STR tokens, separated by
* spaces or dots.
*/
concatenated_str_seq: str
| '.'
{
$$.len = 1;
$$.str = region_strdup(parser->rr_region, ".");
}
| concatenated_str_seq sp str
{
$$.len = $1.len + $3.len + 1;
$$.str = (char *) region_alloc(parser->rr_region, $$.len + 1);
memcpy($$.str, $1.str, $1.len);
memcpy($$.str + $1.len, " ", 1);
memcpy($$.str + $1.len + 1, $3.str, $3.len);
$$.str[$$.len] = '\0';
}
| concatenated_str_seq '.' str
{
$$.len = $1.len + $3.len + 1;
$$.str = (char *) region_alloc(parser->rr_region, $$.len + 1);
memcpy($$.str, $1.str, $1.len);
memcpy($$.str + $1.len, ".", 1);
memcpy($$.str + $1.len + 1, $3.str, $3.len);
$$.str[$$.len] = '\0';
}
;
/* used to convert a nxt list of types */
nxt_seq: str
{
uint16_t type = rrtype_from_string($1.str);
if (type != 0 && type < 128) {
set_bit(nxtbits, type);
} else {
zc_error("bad type %d in NXT record", (int) type);
}
}
| nxt_seq sp str
{
uint16_t type = rrtype_from_string($3.str);
if (type != 0 && type < 128) {
set_bit(nxtbits, type);
} else {
zc_error("bad type %d in NXT record", (int) type);
}
}
;
nsec_more: SP nsec_more
{
}
| NL
{
}
| str nsec_seq
{
uint16_t type = rrtype_from_string($1.str);
if (type != 0) {
if (type > nsec_highest_rcode) {
nsec_highest_rcode = type;
}
set_bitnsec(nsecbits, type);
} else {
zc_error("bad type %d in NSEC record", (int) type);
}
}
;
nsec_seq: NL
| SP nsec_more
;
/*
* Sequence of STR tokens separated by spaces. The spaces are not
* preserved during concatenation.
*/
str_sp_seq: str
| str_sp_seq sp str
{
char *result = (char *) region_alloc(parser->rr_region,
$1.len + $3.len + 1);
memcpy(result, $1.str, $1.len);
memcpy(result + $1.len, $3.str, $3.len);
$$.str = result;
$$.len = $1.len + $3.len;
$$.str[$$.len] = '\0';
}
;
/*
* Sequence of STR tokens separated by dots. The dots are not
* preserved during concatenation.
*/
str_dot_seq: str
| str_dot_seq '.' str
{
char *result = (char *) region_alloc(parser->rr_region,
$1.len + $3.len + 1);
memcpy(result, $1.str, $1.len);
memcpy(result + $1.len, $3.str, $3.len);
$$.str = result;
$$.len = $1.len + $3.len;
$$.str[$$.len] = '\0';
}
;
/*
* A string that can contain dots.
*/
unquoted_dotted_str: STR
| '.'
{
$$.str = ".";
$$.len = 1;
}
| unquoted_dotted_str '.'
{
char *result = (char *) region_alloc(parser->rr_region,
$1.len + 2);
memcpy(result, $1.str, $1.len);
result[$1.len] = '.';
$$.str = result;
$$.len = $1.len + 1;
$$.str[$$.len] = '\0';
}
| unquoted_dotted_str '.' STR
{
char *result = (char *) region_alloc(parser->rr_region,
$1.len + $3.len + 2);
memcpy(result, $1.str, $1.len);
result[$1.len] = '.';
memcpy(result + $1.len + 1, $3.str, $3.len);
$$.str = result;
$$.len = $1.len + $3.len + 1;
$$.str[$$.len] = '\0';
}
;
/*
* A string that can contain dots or a quoted string.
*/
dotted_str: unquoted_dotted_str | QSTR
/* define what we can parse */
type_and_rdata:
/*
* All supported RR types. We don't support NULL and types marked obsolete.
*/
T_A sp rdata_a
| T_A sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_NS sp rdata_domain_name
| T_NS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_MD sp rdata_domain_name { zc_warning_prev_line("MD is obsolete"); }
| T_MD sp rdata_unknown
{
zc_warning_prev_line("MD is obsolete");
$$ = $1; parse_unknown_rdata($1, $3);
}
| T_MF sp rdata_domain_name { zc_warning_prev_line("MF is obsolete"); }
| T_MF sp rdata_unknown
{
zc_warning_prev_line("MF is obsolete");
$$ = $1;
parse_unknown_rdata($1, $3);
}
| T_CNAME sp rdata_domain_name
| T_CNAME sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_SOA sp rdata_soa
| T_SOA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_MB sp rdata_domain_name { zc_warning_prev_line("MB is obsolete"); }
| T_MB sp rdata_unknown
{
zc_warning_prev_line("MB is obsolete");
$$ = $1;
parse_unknown_rdata($1, $3);
}
| T_MG sp rdata_domain_name
| T_MG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_MR sp rdata_domain_name
| T_MR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
/* NULL */
| T_WKS sp rdata_wks
| T_WKS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_PTR sp rdata_domain_name
| T_PTR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_HINFO sp rdata_hinfo
| T_HINFO sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_MINFO sp rdata_minfo /* Experimental */
| T_MINFO sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_MX sp rdata_mx
| T_MX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_TXT sp rdata_txt
| T_TXT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_SPF sp rdata_txt
| T_SPF sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_AVC sp rdata_txt
| T_AVC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_RP sp rdata_rp /* RFC 1183 */
| T_RP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_AFSDB sp rdata_afsdb /* RFC 1183 */
| T_AFSDB sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_X25 sp rdata_x25 /* RFC 1183 */
| T_X25 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_ISDN sp rdata_isdn /* RFC 1183 */
| T_ISDN sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_IPSECKEY sp rdata_ipseckey /* RFC 4025 */
| T_IPSECKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_DHCID sp rdata_dhcid
| T_DHCID sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_RT sp rdata_rt /* RFC 1183 */
| T_RT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_NSAP sp rdata_nsap /* RFC 1706 */
| T_NSAP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_SIG sp rdata_rrsig
| T_SIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_KEY sp rdata_dnskey
| T_KEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_PX sp rdata_px /* RFC 2163 */
| T_PX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_AAAA sp rdata_aaaa
| T_AAAA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_LOC sp rdata_loc
| T_LOC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_NXT sp rdata_nxt
| T_NXT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_SRV sp rdata_srv
| T_SRV sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_NAPTR sp rdata_naptr /* RFC 2915 */
| T_NAPTR sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_KX sp rdata_kx /* RFC 2230 */
| T_KX sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_CERT sp rdata_cert /* RFC 2538 */
| T_CERT sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_DNAME sp rdata_domain_name /* RFC 2672 */
| T_DNAME sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_APL trail /* RFC 3123 */
| T_APL sp rdata_apl /* RFC 3123 */
| T_APL sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_DS sp rdata_ds
| T_DS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_DLV sp rdata_dlv { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } }
| T_DLV sp rdata_unknown { if (dlv_warn) { dlv_warn = 0; zc_warning_prev_line("DLV is experimental"); } $$ = $1; parse_unknown_rdata($1, $3); }
| T_SSHFP sp rdata_sshfp
| T_SSHFP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); check_sshfp(); }
| T_RRSIG sp rdata_rrsig
| T_RRSIG sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_NSEC sp rdata_nsec
| T_NSEC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_NSEC3 sp rdata_nsec3
| T_NSEC3 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_NSEC3PARAM sp rdata_nsec3_param
| T_NSEC3PARAM sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_DNSKEY sp rdata_dnskey
| T_DNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_TLSA sp rdata_tlsa
| T_TLSA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_SMIMEA sp rdata_smimea
| T_SMIMEA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_NID sp rdata_nid
| T_NID sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_L32 sp rdata_l32
| T_L32 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_L64 sp rdata_l64
| T_L64 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_LP sp rdata_lp
| T_LP sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_EUI48 sp rdata_eui48
| T_EUI48 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_EUI64 sp rdata_eui64
| T_EUI64 sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_CAA sp rdata_caa
| T_CAA sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_CDS sp rdata_ds
| T_CDS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_CDNSKEY sp rdata_dnskey
| T_CDNSKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_OPENPGPKEY sp rdata_openpgpkey
| T_OPENPGPKEY sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_CSYNC sp rdata_csync
| T_CSYNC sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_ZONEMD sp rdata_zonemd
| T_ZONEMD sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_SVCB sp rdata_svcb
| T_SVCB sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_HTTPS sp rdata_svcb
| T_HTTPS sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_URI sp rdata_uri
| T_URI sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| T_UTYPE sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
| str error NL
{
zc_error_prev_line("unrecognized RR type '%s'", $1.str);
}
;
/*
*
* below are all the definition for all the different rdata
*
*/
rdata_a: dotted_str trail
{
zadd_rdata_wireformat(zparser_conv_a(parser->region, $1.str));
}
;
rdata_domain_name: dname trail
{
/* convert a single dname record */
zadd_rdata_domain($1);
}
;
rdata_soa: dname sp dname sp str sp str sp str sp str sp str trail
{
/* convert the soa data */
zadd_rdata_domain($1); /* prim. ns */
zadd_rdata_domain($3); /* email */
zadd_rdata_wireformat(zparser_conv_serial(parser->region, $5.str)); /* serial */
zadd_rdata_wireformat(zparser_conv_period(parser->region, $7.str)); /* refresh */
zadd_rdata_wireformat(zparser_conv_period(parser->region, $9.str)); /* retry */
zadd_rdata_wireformat(zparser_conv_period(parser->region, $11.str)); /* expire */
zadd_rdata_wireformat(zparser_conv_period(parser->region, $13.str)); /* minimum */
}
;
rdata_wks: dotted_str sp str sp concatenated_str_seq trail
{
zadd_rdata_wireformat(zparser_conv_a(parser->region, $1.str)); /* address */
zadd_rdata_wireformat(zparser_conv_services(parser->region, $3.str, $5.str)); /* protocol and services */
}
;
rdata_hinfo: str sp str trail
{
zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* CPU */
zadd_rdata_wireformat(zparser_conv_text(parser->region, $3.str, $3.len)); /* OS*/
}
;
rdata_minfo: dname sp dname trail
{
/* convert a single dname record */
zadd_rdata_domain($1);
zadd_rdata_domain($3);
}
;
rdata_mx: str sp dname trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* priority */
zadd_rdata_domain($3); /* MX host */
}
;
rdata_txt: str_seq trail
{
zadd_rdata_txt_clean_wireformat();
}
;
/* RFC 1183 */
rdata_rp: dname sp dname trail
{
zadd_rdata_domain($1); /* mbox d-name */
zadd_rdata_domain($3); /* txt d-name */
}
;
/* RFC 1183 */
rdata_afsdb: str sp dname trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* subtype */
zadd_rdata_domain($3); /* domain name */
}
;
/* RFC 1183 */
rdata_x25: str trail
{
zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* X.25 address. */
}
;
/* RFC 1183 */
rdata_isdn: str trail
{
zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* address */
}
| str sp str trail
{
zadd_rdata_wireformat(zparser_conv_text(parser->region, $1.str, $1.len)); /* address */
zadd_rdata_wireformat(zparser_conv_text(parser->region, $3.str, $3.len)); /* sub-address */
}
;
/* RFC 1183 */
rdata_rt: str sp dname trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */
zadd_rdata_domain($3); /* intermediate host */
}
;
/* RFC 1706 */
rdata_nsap: str_dot_seq trail
{
/* String must start with "0x" or "0X". */
if (strncasecmp($1.str, "0x", 2) != 0) {
zc_error_prev_line("NSAP rdata must start with '0x'");
} else {
zadd_rdata_wireformat(zparser_conv_hex(parser->region, $1.str + 2, $1.len - 2)); /* NSAP */
}
}
;
/* RFC 2163 */
rdata_px: str sp dname sp dname trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */
zadd_rdata_domain($3); /* MAP822 */
zadd_rdata_domain($5); /* MAPX400 */
}
;
rdata_aaaa: dotted_str trail
{
zadd_rdata_wireformat(zparser_conv_aaaa(parser->region, $1.str)); /* IPv6 address */
}
;
rdata_loc: concatenated_str_seq trail
{
zadd_rdata_wireformat(zparser_conv_loc(parser->region, $1.str)); /* Location */
}
;
rdata_nxt: dname sp nxt_seq trail
{
zadd_rdata_domain($1); /* nxt name */
zadd_rdata_wireformat(zparser_conv_nxt(parser->region, nxtbits)); /* nxt bitlist */
memset(nxtbits, 0, sizeof(nxtbits));
}
;
rdata_srv: str sp str sp str sp dname trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* prio */
zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* weight */
zadd_rdata_wireformat(zparser_conv_short(parser->region, $5.str)); /* port */
zadd_rdata_domain($7); /* target name */
}
;
/* RFC 2915 */
rdata_naptr: str sp str sp str sp str sp str sp dname trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* order */
zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* preference */
zadd_rdata_wireformat(zparser_conv_text(parser->region, $5.str, $5.len)); /* flags */
zadd_rdata_wireformat(zparser_conv_text(parser->region, $7.str, $7.len)); /* service */
zadd_rdata_wireformat(zparser_conv_text(parser->region, $9.str, $9.len)); /* regexp */
zadd_rdata_domain($11); /* target name */
}
;
/* RFC 2230 */
rdata_kx: str sp dname trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */
zadd_rdata_domain($3); /* exchanger */
}
;
/* RFC 2538 */
rdata_cert: str sp str sp str sp str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_certificate_type(parser->region, $1.str)); /* type */
zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* key tag */
zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $5.str)); /* algorithm */
zadd_rdata_wireformat(zparser_conv_b64(parser->region, $7.str)); /* certificate or CRL */
}
;
/* RFC 3123 */
rdata_apl: rdata_apl_seq trail
;
rdata_apl_seq: dotted_str
{
zadd_rdata_wireformat(zparser_conv_apl_rdata(parser->region, $1.str));
}
| rdata_apl_seq sp dotted_str
{
zadd_rdata_wireformat(zparser_conv_apl_rdata(parser->region, $3.str));
}
;
rdata_ds: str sp str sp str sp str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* keytag */
zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $3.str)); /* alg */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* type */
zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* hash */
}
;
rdata_dlv: str sp str sp str sp str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* keytag */
zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $3.str)); /* alg */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* type */
zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* hash */
}
;
rdata_sshfp: str sp str sp str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* alg */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* fp type */
zadd_rdata_wireformat(zparser_conv_hex(parser->region, $5.str, $5.len)); /* hash */
check_sshfp();
}
;
rdata_dhcid: str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_b64(parser->region, $1.str)); /* data blob */
}
;
rdata_rrsig: str sp str sp str sp str sp str sp str sp str sp wire_dname sp str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_rrtype(parser->region, $1.str)); /* rr covered */
zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $3.str)); /* alg */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* # labels */
zadd_rdata_wireformat(zparser_conv_period(parser->region, $7.str)); /* # orig TTL */
zadd_rdata_wireformat(zparser_conv_time(parser->region, $9.str)); /* sig exp */
zadd_rdata_wireformat(zparser_conv_time(parser->region, $11.str)); /* sig inc */
zadd_rdata_wireformat(zparser_conv_short(parser->region, $13.str)); /* key id */
zadd_rdata_wireformat(zparser_conv_dns_name(parser->region,
(const uint8_t*) $15.str,$15.len)); /* sig name */
zadd_rdata_wireformat(zparser_conv_b64(parser->region, $17.str)); /* sig data */
}
;
rdata_nsec: wire_dname nsec_seq
{
zadd_rdata_wireformat(zparser_conv_dns_name(parser->region,
(const uint8_t*) $1.str, $1.len)); /* nsec name */
zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */
memset(nsecbits, 0, sizeof(nsecbits));
nsec_highest_rcode = 0;
}
;
rdata_nsec3: str sp str sp str sp str sp str nsec_seq
{
#ifdef NSEC3
nsec3_add_params($1.str, $3.str, $5.str, $7.str, $7.len);
zadd_rdata_wireformat(zparser_conv_b32(parser->region, $9.str)); /* next hashed name */
zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */
memset(nsecbits, 0, sizeof(nsecbits));
nsec_highest_rcode = 0;
#else
zc_error_prev_line("nsec3 not supported");
#endif /* NSEC3 */
}
;
rdata_nsec3_param: str sp str sp str sp str trail
{
#ifdef NSEC3
nsec3_add_params($1.str, $3.str, $5.str, $7.str, $7.len);
#else
zc_error_prev_line("nsec3 not supported");
#endif /* NSEC3 */
}
;
rdata_tlsa: str sp str sp str sp str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* usage */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* selector */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* matching type */
zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* ca data */
}
;
rdata_smimea: str sp str sp str sp str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* usage */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* selector */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* matching type */
zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* ca data */
}
;
rdata_dnskey: str sp str sp str sp str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* flags */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* proto */
zadd_rdata_wireformat(zparser_conv_algorithm(parser->region, $5.str)); /* alg */
zadd_rdata_wireformat(zparser_conv_b64(parser->region, $7.str)); /* hash */
}
;
rdata_ipsec_base: str sp str sp str sp dotted_str
{
const dname_type* name = 0;
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* precedence */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* gateway type */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* algorithm */
switch(atoi($3.str)) {
case IPSECKEY_NOGATEWAY:
zadd_rdata_wireformat(alloc_rdata_init(parser->region, "", 0));
break;
case IPSECKEY_IP4:
zadd_rdata_wireformat(zparser_conv_a(parser->region, $7.str));
break;
case IPSECKEY_IP6:
zadd_rdata_wireformat(zparser_conv_aaaa(parser->region, $7.str));
break;
case IPSECKEY_DNAME:
/* convert and insert the dname */
if(strlen($7.str) == 0)
zc_error_prev_line("IPSECKEY must specify gateway name");
if(!(name = dname_parse(parser->region, $7.str))) {
zc_error_prev_line("IPSECKEY bad gateway dname %s", $7.str);
break;
}
if($7.str[strlen($7.str)-1] != '.') {
if(parser->origin == error_domain) {
zc_error("cannot concatenate origin to domain name, because origin failed to parse");
break;
} else if(name->name_size + domain_dname(parser->origin)->name_size - 1 > MAXDOMAINLEN) {
zc_error("ipsec gateway name exceeds %d character limit",
MAXDOMAINLEN);
break;
}
name = dname_concatenate(parser->rr_region, name,
domain_dname(parser->origin));
}
zadd_rdata_wireformat(alloc_rdata_init(parser->region,
dname_name(name), name->name_size));
break;
default:
zc_error_prev_line("unknown IPSECKEY gateway type");
}
}
;
rdata_ipseckey: rdata_ipsec_base sp str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_b64(parser->region, $3.str)); /* public key */
}
| rdata_ipsec_base trail
;
/* RFC 6742 */
rdata_nid: str sp dotted_str trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */
zadd_rdata_wireformat(zparser_conv_ilnp64(parser->region, $3.str)); /* NodeID */
}
;
rdata_l32: str sp dotted_str trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */
zadd_rdata_wireformat(zparser_conv_a(parser->region, $3.str)); /* Locator32 */
}
;
rdata_l64: str sp dotted_str trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */
zadd_rdata_wireformat(zparser_conv_ilnp64(parser->region, $3.str)); /* Locator64 */
}
;
rdata_lp: str sp dname trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* preference */
zadd_rdata_domain($3); /* FQDN */
}
;
rdata_eui48: str trail
{
zadd_rdata_wireformat(zparser_conv_eui(parser->region, $1.str, 48));
}
;
rdata_eui64: str trail
{
zadd_rdata_wireformat(zparser_conv_eui(parser->region, $1.str, 64));
}
;
/* RFC7553 */
rdata_uri: str sp str sp dotted_str trail
{
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str)); /* priority */
zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str)); /* weight */
zadd_rdata_wireformat(zparser_conv_long_text(parser->region, $5.str, $5.len)); /* target */
}
;
/* RFC 6844 */
rdata_caa: str sp str sp dotted_str trail
{
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $1.str)); /* Flags */
zadd_rdata_wireformat(zparser_conv_tag(parser->region, $3.str, $3.len)); /* Tag */
zadd_rdata_wireformat(zparser_conv_long_text(parser->region, $5.str, $5.len)); /* Value */
}
;
/* RFC7929 */
rdata_openpgpkey: str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_b64(parser->region, $1.str));
}
;
/* RFC7477 */
rdata_csync: str sp str nsec_seq
{
zadd_rdata_wireformat(zparser_conv_serial(parser->region, $1.str));
zadd_rdata_wireformat(zparser_conv_short(parser->region, $3.str));
zadd_rdata_wireformat(zparser_conv_nsec(parser->region, nsecbits)); /* nsec bitlist */
memset(nsecbits, 0, sizeof(nsecbits));
nsec_highest_rcode = 0;
}
;
/* draft-ietf-dnsop-dns-zone-digest */
rdata_zonemd: str sp str sp str sp str_sp_seq trail
{
zadd_rdata_wireformat(zparser_conv_serial(parser->region, $1.str)); /* serial */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $3.str)); /* scheme */
zadd_rdata_wireformat(zparser_conv_byte(parser->region, $5.str)); /* hash algorithm */
zadd_rdata_wireformat(zparser_conv_hex(parser->region, $7.str, $7.len)); /* digest */
}
;
svcparam: dotted_str QSTR
{
zadd_rdata_wireformat(zparser_conv_svcbparam(
parser->region, $1.str, $1.len, $2.str, $2.len));
}
| dotted_str
{
zadd_rdata_wireformat(zparser_conv_svcbparam(
parser->region, $1.str, $1.len, NULL, 0));
}
;
svcparams: svcparam
| svcparams sp svcparam
;
/* draft-ietf-dnsop-svcb-https */
rdata_svcb_base: str sp dname
{
/* SvcFieldPriority */
zadd_rdata_wireformat(zparser_conv_short(parser->region, $1.str));
/* SvcDomainName */
zadd_rdata_domain($3);
};
rdata_svcb: rdata_svcb_base sp svcparams trail
{
zadd_rdata_svcb_check_wireformat();
}
| rdata_svcb_base trail
;
rdata_unknown: URR sp str sp str_sp_seq trail
{
/* $2 is the number of octets, currently ignored */
$$ = zparser_conv_hex(parser->rr_region, $5.str, $5.len);
}
| URR sp str trail
{
$$ = zparser_conv_hex(parser->rr_region, "", 0);
}
| URR error NL
{
$$ = zparser_conv_hex(parser->rr_region, "", 0);
}
;
%%
int
yywrap(void)
{
return 1;
}
/*
* Create the parser.
*/
zparser_type *
zparser_create(region_type *region, region_type *rr_region, namedb_type *db)
{
zparser_type *result;
result = (zparser_type *) region_alloc(region, sizeof(zparser_type));
result->region = region;
result->rr_region = rr_region;
result->db = db;
result->filename = NULL;
result->current_zone = NULL;
result->origin = NULL;
result->prev_dname = NULL;
result->temporary_rdatas = (rdata_atom_type *) region_alloc_array(
result->region, MAXRDATALEN, sizeof(rdata_atom_type));
return result;
}
/*
* Initialize the parser for a new zone file.
*/
void
zparser_init(const char *filename, uint32_t ttl, uint16_t klass,
const dname_type *origin)
{
memset(nxtbits, 0, sizeof(nxtbits));
memset(nsecbits, 0, sizeof(nsecbits));
nsec_highest_rcode = 0;
parser->default_ttl = ttl;
parser->default_class = klass;
parser->current_zone = NULL;
parser->origin = domain_table_insert(parser->db->domains, origin);
parser->prev_dname = parser->origin;
parser->error_occurred = 0;
parser->errors = 0;
parser->line = 1;
parser->filename = filename;
parser->current_rr.rdata_count = 0;
parser->current_rr.rdatas = parser->temporary_rdatas;
}
void
yyerror(const char *message)
{
zc_error("%s", message);
}
static void
error_va_list(unsigned line, const char *fmt, va_list args)
{
if (parser->filename) {
char message[MAXSYSLOGMSGLEN];
vsnprintf(message, sizeof(message), fmt, args);
log_msg(LOG_ERR, "%s:%u: %s", parser->filename, line, message);
}
else log_vmsg(LOG_ERR, fmt, args);
++parser->errors;
parser->error_occurred = 1;
}
/* the line counting sux, to say the least
* with this grose hack we try do give sane
* numbers back */
void
zc_error_prev_line(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
error_va_list(parser->line - 1, fmt, args);
va_end(args);
}
void
zc_error(const char *fmt, ...)
{
/* send an error message to stderr */
va_list args;
va_start(args, fmt);
error_va_list(parser->line, fmt, args);
va_end(args);
}
static void
warning_va_list(unsigned line, const char *fmt, va_list args)
{
if (parser->filename) {
char m[MAXSYSLOGMSGLEN];
vsnprintf(m, sizeof(m), fmt, args);
log_msg(LOG_WARNING, "%s:%u: %s", parser->filename, line, m);
}
else log_vmsg(LOG_WARNING, fmt, args);
}
void
zc_warning_prev_line(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
warning_va_list(parser->line - 1, fmt, args);
va_end(args);
}
void
zc_warning(const char *fmt, ... )
{
va_list args;
va_start(args, fmt);
warning_va_list(parser->line, fmt, args);
va_end(args);
}
#ifdef NSEC3
static void
nsec3_add_params(const char* hashalgo_str, const char* flag_str,
const char* iter_str, const char* salt_str, int salt_len)
{
zadd_rdata_wireformat(zparser_conv_byte(parser->region, hashalgo_str));
zadd_rdata_wireformat(zparser_conv_byte(parser->region, flag_str));
zadd_rdata_wireformat(zparser_conv_short(parser->region, iter_str));
/* salt */
if(strcmp(salt_str, "-") != 0)
zadd_rdata_wireformat(zparser_conv_hex_length(parser->region,
salt_str, salt_len));
else
zadd_rdata_wireformat(alloc_rdata_init(parser->region, "", 1));
}
#endif /* NSEC3 */