Merge branch 'master' into base64-example

This commit is contained in:
Sven M. Hallberg 2013-02-17 15:25:58 +01:00
commit dd763f0c07
11 changed files with 967 additions and 682 deletions

View file

@ -19,14 +19,13 @@ LDFLAGS += $(pkg-config --libs glib-2.0)
all: dns base64 base64_sem1 base64_sem2
dns: LDFLAGS:=-L../src -lhammer $(LDFLAGS)
dns: dns.o rr.o dns_common.o
dns: dns.o rr.o dns_common.o glue.o
$(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS)
dns.o: ../src/hammer.h dns_common.h
rr.o: ../src/hammer.h rr.h dns_common.h
dns_common.o: ../src/hammer.h dns_common.h
glue.o: ../src/hammer.h glue.h
base64%: LDFLAGS:=-L../src -lhammer $(LDFLAGS)
base64%: base64%.o

View file

@ -10,7 +10,12 @@
#define false 0
#define true 1
bool is_zero(HParseResult *p) {
///
// Validations
///
bool validate_hdzero(HParseResult *p) {
if (TT_UINT != p->ast->token_type)
return false;
return (0 == p->ast->uint);
@ -20,407 +25,243 @@ bool is_zero(HParseResult *p) {
* Every DNS message should have QDCOUNT entries in the question
* section, and ANCOUNT+NSCOUNT+ARCOUNT resource records.
*/
bool validate_dns(HParseResult *p) {
bool validate_message(HParseResult *p) {
if (TT_SEQUENCE != p->ast->token_type)
return false;
// The header holds the counts as its last 4 elements.
HParsedToken **elems = p->ast->seq->elements[0]->seq->elements;
size_t qd = elems[8]->uint;
size_t an = elems[9]->uint;
size_t ns = elems[10]->uint;
size_t ar = elems[11]->uint;
HParsedToken *questions = p->ast->seq->elements[1];
if (questions->seq->used != qd)
dns_header_t *header = H_FIELD(dns_header_t, 0);
size_t qd = header->question_count;
size_t an = header->answer_count;
size_t ns = header->authority_count;
size_t ar = header->additional_count;
if (H_FIELD_SEQ(1)->used != qd)
return false;
HParsedToken *rrs = p->ast->seq->elements[2];
if (an+ns+ar != rrs->seq->used)
if (an+ns+ar != H_FIELD_SEQ(2)->used)
return false;
return true;
}
struct dns_qname get_qname(const HParsedToken *t) {
// The qname parser parses at least 1 length-value pair, then a NULL.
// So, t->seq->elements[0] is a sequence of at least 1 such pair,
// and t->seq->elements[1] is the null.
const HParsedToken *labels = t->seq->elements[0];
struct dns_qname ret = {
.qlen = labels->seq->used,
.labels = h_arena_malloc(t->seq->arena, sizeof(*ret.labels)*labels->seq->used)
};
// i is which label we're on
for (size_t i=0; i<labels->seq->used; ++i) {
ret.labels[i].len = labels->seq->elements[i]->seq->used;
ret.labels[i].label = h_arena_malloc(t->seq->arena, ret.labels[i].len + 1);
// j is which char of the label we're on
for (size_t j=0; j<ret.labels[i].len; ++j)
ret.labels[i].label[j] = labels->seq->elements[i]->seq->elements[j]->uint;
ret.labels[i].label[ret.labels[i].len] = 0;
}
return ret;
}
char* get_domain(const HParsedToken *t) {
switch(t->token_type) {
case TT_UINT:
return " ";
case TT_SEQUENCE:
{
// Sequence of subdomains separated by "."
// Each subdomain is a label, which can be no more than 63 chars.
char *ret = h_arena_malloc(t->seq->arena, 64*t->seq->used);
size_t count = 0;
for (size_t i=0; i<t->seq->used; ++i) {
HParsedToken *tmp = t->seq->elements[i];
for (size_t j=0; j<tmp->seq->used; ++j) {
ret[count] = tmp->seq->elements[i]->uint;
++count;
}
ret[count] = '.';
++count;
}
ret[count-1] = '\x00';
return ret;
}
default:
return NULL;
}
}
///
// Semantic Actions
///
uint8_t* get_cs(const HCountedArray *arr) {
uint8_t *ret = h_arena_malloc(arr->arena, sizeof(uint8_t)*arr->used);
for (size_t i=0; i<arr->used; ++i)
ret[i] = arr->elements[i]->uint;
return ret;
}
uint8_t** get_txt(const HCountedArray *arr) {
uint8_t **ret = h_arena_malloc(arr->arena, sizeof(uint8_t*)*arr->used);
for (size_t i=0; i<arr->used; ++i) {
uint8_t *tmp = h_arena_malloc(arr->arena, sizeof(uint8_t)*arr->elements[i]->seq->used);
for (size_t j=0; j<arr->elements[i]->seq->used; ++j)
tmp[j] = arr->elements[i]->seq->elements[j]->uint;
}
return ret;
}
void set_rr(struct dns_rr rr, HCountedArray *rdata) {
// Helper: Parse and pack the RDATA field of a Resource Record.
void set_rdata(struct dns_rr rr, HCountedArray *rdata) {
uint8_t *data = h_arena_malloc(rdata->arena, sizeof(uint8_t)*rdata->used);
for (size_t i=0; i<rdata->used; ++i)
data[i] = rdata->elements[i]->uint;
data[i] = H_CAST_UINT(rdata->elements[i]);
// Parse RDATA if possible.
const HParseResult *p = NULL;
const HParser *parser = init_rdata(rr.type);
if (parser)
p = h_parse(parser, (const uint8_t*)data, rdata->used);
// If the RR doesn't parse, set its type to 0.
if (!p)
rr.type = 0;
// Pack the parsed rdata into rr.
switch(rr.type) {
case 1: // A
{
const HParseResult *r = h_parse(init_a(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else
rr.a = r->ast->seq->elements[0]->uint;
break;
}
case 2: // NS
{
const HParseResult *r = h_parse(init_ns(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else
rr.ns = get_domain(r->ast->seq->elements[0]);
break;
}
case 3: // MD
{
const HParseResult *r = h_parse(init_md(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else
rr.md = get_domain(r->ast->seq->elements[0]);
break;
}
case 4: // MF
{
const HParseResult *r = h_parse(init_mf(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else
rr.md = get_domain(r->ast->seq->elements[0]);
break;
}
case 5: // CNAME
{
const HParseResult *r = h_parse(init_cname(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else
rr.cname = get_domain(r->ast->seq->elements[0]);
break;
}
case 6: // SOA
{
const HParseResult *r = h_parse(init_soa(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else {
rr.soa.mname = get_domain(r->ast->seq->elements[0]);
rr.soa.rname = get_domain(r->ast->seq->elements[1]);
rr.soa.serial = r->ast->seq->elements[2]->uint;
rr.soa.refresh = r->ast->seq->elements[3]->uint;
rr.soa.retry = r->ast->seq->elements[4]->uint;
rr.soa.expire = r->ast->seq->elements[5]->uint;
rr.soa.minimum = r->ast->seq->elements[6]->uint;
}
break;
}
case 7: // MB
{
const HParseResult *r = h_parse(init_mb(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else
rr.mb = get_domain(r->ast->seq->elements[0]);
break;
}
case 8: // MG
{
const HParseResult *r = h_parse(init_mg(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else
rr.mg = get_domain(r->ast->seq->elements[0]);
break;
}
case 9: // MR
{
const HParseResult *r = h_parse(init_mr(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else
rr.mr = get_domain(r->ast->seq->elements[0]);
break;
}
case 10: // NULL
{
const HParseResult *r = h_parse(init_null(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else {
rr.null = h_arena_malloc(rdata->arena, sizeof(uint8_t)*r->ast->seq->used);
for (size_t i=0; i<r->ast->seq->used; ++i)
rr.null[i] = r->ast->seq->elements[i]->uint;
}
break;
}
case 11: // WKS
{
const HParseResult *r = h_parse(init_wks(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else {
rr.wks.address = r->ast->seq->elements[0]->uint;
rr.wks.protocol = r->ast->seq->elements[1]->uint;
rr.wks.len = r->ast->seq->elements[2]->seq->used;
rr.wks.bit_map = h_arena_malloc(rdata->arena, sizeof(uint8_t)*r->ast->seq->elements[2]->seq->used);
for (size_t i=0; i<rr.wks.len; ++i)
rr.wks.bit_map[i] = r->ast->seq->elements[2]->seq->elements[i]->uint;
}
break;
}
case 12: // PTR
{
const HParseResult *r = h_parse(init_ptr(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else
rr.ptr = get_domain(r->ast->seq->elements[0]);
break;
}
case 13: // HINFO
{
const HParseResult *r = h_parse(init_hinfo(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else {
rr.hinfo.cpu = get_cs(r->ast->seq->elements[0]->seq);
rr.hinfo.os = get_cs(r->ast->seq->elements[1]->seq);
}
break;
}
case 14: // MINFO
{
const HParseResult *r = h_parse(init_minfo(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else {
rr.minfo.rmailbx = get_domain(r->ast->seq->elements[0]);
rr.minfo.emailbx = get_domain(r->ast->seq->elements[1]);
}
break;
}
case 15: // MX
{
const HParseResult *r = h_parse(init_mx(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else {
rr.mx.preference = r->ast->seq->elements[0]->uint;
rr.mx.exchange = get_domain(r->ast->seq->elements[1]);
}
break;
}
case 16: // TXT
{
const HParseResult *r = h_parse(init_txt(), (const uint8_t*)data, rdata->used);
if (!r)
rr.type = 0;
else {
rr.txt.count = r->ast->seq->elements[0]->seq->used;
rr.txt.txt_data = get_txt(r->ast->seq->elements[0]->seq);
}
break;
}
default:
break;
case 1: rr.a = H_CAST_UINT(p->ast); break;
case 2: rr.ns = *H_CAST(dns_domain_t, p->ast); break;
case 3: rr.md = *H_CAST(dns_domain_t, p->ast); break;
case 4: rr.md = *H_CAST(dns_domain_t, p->ast); break;
case 5: rr.cname = *H_CAST(dns_domain_t, p->ast); break;
case 6: rr.soa = *H_CAST(dns_rr_soa_t, p->ast); break;
case 7: rr.mb = *H_CAST(dns_domain_t, p->ast); break;
case 8: rr.mg = *H_CAST(dns_domain_t, p->ast); break;
case 9: rr.mr = *H_CAST(dns_domain_t, p->ast); break;
case 10: rr.null = *H_CAST(dns_rr_null_t, p->ast); break;
case 11: rr.wks = *H_CAST(dns_rr_wks_t, p->ast); break;
case 12: rr.ptr = *H_CAST(dns_domain_t, p->ast); break;
case 13: rr.hinfo = *H_CAST(dns_rr_hinfo_t, p->ast); break;
case 14: rr.minfo = *H_CAST(dns_rr_minfo_t, p->ast); break;
case 15: rr.mx = *H_CAST(dns_rr_mx_t, p->ast); break;
case 16: rr.txt = *H_CAST(dns_rr_txt_t, p->ast); break;
default: break;
}
}
const HParsedToken* pack_dns_struct(const HParseResult *p) {
h_pprint(stdout, p->ast, 0, 2);
HParsedToken *ret = h_arena_malloc(p->arena, sizeof(HParsedToken));
ret->token_type = TT_USER;
dns_message_t *msg = h_arena_malloc(p->arena, sizeof(dns_message_t));
HParsedToken *hdr = p->ast->seq->elements[0];
struct dns_header header = {
.id = hdr->seq->elements[0]->uint,
.qr = hdr->seq->elements[1]->uint,
.opcode = hdr->seq->elements[2]->uint,
.aa = hdr->seq->elements[3]->uint,
.tc = hdr->seq->elements[4]->uint,
.rd = hdr->seq->elements[5]->uint,
.ra = hdr->seq->elements[6]->uint,
.rcode = hdr->seq->elements[7]->uint,
.question_count = hdr->seq->elements[8]->uint,
.answer_count = hdr->seq->elements[9]->uint,
.authority_count = hdr->seq->elements[10]->uint,
.additional_count = hdr->seq->elements[11]->uint
const HParsedToken* act_header(const HParseResult *p) {
HParsedToken **fields = h_seq_elements(p->ast);
dns_header_t header_ = {
.id = H_CAST_UINT(fields[0]),
.qr = H_CAST_UINT(fields[1]),
.opcode = H_CAST_UINT(fields[2]),
.aa = H_CAST_UINT(fields[3]),
.tc = H_CAST_UINT(fields[4]),
.rd = H_CAST_UINT(fields[5]),
.ra = H_CAST_UINT(fields[6]),
.rcode = H_CAST_UINT(fields[7]),
.question_count = H_CAST_UINT(fields[8]),
.answer_count = H_CAST_UINT(fields[9]),
.authority_count = H_CAST_UINT(fields[10]),
.additional_count = H_CAST_UINT(fields[11])
};
msg->header = header;
HParsedToken *qs = p->ast->seq->elements[1];
dns_header_t *header = H_ALLOC(dns_header_t);
*header = header_;
return H_MAKE(dns_header_t, header);
}
const HParsedToken* act_label(const HParseResult *p) {
dns_label_t *r = H_ALLOC(dns_label_t);
r->len = h_seq_len(p->ast);
r->label = h_arena_malloc(p->arena, r->len + 1);
for (size_t i=0; i<r->len; ++i)
r->label[i] = H_FIELD_UINT(i);
r->label[r->len] = 0;
return H_MAKE(dns_label_t, r);
}
const HParsedToken* act_rr(const HParseResult *p) {
dns_rr_t *rr = H_ALLOC(dns_rr_t);
rr->name = *H_FIELD(dns_domain_t, 0);
rr->type = H_FIELD_UINT(1);
rr->class = H_FIELD_UINT(2);
rr->ttl = H_FIELD_UINT(3);
rr->rdlength = H_FIELD_SEQ(4)->used;
// Parse and pack RDATA.
set_rdata(*rr, H_FIELD_SEQ(4));
return H_MAKE(dns_rr_t, rr);
}
const HParsedToken* act_question(const HParseResult *p) {
dns_question_t *q = H_ALLOC(dns_question_t);
HParsedToken **fields = h_seq_elements(p->ast);
// QNAME is a sequence of labels. Pack them into an array.
q->qname.qlen = h_seq_len(fields[0]);
q->qname.labels = h_arena_malloc(p->arena, sizeof(dns_label_t)*q->qname.qlen);
for(size_t i=0; i<q->qname.qlen; i++) {
q->qname.labels[i] = *H_INDEX(dns_label_t, fields[0], i);
}
q->qtype = H_CAST_UINT(fields[1]);
q->qclass = H_CAST_UINT(fields[2]);
return H_MAKE(dns_question_t, q);
}
const HParsedToken* act_message(const HParseResult *p) {
h_pprint(stdout, p->ast, 0, 2);
dns_message_t *msg = H_ALLOC(dns_message_t);
// Copy header into message struct.
dns_header_t *header = H_FIELD(dns_header_t, 0);
msg->header = *header;
// Copy questions into message struct.
HParsedToken *qs = h_seq_index(p->ast, 1);
struct dns_question *questions = h_arena_malloc(p->arena,
sizeof(struct dns_question)*(header.question_count));
for (size_t i=0; i<header.question_count; ++i) {
// QNAME is a sequence of labels. In the parser, it's defined as
// sequence(many1(length_value(...)), ch('\x00'), NULL).
questions[i].qname = get_qname(qs->seq->elements[i]->seq->elements[0]);
questions[i].qtype = qs->seq->elements[i]->seq->elements[1]->uint;
questions[i].qclass = qs->seq->elements[i]->seq->elements[2]->uint;
sizeof(struct dns_question)*(header->question_count));
for (size_t i=0; i<header->question_count; ++i) {
questions[i] = *H_INDEX(dns_question_t, qs, i);
}
msg->questions = questions;
HParsedToken *rrs = p->ast->seq->elements[2];
// Copy answer RRs into message struct.
HParsedToken *rrs = h_seq_index(p->ast, 2);
struct dns_rr *answers = h_arena_malloc(p->arena,
sizeof(struct dns_rr)*(header.answer_count));
for (size_t i=0; i<header.answer_count; ++i) {
answers[i].name = get_domain(rrs[i].seq->elements[0]);
answers[i].type = rrs[i].seq->elements[1]->uint;
answers[i].class = rrs[i].seq->elements[2]->uint;
answers[i].ttl = rrs[i].seq->elements[3]->uint;
answers[i].rdlength = rrs[i].seq->elements[4]->seq->used;
set_rr(answers[i], rrs[i].seq->elements[4]->seq);
sizeof(struct dns_rr)*(header->answer_count));
for (size_t i=0; i<header->answer_count; ++i) {
answers[i] = *H_INDEX(dns_rr_t, rrs, i);
}
msg->answers = answers;
// Copy authority RRs into message struct.
struct dns_rr *authority = h_arena_malloc(p->arena,
sizeof(struct dns_rr)*(header.authority_count));
for (size_t i=0, j=header.answer_count; i<header.authority_count; ++i, ++j) {
authority[i].name = get_domain(rrs[j].seq->elements[0]);
authority[i].type = rrs[j].seq->elements[1]->uint;
authority[i].class = rrs[j].seq->elements[2]->uint;
authority[i].ttl = rrs[j].seq->elements[3]->uint;
authority[i].rdlength = rrs[j].seq->elements[4]->seq->used;
set_rr(authority[i], rrs[j].seq->elements[4]->seq);
sizeof(struct dns_rr)*(header->authority_count));
for (size_t i=0, j=header->answer_count; i<header->authority_count; ++i, ++j) {
authority[i] = *H_INDEX(dns_rr_t, rrs, j);
}
msg->authority = authority;
// Copy additional RRs into message struct.
struct dns_rr *additional = h_arena_malloc(p->arena,
sizeof(struct dns_rr)*(header.additional_count));
for (size_t i=0, j=header.answer_count+header.authority_count; i<header.additional_count; ++i, ++j) {
additional[i].name = get_domain(rrs[j].seq->elements[0]);
additional[i].type = rrs[j].seq->elements[1]->uint;
additional[i].class = rrs[j].seq->elements[2]->uint;
additional[i].ttl = rrs[j].seq->elements[3]->uint;
additional[i].rdlength = rrs[j].seq->elements[4]->seq->used;
set_rr(additional[i], rrs[j].seq->elements[4]->seq);
sizeof(struct dns_rr)*(header->additional_count));
for (size_t i=0, j=header->answer_count+header->authority_count; i<header->additional_count; ++i, ++j) {
additional[i] = *H_INDEX(dns_rr_t, rrs, j);
}
msg->additional = additional;
ret->user = (void*)msg;
return H_MAKE(dns_message_t, msg);
}
#define act_hdzero h_act_ignore
#define act_qname act_index0
///
// Grammar
///
const HParser* init_parser() {
static const HParser *ret = NULL;
if (ret)
return ret;
H_RULE (domain, init_domain());
H_AVRULE(hdzero, h_bits(3, false));
H_ARULE (header, h_sequence(h_bits(16, false), // ID
h_bits(1, false), // QR
h_bits(4, false), // opcode
h_bits(1, false), // AA
h_bits(1, false), // TC
h_bits(1, false), // RD
h_bits(1, false), // RA
hdzero, // Z
h_bits(4, false), // RCODE
h_uint16(), // QDCOUNT
h_uint16(), // ANCOUNT
h_uint16(), // NSCOUNT
h_uint16(), // ARCOUNT
NULL));
H_RULE (type, h_int_range(h_uint16(), 1, 16));
H_RULE (qtype, h_choice(type,
h_int_range(h_uint16(), 252, 255),
NULL));
H_RULE (class, h_int_range(h_uint16(), 1, 4));
H_RULE (qclass, h_choice(class,
h_int_range(h_uint16(), 255, 255),
NULL));
H_RULE (len, h_int_range(h_uint8(), 1, 255));
H_ARULE (label, h_length_value(len, h_uint8()));
H_ARULE (qname, h_sequence(h_many1(label),
h_ch('\x00'),
NULL));
H_ARULE (question, h_sequence(qname, qtype, qclass, NULL));
H_RULE (rdata, h_length_value(h_uint16(), h_uint8()));
H_ARULE (rr, h_sequence(domain, // NAME
type, // TYPE
class, // CLASS
h_uint32(), // TTL
rdata, // RDLENGTH+RDATA
NULL));
H_AVRULE(message, h_sequence(header,
h_many(question),
h_many(rr),
h_end_p(),
NULL));
ret = message;
return ret;
}
const HParser* init_parser() {
static HParser *dns_message = NULL;
if (dns_message)
return dns_message;
const HParser *domain = init_domain();
const HParser *dns_header = h_sequence(h_bits(16, false), // ID
h_bits(1, false), // QR
h_bits(4, false), // opcode
h_bits(1, false), // AA
h_bits(1, false), // TC
h_bits(1, false), // RD
h_bits(1, false), // RA
h_ignore(h_attr_bool(h_bits(3, false), is_zero)), // Z
h_bits(4, false), // RCODE
h_uint16(), // QDCOUNT
h_uint16(), // ANCOUNT
h_uint16(), // NSCOUNT
h_uint16(), // ARCOUNT
NULL);
const HParser *type = h_int_range(h_uint16(), 1, 16);
const HParser *qtype = h_choice(type,
h_int_range(h_uint16(), 252, 255),
NULL);
const HParser *class = h_int_range(h_uint16(), 1, 4);
const HParser *qclass = h_choice(class,
h_int_range(h_uint16(), 255, 255),
NULL);
const HParser *dns_question = h_sequence(h_sequence(h_many1(h_length_value(h_int_range(h_uint8(), 1, 255),
h_uint8())),
h_ch('\x00'),
NULL), // QNAME
qtype, // QTYPE
qclass, // QCLASS
NULL);
const HParser *dns_rr = h_sequence(domain, // NAME
type, // TYPE
class, // CLASS
h_uint32(), // TTL
h_length_value(h_uint16(), h_uint8()), // RDLENGTH+RDATA
NULL);
dns_message = (HParser*)h_action(h_attr_bool(h_sequence(dns_header,
h_many(dns_question),
h_many(dns_rr),
h_end_p(),
NULL),
validate_dns),
pack_dns_struct);
return dns_message;
}
///
// Main Program for a Dummy DNS Server
///
int start_listening() {
// return: fd
@ -442,7 +283,7 @@ int start_listening() {
const int TYPE_MAX = 16;
typedef const char* cstr;
const char* TYPE_STR[17] = {
static const char* TYPE_STR[17] = {
"nil", "A", "NS", "MD",
"MF", "CNAME", "SOA", "MB",
"MG", "MR", "NULL", "WKS",

View file

@ -1,6 +1,27 @@
#include "../src/hammer.h"
struct dns_header {
enum DNSTokenType_ {
TT_dns_message_t = TT_USER,
TT_dns_header_t,
TT_dns_label_t,
TT_dns_qname_t,
TT_dns_question_t,
TT_dns_rr_t,
TT_dns_rr_txt_t,
TT_dns_rr_hinfo_t,
TT_dns_rr_minfo_t,
TT_dns_rr_mx_t,
TT_dns_rr_soa_t,
TT_dns_rr_wks_t,
TT_dns_rr_null_t,
TT_dns_domain_t,
TT_dns_cstr_t
};
typedef char *dns_domain_t;
typedef uint8_t *dns_cstr_t;
typedef struct dns_header {
uint16_t id;
bool qr, aa, tc, rd, ra;
char opcode, rcode;
@ -8,74 +29,93 @@ struct dns_header {
size_t answer_count;
size_t authority_count;
size_t additional_count;
};
struct dns_qname {
} dns_header_t;
typedef struct dns_label {
size_t len;
uint8_t *label;
} dns_label_t;
typedef struct dns_qname {
size_t qlen;
struct {
size_t len;
uint8_t *label;
} *labels;
};
struct dns_question {
struct dns_qname qname;
dns_label_t *labels;
} dns_qname_t;
typedef struct dns_question {
dns_qname_t qname;
uint16_t qtype;
uint16_t qclass;
};
struct dns_rr {
} dns_question_t;
typedef struct {
dns_cstr_t cpu;
dns_cstr_t os;
} dns_rr_hinfo_t;
typedef struct {
char* rmailbx;
char* emailbx;
} dns_rr_minfo_t;
typedef struct {
uint16_t preference;
char* exchange;
} dns_rr_mx_t;
typedef struct {
char* mname;
char* rname;
uint32_t serial;
uint32_t refresh;
uint32_t retry;
uint32_t expire;
uint32_t minimum;
} dns_rr_soa_t;
typedef struct {
size_t count;
uint8_t** txt_data;
} dns_rr_txt_t;
typedef struct {
uint32_t address;
uint8_t protocol;
size_t len;
uint8_t* bit_map;
} dns_rr_wks_t;
typedef uint8_t *dns_rr_null_t;
typedef struct dns_rr {
char* name;
uint16_t type;
uint16_t class;
uint32_t ttl; // cmos is also acceptable.
uint16_t rdlength;
union {
char* cname;
struct {
uint8_t* cpu;
uint8_t* os;
} hinfo;
char* mb;
char* md;
char* mf;
char* mg;
struct {
char* rmailbx;
char* emailbx;
} minfo;
char* mr;
struct {
uint16_t preference;
char* exchange;
} mx;
uint8_t* null;
char* ns;
char* ptr;
struct {
char* mname;
char* rname;
uint32_t serial;
uint32_t refresh;
uint32_t retry;
uint32_t expire;
uint32_t minimum;
} soa;
struct {
size_t count;
uint8_t** txt_data;
} txt;
uint32_t a;
struct {
uint32_t address;
uint8_t protocol;
size_t len;
uint8_t* bit_map;
} wks;
uint32_t a;
char* ns;
char* md;
char* mf;
char* cname;
dns_rr_soa_t soa;
char* mb;
char* mg;
char* mr;
dns_rr_null_t null;
dns_rr_wks_t wks;
char* ptr;
dns_rr_hinfo_t hinfo;
dns_rr_minfo_t minfo;
dns_rr_mx_t mx;
dns_rr_txt_t txt;
};
};
} dns_rr_t;
typedef struct dns_message {
struct dns_header header;
struct dns_question *questions;
struct dns_rr *answers;
struct dns_rr *authority;
struct dns_rr *additional;
dns_header_t header;
dns_question_t *questions;
dns_rr_t *answers;
dns_rr_t *authority;
dns_rr_t *additional;
} dns_message_t;

View file

@ -1,9 +1,12 @@
#include "../src/hammer.h"
#include "dns_common.h"
#include "dns.h"
#define false 0
#define true 1
H_ACT_APPLY(act_index0, h_act_index, 0)
/**
* A label can't be more than 63 characters.
*/
@ -13,51 +16,64 @@ bool validate_label(HParseResult *p) {
return (64 > p->ast->seq->used);
}
#define act_label h_act_flatten
const HParsedToken* act_domain(const HParseResult *p) {
const HParsedToken *ret = NULL;
char *arr = NULL;
switch(p->ast->token_type) {
case TT_UINT:
arr = " ";
break;
case TT_SEQUENCE:
// Sequence of subdomains separated by "."
// Each subdomain is a label, which can be no more than 63 chars.
arr = h_arena_malloc(p->arena, 64*p->ast->seq->used);
size_t count = 0;
for (size_t i=0; i<p->ast->seq->used; ++i) {
HParsedToken *tmp = p->ast->seq->elements[i];
for (size_t j=0; j<tmp->seq->used; ++j) {
arr[count] = tmp->seq->elements[i]->uint;
++count;
}
arr[count] = '.';
++count;
}
arr[count-1] = '\x00';
break;
default:
arr = NULL;
ret = NULL;
}
if(arr) {
dns_domain_t *val = H_ALLOC(dns_domain_t); // dns_domain_t is char*
*val = arr;
ret = H_MAKE(dns_domain_t, val);
}
return ret;
}
const HParser* init_domain() {
static const HParser *domain = NULL;
if (domain)
return domain;
static const HParser *ret = NULL;
if (ret)
return ret;
const HParser *letter = h_choice(h_ch_range('a', 'z'),
h_ch_range('A', 'Z'),
NULL);
H_RULE (letter, h_choice(h_ch_range('a','z'), h_ch_range('A','Z'), NULL));
H_RULE (let_dig, h_choice(letter, h_ch_range('0','9'), NULL));
H_RULE (ldh_str, h_many1(h_choice(let_dig, h_ch('-'), NULL)));
H_VARULE(label, h_sequence(letter,
h_optional(h_sequence(h_optional(ldh_str),
let_dig,
NULL)),
NULL));
H_RULE (subdomain, h_sepBy1(label, h_ch('.')));
H_ARULE (domain, h_choice(subdomain, h_ch(' '), NULL));
const HParser *let_dig = h_choice(letter,
h_ch_range('0', '9'),
NULL);
const HParser *ldh_str = h_many1(h_choice(let_dig,
h_ch('-'),
NULL));
const HParser *label = h_attr_bool(h_sequence(letter,
h_optional(h_sequence(h_optional(ldh_str),
let_dig,
NULL)),
NULL),
validate_label);
/**
* You could write it like this ...
* HParser *indirect_subdomain = h_indirect();
* const HParser *subdomain = h_choice(label,
* h_sequence(indirect_subdomain,
* h_ch('.'),
* label,
* NULL),
* NULL);
* h_bind_indirect(indirect_subdomain, subdomain);
*
* ... but this is easier and equivalent
*/
const HParser *subdomain = h_sepBy1(label, h_ch('.'));
domain = h_choice(subdomain,
h_ch(' '),
NULL);
return domain;
ret = domain;
return ret;
}
const HParser* init_character_string() {

View file

@ -2,8 +2,11 @@
#define HAMMER_DNS_COMMON__H
#include "../src/hammer.h"
#include "glue.h"
const HParser* init_domain();
const HParser* init_character_string();
const HParsedToken* act_index0(const HParseResult *p);
#endif

170
examples/glue.c Normal file
View file

@ -0,0 +1,170 @@
#include "glue.h"
#include "../src/internal.h" // for h_carray_*
// The action equivalent of h_ignore.
const HParsedToken *h_act_ignore(const HParseResult *p)
{
return NULL;
}
// Helper to build HAction's that pick one index out of a sequence.
const HParsedToken *h_act_index(int i, const HParseResult *p)
{
if(!p) return NULL;
const HParsedToken *tok = p->ast;
if(!tok || tok->token_type != TT_SEQUENCE)
return NULL;
const HCountedArray *seq = tok->seq;
size_t n = seq->used;
if(i<0 || (size_t)i>=n)
return NULL;
else
return tok->seq->elements[i];
}
// Action version of h_seq_flatten.
const HParsedToken *h_act_flatten(const HParseResult *p) {
return h_seq_flatten(p->arena, p->ast);
}
// Low-level helper for the h_make family.
HParsedToken *h_make_(HArena *arena, HTokenType type)
{
HParsedToken *ret = h_arena_malloc(arena, sizeof(HParsedToken));
ret->token_type = type;
return ret;
}
HParsedToken *h_make(HArena *arena, HTokenType type, void *value)
{
assert(type >= TT_USER);
HParsedToken *ret = h_make_(arena, type);
ret->user = value;
return ret;
}
HParsedToken *h_make_seq(HArena *arena)
{
HParsedToken *ret = h_make_(arena, TT_SEQUENCE);
ret->seq = h_carray_new(arena);
return ret;
}
HParsedToken *h_make_bytes(HArena *arena, size_t len)
{
HParsedToken *ret = h_make_(arena, TT_BYTES);
ret->bytes.len = len;
ret->bytes.token = h_arena_malloc(arena, len);
return ret;
}
HParsedToken *h_make_sint(HArena *arena, int64_t val)
{
HParsedToken *ret = h_make_(arena, TT_SINT);
ret->sint = val;
return ret;
}
HParsedToken *h_make_uint(HArena *arena, uint64_t val)
{
HParsedToken *ret = h_make_(arena, TT_UINT);
ret->uint = val;
return ret;
}
// XXX -> internal
HParsedToken *h_carray_index(const HCountedArray *a, size_t i)
{
assert(i < a->used);
return a->elements[i];
}
size_t h_seq_len(const HParsedToken *p)
{
assert(p != NULL);
assert(p->token_type == TT_SEQUENCE);
return p->seq->used;
}
HParsedToken **h_seq_elements(const HParsedToken *p)
{
assert(p != NULL);
assert(p->token_type == TT_SEQUENCE);
return p->seq->elements;
}
HParsedToken *h_seq_index(const HParsedToken *p, size_t i)
{
assert(p != NULL);
assert(p->token_type == TT_SEQUENCE);
return h_carray_index(p->seq, i);
}
HParsedToken *h_seq_index_path(const HParsedToken *p, size_t i, ...)
{
va_list va;
va_start(va, i);
HParsedToken *ret = h_seq_index_vpath(p, i, va);
va_end(va);
return ret;
}
HParsedToken *h_seq_index_vpath(const HParsedToken *p, size_t i, va_list va)
{
HParsedToken *ret = h_seq_index(p, i);
int j;
while((j = va_arg(va, int)) >= 0)
ret = h_seq_index(p, j);
return ret;
}
void h_seq_snoc(HParsedToken *xs, const HParsedToken *x)
{
assert(xs != NULL);
assert(xs->token_type == TT_SEQUENCE);
h_carray_append(xs->seq, (HParsedToken *)x);
}
void h_seq_append(HParsedToken *xs, const HParsedToken *ys)
{
assert(xs != NULL);
assert(xs->token_type == TT_SEQUENCE);
assert(ys != NULL);
assert(ys->token_type == TT_SEQUENCE);
for(size_t i; i<ys->seq->used; i++)
h_carray_append(xs->seq, ys->seq->elements[i]);
}
// Flatten nested sequences. Always returns a sequence.
// If input element is not a sequence, returns it as a singleton sequence.
const HParsedToken *h_seq_flatten(HArena *arena, const HParsedToken *p)
{
assert(p != NULL);
HParsedToken *ret = h_make_seq(arena);
switch(p->token_type) {
case TT_SEQUENCE:
// Flatten and append all.
for(size_t i; i<p->seq->used; i++) {
h_seq_append(ret, h_seq_flatten(arena, h_seq_index(p, i)));
}
break;
default:
// Make singleton sequence.
h_seq_snoc(ret, p);
break;
}
return ret;
}

251
examples/glue.h Normal file
View file

@ -0,0 +1,251 @@
//
// API additions for writing grammar and semantic actions more concisely
//
//
// Quick Overview:
//
// Grammars can be succinctly specified with the family of H_RULE macros.
// H_RULE defines a plain parser variable. H_ARULE additionally attaches a
// semantic action; H_VRULE attaches a validation. H_AVRULE and H_VARULE
// combine both.
//
// A few standard semantic actions are defined below. The H_ACT_APPLY macro
// allows semantic actions to be defined by "partial application" of
// a generic action to fixed paramters.
//
// The definition of more complex semantic actions will usually consist of
// extracting data from the given parse tree and constructing a token of custom
// type to represent the result. A number of functions and convenience macros
// are provided to capture the most common cases and idioms.
//
// See the leading comment blocks on the sections below for more details.
//
#ifndef HAMMER_EXAMPLES_GLUE__H
#define HAMMER_EXAMPLES_GLUE__H
#include <assert.h>
#include "../src/hammer.h"
//
// Grammar specification
//
// H_RULE is simply a short-hand for the typical declaration and definition of
// a parser variable. See its plain definition below. The goal is to save
// horizontal space as well as to provide a clear and unified look together with
// the other macro variants that stays close to an abstract PEG or BNF grammar.
// The latter goal is more specifically enabled by H_ARULE, H_VRULE, and their
// combinations as they allow the definition of syntax to be given without
// intermingling it with the semantic specifications.
//
// H_ARULE defines a variable just like H_RULE but attaches a semantic action
// to the result of the parser via h_action. The action is expected to be
// named act_<rulename>.
//
// H_VRULE is analogous to H_ARULE but attaches a validation via h_attr_bool.
// The validation is expected to be named validate_<rulename>.
//
// H_VARULE combines H_RULE with both an action and a validation. The action is
// attached before the validation, i.e. the validation receives as input the
// result of the action.
//
// H_AVRULE is like H_VARULE but the action is attached outside the validation,
// i.e. the validation receives the uninterpreted AST as input.
//
#define H_RULE(rule, def) const HParser *rule = def
#define H_ARULE(rule, def) const HParser *rule = h_action(def, act_ ## rule)
#define H_VRULE(rule, def) const HParser *rule = \
h_attr_bool(def, validate_ ## rule)
#define H_VARULE(rule, def) const HParser *rule = \
h_attr_bool(h_action(def, act_ ## rule), validate_ ## rule)
#define H_AVRULE(rule, def) const HParser *rule = \
h_action(h_attr_bool(def, validate_ ## rule), act_ ## rule)
//
// Pre-fab semantic actions
//
// A collection of generally useful semantic actions is provided.
//
// h_act_ignore is the action equivalent of the parser combinator h_ignore. It
// simply causes the AST it is applied to to be replaced with NULL. This most
// importantly causes it to be elided from the result of a surrounding
// h_sequence.
//
// h_act_index is of note as it is not itself suitable to be passed to
// h_action. It is parameterized by an index to be picked from a sequence
// token. It must be wrapped in a proper HAction to be used. The H_ACT_APPLY
// macro provides a concise way to define such a parameter-application wrapper.
//
// h_act_flatten acts on a token of possibly nested sequences by recursively
// flattening it into a single sequence. Cf. h_seq_flatten below.
//
// H_ACT_APPLY implements "partial application" for semantic actions. It
// defines a new action that supplies given parameters to a parameterized
// action such as h_act_index.
//
const HParsedToken *h_act_ignore(const HParseResult *p);
const HParsedToken *h_act_index(int i, const HParseResult *p);
const HParsedToken *h_act_flatten(const HParseResult *p);
// Define 'myaction' as a specialization of 'paction' by supplying the leading
// parameters.
#define H_ACT_APPLY(myaction, paction, ...) \
const HParsedToken *myaction(const HParseResult *p) { \
return paction(__VA_ARGS__, p); \
}
//
// Working with HParsedTokens
//
// The type HParsedToken represents a dynamically-typed universe of values.
// Declared below are constructors to turn ordinary values into their
// HParsedToken equivalents, extractors to retrieve the original values from
// inside an HParsedToken, and functions that inspect and modify tokens of
// sequence type directly.
//
// In addition, there are a number of short-hand macros that work with some
// conventions to eliminate common boilerplate. These conventions are listed
// below. Be sure to follow them if you want to use the respective macros.
//
// * The single argument to semantic actions should be called 'p'.
//
// The H_MAKE macros suppy 'p->arena' to their underlying h_make
// counterparts. The H_FIELD macros supply 'p->ast' to their underlying
// H_INDEX counterparts.
//
// * For each custom token type, there should be a typedef for the
// corresponding value type.
//
// H_CAST, H_INDEX and H_FIELD cast the void * user field of such a token to
// a pointer to the given type.
//
// * For each custom token type, say 'foo_t', there must be an integer
// constant 'TT_foo_t' to identify the token type. This constant must have a
// value greater or equal than TT_USER.
//
// One idiom is to define an enum for all custom token types and to assign a
// value of TT_USER to the first element. This can be viewed as extending
// the HTokenType enum.
//
// The H_MAKE and H_ASSERT macros derive the name of the token type constant
// from the given type name.
//
//
// The H_ALLOC macro is useful for allocating values of custom token types.
//
// The H_MAKE family of macros construct tokens of a given type. The native
// token types are indicated by a corresponding suffix such as in H_MAKE_SEQ.
// The form with no suffix is used for custom token types. This convention is
// also used for other macro and function families.
//
// The H_ASSERT family simply asserts that a given token has the expected type.
// It mainly serves as an implementation aid for H_CAST. Of note in that regard
// is that, unlike the standard 'assert' macro, these form _expressions_ that
// return the value of their token argument; thus they can be used in a
// "pass-through" fashion inside other expressions.
//
// The H_CAST family combines a type assertion with access to the
// statically-typed value inside a token.
//
// A number of functions h_seq_* operate on and inspect sequence tokens.
// Note that H_MAKE_SEQ takes no arguments and constructs an empty sequence.
// Therefore there are h_seq_snoc and h_seq_append to build up sequences.
//
// The macro families H_FIELD and H_INDEX combine index access on a sequence
// with a cast to the appropriate result type. H_FIELD is used to access the
// elements of the argument token 'p' in an action. H_INDEX allows any sequence
// token to be specified. Both macro families take an arbitrary number of index
// arguments, giving access to elements in nested sequences by path.
// These macros are very useful to avoid spaghetti chains of unchecked pointer
// dereferences.
//
// Standard short-hand for arena-allocating a variable in a semantic action.
#define H_ALLOC(TYP) ((TYP *) h_arena_malloc(p->arena, sizeof(TYP)))
// Token constructors...
HParsedToken *h_make(HArena *arena, HTokenType type, void *value);
HParsedToken *h_make_seq(HArena *arena); // Makes empty sequence.
HParsedToken *h_make_bytes(HArena *arena, size_t len);
HParsedToken *h_make_sint(HArena *arena, int64_t val);
HParsedToken *h_make_uint(HArena *arena, uint64_t val);
// Standard short-hands to make tokens in an action.
#define H_MAKE(TYP, VAL) h_make(p->arena, TT_ ## TYP, VAL)
#define H_MAKE_SEQ() h_make_seq(p->arena)
#define H_MAKE_BYTES(LEN) h_make_bytes(p->arena, LEN)
#define H_MAKE_SINT(VAL) h_make_sint(p->arena, VAL)
#define H_MAKE_UINT(VAL) h_make_uint(p->arena, VAL)
// Extract (cast) type-specific value back from HParsedTokens...
// Pass-through assertion that a given token has the expected type.
#define h_assert_type(T,P) (assert(P->token_type == (HTokenType)T), P)
// Convenience short-hand forms of h_assert_type.
#define H_ASSERT(TYP, TOK) h_assert_type(TT_ ## TYP, TOK)
#define H_ASSERT_SEQ(TOK) h_assert_type(TT_SEQUENCE, TOK)
#define H_ASSERT_BYTES(TOK) h_assert_type(TT_BYTES, TOK)
#define H_ASSERT_SINT(TOK) h_assert_type(TT_SINT, TOK)
#define H_ASSERT_UINT(TOK) h_assert_type(TT_UINT, TOK)
// Assert expected type and return contained value.
#define H_CAST(TYP, TOK) ((TYP *) H_ASSERT(TYP, TOK)->user)
#define H_CAST_SEQ(TOK) (H_ASSERT_SEQ(TOK)->seq)
#define H_CAST_BYTES(TOK) (H_ASSERT_BYTES(TOK)->bytes)
#define H_CAST_SINT(TOK) (H_ASSERT_SINT(TOK)->sint)
#define H_CAST_UINT(TOK) (H_ASSERT_UINT(TOK)->uint)
// Sequence access...
// Return the length of a sequence.
size_t h_seq_len(const HParsedToken *p);
// Access a sequence's element array.
HParsedToken **h_seq_elements(const HParsedToken *p);
// Access a sequence element by index.
HParsedToken *h_seq_index(const HParsedToken *p, size_t i);
// Access an element in a nested sequence by a path of indices.
HParsedToken *h_seq_index_path(const HParsedToken *p, size_t i, ...);
HParsedToken *h_seq_index_vpath(const HParsedToken *p, size_t i, va_list va);
// Convenience macros combining (nested) index access and h_cast.
#define H_INDEX(TYP, SEQ, ...) H_CAST(TYP, H_INDEX_TOKEN(SEQ, __VA_ARGS__))
#define H_INDEX_SEQ(SEQ, ...) H_CAST_SEQ(H_INDEX_TOKEN(SEQ, __VA_ARGS__))
#define H_INDEX_BYTES(SEQ, ...) H_CAST_BYTES(H_INDEX_TOKEN(SEQ, __VA_ARGS__))
#define H_INDEX_SINT(SEQ, ...) H_CAST_SINT(H_INDEX_TOKEN(SEQ, __VA_ARGS__))
#define H_INDEX_UINT(SEQ, ...) H_CAST_UINT(H_INDEX_TOKEN(SEQ, __VA_ARGS__))
#define H_INDEX_TOKEN(SEQ, ...) h_seq_index_path(SEQ, __VA_ARGS__, -1)
// Standard short-hand to access and cast elements on a sequence token.
#define H_FIELD(TYP, ...) H_INDEX(TYP, p->ast, __VA_ARGS__)
#define H_FIELD_SEQ(...) H_INDEX_SEQ(p->ast, __VA_ARGS__)
#define H_FIELD_BYTES(...) H_INDEX_BYTES(p->ast, __VA_ARGS__)
#define H_FIELD_SINT(...) H_INDEX_SINT(p->ast, __VA_ARGS__)
#define H_FIELD_UINT(...) H_INDEX_UINT(p->ast, __VA_ARGS__)
// Lower-level helper for h_seq_index.
HParsedToken *h_carray_index(const HCountedArray *a, size_t i); // XXX -> internal
// Sequence modification...
// Add elements to a sequence.
void h_seq_snoc(HParsedToken *xs, const HParsedToken *x); // append one
void h_seq_append(HParsedToken *xs, const HParsedToken *ys); // append many
// XXX TODO: Remove elements from a sequence.
// Flatten nested sequences into one.
const HParsedToken *h_seq_flatten(HArena *arena, const HParsedToken *p);
#endif

View file

@ -1,124 +1,15 @@
#include "../src/hammer.h"
#include "dns_common.h"
#include "dns.h"
#include "rr.h"
#define false 0
#define true 1
const HParser* init_cname() {
static const HParser *cname = NULL;
if (cname)
return cname;
cname = h_sequence(init_domain(),
h_end_p(),
NULL);
return cname;
}
const HParser* init_hinfo() {
static const HParser *hinfo = NULL;
if (hinfo)
return hinfo;
const HParser* cstr = init_character_string();
hinfo = h_sequence(cstr,
cstr,
h_end_p(),
NULL);
return hinfo;
}
const HParser* init_mb() {
static const HParser *mb = NULL;
if (mb)
return mb;
mb = h_sequence(init_domain(),
h_end_p(),
NULL);
return mb;
}
const HParser* init_md() {
static const HParser *md = NULL;
if (md)
return md;
md = h_sequence(init_domain(),
h_end_p,
NULL);
return md;
}
const HParser* init_mf() {
static const HParser *mf = NULL;
if (mf)
return mf;
mf = h_sequence(init_domain(),
h_end_p(),
NULL);
return mf;
}
const HParser* init_mg() {
static const HParser *mg = NULL;
if (mg)
return mg;
mg = h_sequence(init_domain(),
h_end_p(),
NULL);
return mg;
}
const HParser* init_minfo() {
static const HParser *minfo = NULL;
if (minfo)
return minfo;
const HParser* domain = init_domain();
minfo = h_sequence(domain,
domain,
h_end_p(),
NULL);
return minfo;
}
const HParser* init_mr() {
static const HParser *mr = NULL;
if (mr)
return mr;
mr = h_sequence(init_domain(),
h_end_p(),
NULL);
return mr;
}
const HParser* init_mx() {
static const HParser *mx = NULL;
if (mx)
return mx;
mx = h_sequence(h_uint16(),
init_domain(),
h_end_p(),
NULL);
return mx;
}
///
// Validations and Semantic Actions
///
bool validate_null(HParseResult *p) {
if (TT_SEQUENCE != p->ast->token_type)
@ -126,94 +17,177 @@ bool validate_null(HParseResult *p) {
return (65536 > p->ast->seq->used);
}
const HParser* init_null() {
static const HParser *null_ = NULL;
if (null_)
return null_;
const HParsedToken *act_null(const HParseResult *p) {
dns_rr_null_t *null = H_ALLOC(dns_rr_null_t);
null_ = h_attr_bool(h_many(h_uint8()), validate_null);
size_t len = h_seq_len(p->ast);
uint8_t *buf = h_arena_malloc(p->arena, sizeof(uint8_t)*len);
for (size_t i=0; i<len; ++i)
buf[i] = H_FIELD_UINT(i);
return null_;
return H_MAKE(dns_rr_null_t, null);
}
const HParser* init_ns() {
static const HParser *ns = NULL;
if (ns)
return ns;
const HParsedToken *act_txt(const HParseResult *p) {
dns_rr_txt_t *txt = H_ALLOC(dns_rr_txt_t);
ns = h_sequence(init_domain(),
h_end_p(),
NULL);
const HCountedArray *arr = H_CAST_SEQ(p->ast);
uint8_t **ret = h_arena_malloc(arr->arena, sizeof(uint8_t*)*arr->used);
for (size_t i=0; i<arr->used; ++i) {
size_t len = h_seq_len(arr->elements[i]);
uint8_t *tmp = h_arena_malloc(arr->arena, sizeof(uint8_t)*len);
for (size_t j=0; j<len; ++j)
tmp[j] = H_INDEX_UINT(arr->elements[i], j);
ret[i] = tmp;
}
return ns;
txt->count = arr->used;
txt->txt_data = ret;
return H_MAKE(dns_rr_txt_t, txt);
}
const HParser* init_ptr() {
static const HParser *ptr = NULL;
if (ptr)
return ptr;
const HParsedToken* act_cstr(const HParseResult *p) {
dns_cstr_t *cs = H_ALLOC(dns_cstr_t);
const HCountedArray *arr = H_CAST_SEQ(p->ast);
uint8_t *ret = h_arena_malloc(arr->arena, sizeof(uint8_t)*arr->used);
for (size_t i=0; i<arr->used; ++i)
ret[i] = H_CAST_UINT(arr->elements[i]);
assert(ret[arr->used-1] == '\0'); // XXX Is this right?! If so, shouldn't it be a validation?
*cs = ret;
return H_MAKE(dns_cstr_t, cs);
}
const HParsedToken* act_soa(const HParseResult *p) {
dns_rr_soa_t *soa = H_ALLOC(dns_rr_soa_t);
soa->mname = *H_FIELD(dns_domain_t, 0);
soa->rname = *H_FIELD(dns_domain_t, 1);
soa->serial = H_FIELD_UINT(2);
soa->refresh = H_FIELD_UINT(3);
soa->retry = H_FIELD_UINT(4);
soa->expire = H_FIELD_UINT(5);
soa->minimum = H_FIELD_UINT(6);
return H_MAKE(dns_rr_soa_t, soa);
}
const HParsedToken* act_wks(const HParseResult *p) {
dns_rr_wks_t *wks = H_ALLOC(dns_rr_wks_t);
wks->address = H_FIELD_UINT(0);
wks->protocol = H_FIELD_UINT(1);
wks->len = H_FIELD_SEQ(2)->used;
wks->bit_map = h_arena_malloc(p->arena, sizeof(uint8_t)*wks->len);
for (size_t i=0; i<wks->len; ++i)
wks->bit_map[i] = H_INDEX_UINT(p->ast, 2, i);
return H_MAKE(dns_rr_wks_t, wks);
}
const HParsedToken* act_hinfo(const HParseResult *p) {
dns_rr_hinfo_t *hinfo = H_ALLOC(dns_rr_hinfo_t);
hinfo->cpu = *H_FIELD(dns_cstr_t, 0);
hinfo->os = *H_FIELD(dns_cstr_t, 1);
return H_MAKE(dns_rr_hinfo_t, hinfo);
}
const HParsedToken* act_minfo(const HParseResult *p) {
dns_rr_minfo_t *minfo = H_ALLOC(dns_rr_minfo_t);
minfo->rmailbx = *H_FIELD(dns_domain_t, 0);
minfo->emailbx = *H_FIELD(dns_domain_t, 1);
return H_MAKE(dns_rr_minfo_t, minfo);
}
const HParsedToken* act_mx(const HParseResult *p) {
dns_rr_mx_t *mx = H_ALLOC(dns_rr_mx_t);
mx->preference = H_FIELD_UINT(0);
mx->exchange = *H_FIELD(dns_domain_t, 1);
return H_MAKE(dns_rr_mx_t, mx);
}
///
// Parsers for all types of RDATA
///
#define RDATA_TYPE_MAX 16
const HParser* init_rdata(uint16_t type) {
static const HParser *parsers[RDATA_TYPE_MAX+1];
static int inited = 0;
if (type >= sizeof(parsers))
return NULL;
ptr = h_sequence(init_domain(),
h_end_p(),
NULL);
if (inited)
return parsers[type];
return ptr;
}
const HParser* init_soa() {
static const HParser *soa = NULL;
if (soa)
return soa;
const HParser *domain = init_domain();
soa = h_sequence(domain, // MNAME
domain, // RNAME
h_uint32(), // SERIAL
h_uint32(), // REFRESH
h_uint32(), // RETRY
h_uint32(), // EXPIRE
h_uint32(), // MINIMUM
h_end_p(),
NULL);
return soa;
}
const HParser* init_txt() {
static const HParser *txt = NULL;
if (txt)
return txt;
txt = h_sequence(h_many1(init_character_string()),
h_end_p(),
NULL);
return txt;
}
const HParser* init_a() {
static const HParser *a = NULL;
if (a)
return a;
a = h_sequence(h_uint32(),
h_end_p(),
NULL);
return a;
}
const HParser* init_wks() {
static const HParser *wks = NULL;
if (wks)
return wks;
wks = h_sequence(h_uint32(),
h_uint8(),
h_many(h_uint8()),
h_end_p(),
NULL);
return wks;
H_RULE (domain, init_domain());
H_ARULE(cstr, init_character_string());
H_RULE (a, h_uint32());
H_RULE (ns, domain);
H_RULE (md, domain);
H_RULE (mf, domain);
H_RULE (cname, domain);
H_ARULE(soa, h_sequence(domain, // MNAME
domain, // RNAME
h_uint32(), // SERIAL
h_uint32(), // REFRESH
h_uint32(), // RETRY
h_uint32(), // EXPIRE
h_uint32(), // MINIMUM
NULL));
H_RULE (mb, domain);
H_RULE (mg, domain);
H_RULE (mr, domain);
H_VRULE(null, h_many(h_uint8()));
H_RULE (wks, h_sequence(h_uint32(),
h_uint8(),
h_many(h_uint8()),
NULL));
H_RULE (ptr, domain);
H_RULE (hinfo, h_sequence(cstr, cstr, NULL));
H_RULE (minfo, h_sequence(domain, domain, NULL));
H_RULE (mx, h_sequence(h_uint16(), domain, NULL));
H_ARULE(txt, h_many1(cstr));
parsers[ 0] = NULL; // there is no type 0
parsers[ 1] = a;
parsers[ 2] = ns;
parsers[ 3] = md;
parsers[ 4] = mf;
parsers[ 5] = cname;
parsers[ 6] = soa;
parsers[ 7] = mb;
parsers[ 8] = mg;
parsers[ 9] = mr;
parsers[10] = null;
parsers[11] = wks;
parsers[12] = ptr;
parsers[13] = hinfo;
parsers[14] = minfo;
parsers[15] = mx;
parsers[16] = txt;
// All parsers must consume their input exactly.
for(uint16_t i; i<sizeof(parsers); i++) {
if(parsers[i]) {
parsers[i] = h_action(h_sequence(parsers[i], h_end_p(), NULL),
act_index0);
}
}
inited = 1;
return parsers[type];
}

View file

@ -3,21 +3,6 @@
#include "../src/hammer.h"
const HParser* init_cname();
const HParser* init_hinfo();
const HParser* init_mb();
const HParser* init_md();
const HParser* init_mf();
const HParser* init_mg();
const HParser* init_minfo();
const HParser* init_mr();
const HParser* init_mx();
const HParser* init_null();
const HParser* init_ns();
const HParser* init_ptr();
const HParser* init_soa();
const HParser* init_txt();
const HParser* init_a();
const HParser* init_wks();
const HParser* init_rdata(uint16_t type);
#endif