summaryrefslogtreecommitdiff
path: root/src/zcompile
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-11-02 22:44:12 +0100
committerOndřej Surý <ondrej@sury.org>2011-11-02 22:44:12 +0100
commitc8d5977bb546dae9ed59d81556639c49badd8121 (patch)
tree4c86750db26c1c3502b60f2cd78ca9611cfa01d6 /src/zcompile
downloadknot-upstream/0.8.0_pre1.tar.gz
Imported Upstream version 0.8.0~pre1upstream/0.8.0_pre1
Diffstat (limited to 'src/zcompile')
-rw-r--r--src/zcompile/LICENSE30
-rw-r--r--src/zcompile/parser-descriptor.c535
-rw-r--r--src/zcompile/parser-descriptor.h278
-rw-r--r--src/zcompile/parser-util.c2435
-rw-r--r--src/zcompile/parser-util.h357
-rw-r--r--src/zcompile/tests/unittests_zp_main.c62
-rw-r--r--src/zcompile/tests/zcompile_tests.c425
-rw-r--r--src/zcompile/zcompile-error.c52
-rw-r--r--src/zcompile/zcompile-error.h90
-rw-r--r--src/zcompile/zcompile.c639
-rw-r--r--src/zcompile/zcompile.h207
-rw-r--r--src/zcompile/zcompile_main.c116
-rw-r--r--src/zcompile/zlexer.l531
-rw-r--r--src/zcompile/zparser.y1730
14 files changed, 7487 insertions, 0 deletions
diff --git a/src/zcompile/LICENSE b/src/zcompile/LICENSE
new file mode 100644
index 0000000..55faacf
--- /dev/null
+++ b/src/zcompile/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
+
+This software is open source.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+Neither the name of the NLNET LABS nor the names of its contributors may
+be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/zcompile/parser-descriptor.c b/src/zcompile/parser-descriptor.c
new file mode 100644
index 0000000..41e7f2d
--- /dev/null
+++ b/src/zcompile/parser-descriptor.c
@@ -0,0 +1,535 @@
+/*!
+ * \file parser-descriptor.c
+ *
+ * \author Modifications by Jan Kadlec <jan.kadlec@nic.cz>,
+ * most of the work by NLnet Labs.
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief Contains resource record descriptor and its API
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/types.h>
+
+//#include "common.h"
+#include "zcompile/parser-descriptor.h"
+/* TODO this has to be removed - move tokens to separate file
+ but can it be done?) */
+#include "zcompile/zcompile.h"
+/* FIXME: Generate .y and .l to zoneparser/ */
+#include "zparser.h"
+
+enum desclen { PARSER_RRTYPE_DESCRIPTORS_LENGTH = 32770 }; // used to be 101
+
+/* Taken from RFC 1035, section 3.2.4. */
+static knot_lookup_table_t dns_rrclasses[] = {
+ { PARSER_CLASS_IN, "IN" }, /* the Internet */
+ { PARSER_CLASS_CS, "CS" }, /* the CSNET class (Obsolete) */
+ { PARSER_CLASS_CH, "CH" }, /* the CHAOS class */
+ { PARSER_CLASS_HS, "HS" }, /* Hesiod */
+ { 0, NULL }
+};
+static parser_rrtype_descriptor_t
+ knot_rrtype_descriptors[PARSER_RRTYPE_DESCRIPTORS_LENGTH] = {
+ /* 0 */
+ { 0, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 1 */
+ { PARSER_RRTYPE_A, T_A, "A", 1, { PARSER_RDATA_WF_A }, true },
+ /* 2 */
+ { PARSER_RRTYPE_NS, T_NS, "NS", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 3 */
+ { PARSER_RRTYPE_MD, T_MD, "MD", 1,
+ { PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 4 */
+ { PARSER_RRTYPE_MF, T_MF, "MF", 1,
+ { PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 5 */
+ { PARSER_RRTYPE_CNAME, T_CNAME, "CNAME", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 6 */
+ { PARSER_RRTYPE_SOA, T_SOA, "SOA", 7,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME, PARSER_RDATA_WF_COMPRESSED_DNAME,
+ PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG,
+ PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG }, true },
+ /* 7 */
+ { PARSER_RRTYPE_MB, T_MB, "MB", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 8 */
+ { PARSER_RRTYPE_MG, T_MG, "MG", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 9 */
+ { PARSER_RRTYPE_MR, T_MR, "MR", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 10 */
+ { PARSER_RRTYPE_NULL, T_NULL, NULL, 1,
+ { PARSER_RDATA_WF_BINARY }, true },
+ /* 11 */
+ { PARSER_RRTYPE_WKS, T_WKS, "WKS", 2,
+ { PARSER_RDATA_WF_A, PARSER_RDATA_WF_BINARY }, true },
+ /* 12 */
+ { PARSER_RRTYPE_PTR, T_PTR, "PTR", 1,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 13 */
+ { PARSER_RRTYPE_HINFO, T_HINFO, "HINFO", 2,
+ { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, true },
+ /* 14 */
+ { PARSER_RRTYPE_MINFO, T_MINFO, "MINFO", 2,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME,
+ PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 15 */
+ { PARSER_RRTYPE_MX, T_MX, "MX", 2,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 16 */ /* This is obscure, but I guess there's no other way */
+ { PARSER_RRTYPE_TXT, T_TXT, "TXT", PARSER_MAX_RDATA_ITEMS,
+ { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, false },
+ /* 17 */
+ { PARSER_RRTYPE_RP, T_RP, "RP", 2,
+ { PARSER_RDATA_WF_COMPRESSED_DNAME,
+ PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 18 */
+ { PARSER_RRTYPE_AFSDB, T_AFSDB, "AFSDB", 2,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 19 */
+ { PARSER_RRTYPE_X25, T_X25, "X25", 1,
+ { PARSER_RDATA_WF_TEXT }, true },
+ /* 20 */
+ { PARSER_RRTYPE_ISDN, T_ISDN, "ISDN", 2,
+ { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, false },
+ /* 21 */
+ { PARSER_RRTYPE_RT, T_RT, "RT", 2,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_COMPRESSED_DNAME }, true },
+ /* 22 */
+ { PARSER_RRTYPE_NSAP, T_NSAP, "NSAP", 1,
+ { PARSER_RDATA_WF_BINARY }, true },
+ /* 23 */
+ { 23, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 24 */
+ { PARSER_RRTYPE_SIG, T_SIG, "SIG", 9,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG,
+ PARSER_RDATA_WF_SHORT,PARSER_RDATA_WF_UNCOMPRESSED_DNAME,
+ PARSER_RDATA_WF_BINARY }, true },
+ /* 25 */
+ { PARSER_RRTYPE_KEY, T_KEY, "KEY", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true },
+ /* 26 */
+ { PARSER_RRTYPE_PX, T_PX, "PX", 3,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_UNCOMPRESSED_DNAME,
+ PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 27 */
+ { 27, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 28 */
+ { PARSER_RRTYPE_AAAA, T_AAAA, "AAAA", 1,
+ { PARSER_RDATA_WF_AAAA }, true },
+ /* 29 */
+ { PARSER_RRTYPE_LOC, T_LOC, "LOC", 1,
+ { PARSER_RDATA_WF_BINARY }, true },
+ /* 30 */
+ { PARSER_RRTYPE_NXT, T_NXT, "NXT", 2,
+ { PARSER_RDATA_WF_UNCOMPRESSED_DNAME,
+ PARSER_RDATA_WF_BINARY }, true },
+ /* 31 */
+ { 31, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 32 */
+ { 32, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 33 */
+ { PARSER_RRTYPE_SRV, T_SRV, "SRV", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_SHORT,
+ PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_UNCOMPRESSED_DNAME },
+ true },
+ /* 34 */
+ { 34, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 35 */
+ { PARSER_RRTYPE_NAPTR, T_NAPTR, "NAPTR", 6,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 36 */
+ { PARSER_RRTYPE_KX, T_KX, "KX", 2,
+ { PARSER_RDATA_WF_SHORT,
+ PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 37 */
+ { PARSER_RRTYPE_CERT, T_CERT, "CERT", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_SHORT,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true },
+ /* 38 */
+ { PARSER_RRTYPE_A6, T_A6, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 39 */
+ { PARSER_RRTYPE_DNAME, T_DNAME, "DNAME", 1,
+ { PARSER_RDATA_WF_UNCOMPRESSED_DNAME }, true },
+ /* 40 */
+ { 40, 0, NULL, 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 41 */
+ /* OPT has its parser token, but should never be in zone file... */
+ { PARSER_RRTYPE_OPT, T_OPT, "OPT", 1,
+ { PARSER_RDATA_WF_BINARY }, true },
+ /* 42 */
+ { PARSER_RRTYPE_APL, T_APL, "APL", PARSER_MAX_RDATA_ITEMS,
+ { PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL,
+ PARSER_RDATA_WF_APL, PARSER_RDATA_WF_APL }, false },
+ /* 43 */
+ { PARSER_RRTYPE_DS, T_DS, "DS", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true },
+ /* 44 */
+ { PARSER_RRTYPE_SSHFP, T_SSHFP, "SSHFP", 3,
+ { PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BINARY }, true },
+ /* 45 */
+ { PARSER_RRTYPE_IPSECKEY, T_IPSECKEY, "IPSECKEY", 5,
+ { PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_IPSECGATEWAY,
+ PARSER_RDATA_WF_BINARY }, false },
+ /* 46 */
+ { PARSER_RRTYPE_RRSIG, T_RRSIG, "RRSIG", 9,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_LONG,
+ PARSER_RDATA_WF_LONG, PARSER_RDATA_WF_LONG,
+ PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BINARY,
+ PARSER_RDATA_WF_BINARY }, true },
+ /* 47 */
+ { PARSER_RRTYPE_NSEC, T_NSEC, "NSEC", 2,
+ { PARSER_RDATA_WF_BINARY, PARSER_RDATA_WF_BINARY }, true },
+ /* 48 */
+ { PARSER_RRTYPE_DNSKEY, T_DNSKEY, "DNSKEY", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY }, true },
+ /* 49 */
+ { PARSER_RRTYPE_DHCID, T_DHCID, "DHCID", 1, { PARSER_RDATA_WF_BINARY }, true },
+ /* 50 */
+ { PARSER_RRTYPE_NSEC3, T_NSEC3, "NSEC3", 6,
+ { PARSER_RDATA_WF_BYTE, /* hash type */
+ PARSER_RDATA_WF_BYTE, /* flags */
+ PARSER_RDATA_WF_SHORT, /* iterations */
+ PARSER_RDATA_WF_BINARYWITHLENGTH, /* salt */
+ PARSER_RDATA_WF_BINARYWITHLENGTH, /* next hashed name */
+ PARSER_RDATA_WF_BINARY /* type bitmap */ }, true },
+ /* 51 */
+ { PARSER_RRTYPE_NSEC3PARAM, T_NSEC3PARAM, "NSEC3PARAM", 4,
+ { PARSER_RDATA_WF_BYTE, /* hash type */
+ PARSER_RDATA_WF_BYTE, /* flags */
+ PARSER_RDATA_WF_SHORT, /* iterations */
+ PARSER_RDATA_WF_BINARYWITHLENGTH /* salt */ }, true },
+ /* 52 */
+
+
+ /* In NSD they have indices between 52 and 99 filled with
+ unknown types. TODO add here if it's really needed? */
+ /* it is indeed needed, in rrtype_from_string */
+
+ /* There's a GNU extension that works like this: [first ... last] = value */
+
+ [53 ... 98] = { PARSER_RRTYPE_TYPEXXX, T_UTYPE, NULL, 1, { PARSER_RDATA_WF_BINARY }},
+
+ /* 99 */
+ [99] = { PARSER_RRTYPE_SPF, T_SPF, "SPF", PARSER_MAX_RDATA_ITEMS,
+ { PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT,
+ PARSER_RDATA_WF_TEXT, PARSER_RDATA_WF_TEXT }, false },
+ [100 ... 32768] = { PARSER_RRTYPE_TYPEXXX, T_UTYPE, NULL, 1, { PARSER_RDATA_WF_BINARY }},
+ /* 32769 */
+ [32769] = { PARSER_RRTYPE_DLV, T_DLV, "DLV", 4,
+ { PARSER_RDATA_WF_SHORT, PARSER_RDATA_WF_BYTE,
+ PARSER_RDATA_WF_BYTE, PARSER_RDATA_WF_BINARY } },
+};
+
+parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_type(uint16_t type)
+{
+ if (type <= PARSER_RRTYPE_DLV) {
+ return &knot_rrtype_descriptors[type];
+ }
+ return &knot_rrtype_descriptors[0];
+}
+
+/* I see a lot of potential here to speed up zone parsing - this is O(n) *
+ * could be better */
+parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_name(const char *name)
+{
+ if (!name) {
+ return NULL;
+ }
+
+ if (strcasecmp(name, "IN") == 0) {
+ return NULL;
+ }
+
+ if (isdigit((int)name[0])) {
+ return NULL;
+ }
+
+// /* The most common - A and NS. */
+// if (strcasecmp(name, "NS") == 0) {
+// return &knot_rrtype_descriptors[2];
+// }
+
+// if (strcasecmp(name, "A") == 0) {
+// return &knot_rrtype_descriptors[1];
+// }
+
+// /* Then RRSIG */
+// if (strcasecmp(name, "RRSIG") == 0) {
+// return &knot_rrtype_descriptors[46];
+// }
+
+// /* Then DS */
+// if (strcasecmp(name, "DS") == 0) {
+// return &knot_rrtype_descriptors[43];
+// }
+// /* Then NSEC3 */
+// if (strcasecmp(name, "NSEC3") == 0) {
+// return &knot_rrtype_descriptors[50];
+// }
+// /* Then NSEC */
+// if (strcasecmp(name, "NSEC") == 0) {
+// return &knot_rrtype_descriptors[47];
+// }
+
+ int i;
+
+ for (i = 0; i < PARSER_RRTYPE_LAST + 1; ++i) {
+ if (knot_rrtype_descriptors[i].name &&
+ strcasecmp(knot_rrtype_descriptors[i].name, name) == 0) {
+ return &knot_rrtype_descriptors[i];
+ }
+ }
+
+ if (knot_rrtype_descriptors[PARSER_RRTYPE_DLV].name &&
+ strcasecmp(knot_rrtype_descriptors[PARSER_RRTYPE_DLV].name,
+ name) == 0) {
+ return &knot_rrtype_descriptors[PARSER_RRTYPE_DLV];
+ }
+
+ return NULL;
+}
+
+const char *parser_rrtype_to_string(uint16_t rrtype)
+{
+ static char buf[20];
+ parser_rrtype_descriptor_t *descriptor =
+ parser_rrtype_descriptor_by_type(rrtype);
+ if (descriptor->name) {
+ return descriptor->name;
+ } else {
+ snprintf(buf, sizeof(buf), "TYPE%d", (int) rrtype);
+ return buf;
+ }
+}
+
+uint16_t parser_rrtype_from_string(const char *name)
+{
+ char *end;
+ long rrtype;
+ parser_rrtype_descriptor_t *entry;
+
+ entry = parser_rrtype_descriptor_by_name(name);
+ if (entry) {
+ return entry->type;
+ }
+
+ if (strlen(name) < 5) {
+ return 0;
+ }
+
+ if (strncasecmp(name, "TYPE", 4) != 0) {
+ return 0;
+ }
+
+ if (!isdigit((int)name[4])) {
+ return 0;
+ }
+
+ /* The rest from the string must be a number. */
+ rrtype = strtol(name + 4, &end, 10);
+ if (*end != '\0') {
+ return 0;
+ }
+ if (rrtype < 0 || rrtype > 65535L) {
+ return 0;
+ }
+
+ return (uint16_t) rrtype;
+}
+
+const char *parser_rrclass_to_string(uint16_t rrclass)
+{
+ static char buf[20];
+ knot_lookup_table_t *entry = knot_lookup_by_id(dns_rrclasses,
+ rrclass);
+ if (entry) {
+ assert(strlen(entry->name) < sizeof(buf));
+ knot_strlcpy(buf, entry->name, sizeof(buf));
+ } else {
+ snprintf(buf, sizeof(buf), "CLASS%d", (int) rrclass);
+ }
+ return buf;
+}
+
+uint16_t parser_rrclass_from_string(const char *name)
+{
+ char *end;
+ long rrclass;
+ knot_lookup_table_t *entry;
+
+ entry = knot_lookup_by_name(dns_rrclasses, name);
+ if (entry) {
+ return (uint16_t) entry->id;
+ }
+
+ if (strlen(name) < 6) {
+ return 0;
+ }
+
+ if (strncasecmp(name, "CLASS", 5) != 0) {
+ return 0;
+ }
+
+ if (!isdigit((int)name[5])) {
+ return 0;
+ }
+
+ // The rest from the string must be a number.
+ rrclass = strtol(name + 5, &end, 10);
+ if (*end != '\0') {
+ return 0;
+ }
+ if (rrclass < 0 || rrclass > 65535L) {
+ return 0;
+ }
+
+ return (uint16_t) rrclass;
+}
+
diff --git a/src/zcompile/parser-descriptor.h b/src/zcompile/parser-descriptor.h
new file mode 100644
index 0000000..c7865dd
--- /dev/null
+++ b/src/zcompile/parser-descriptor.h
@@ -0,0 +1,278 @@
+/*!
+ * \file parser-descriptor.h
+ *
+ * \author Modifications by Jan Kadlec <jan.kadlec@nic.cz>,
+ * most of the work by NLnet Labs.
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief Contains resource record descriptor and its API
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KNOTD_PARSER_DESCRIPTOR_H_
+#define _KNOTD_PARSER_DESCRIPTOR_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libknot/util/utils.h"
+
+enum parser_mxrdtln {
+ PARSER_MAX_RDATA_ITEMS = 64,
+ PARSER_MAX_RDATA_ITEM_SIZE = 255,
+ PARSER_MAX_RDATA_WIRE_SIZE =
+ PARSER_MAX_RDATA_ITEMS * PARSER_MAX_RDATA_ITEM_SIZE
+};
+//#define MAXRDATALEN 64
+
+/* 64 is in NSD. Seems a little too much, but I'd say it's not a real issue. */
+
+/*!
+ * \brief Enum containing RR class codes.
+ */
+enum parser_rr_class {
+ PARSER_CLASS_IN = 1,
+ PARSER_CLASS_CS,
+ PARSER_CLASS_CH,
+ PARSER_CLASS_HS,
+ PARSER_CLASS_NONE = 254,
+ PARSER_CLASS_ANY = 255
+};
+
+typedef enum parser_rr_class parser_rr_class_t;
+
+enum parser_rr_type {
+ PARSER_RRTYPE_UNKNOWN, /*!< 0 - an unknown type */
+ PARSER_RRTYPE_A, /*!< 1 - a host address */
+ PARSER_RRTYPE_NS, /*!< 2 - an authoritative name server */
+ PARSER_RRTYPE_MD, /*!< 3 - a mail destination (Obsolete - use MX) */
+ PARSER_RRTYPE_MF, /*!< 4 - a mail forwarder (Obsolete - use MX) */
+ PARSER_RRTYPE_CNAME, /*!< 5 - the canonical name for an alias */
+ PARSER_RRTYPE_SOA, /*!< 6 - marks the start of a zone of authority */
+ PARSER_RRTYPE_MB, /*!< 7 - a mailbox domain name (EXPERIMENTAL) */
+ PARSER_RRTYPE_MG, /*!< 8 - a mail group member (EXPERIMENTAL) */
+ PARSER_RRTYPE_MR, /*!< 9 - a mail rename domain name (EXPERIMENTAL) */
+ PARSER_RRTYPE_NULL, /*!< 10 - a null RR (EXPERIMENTAL) */
+ PARSER_RRTYPE_WKS, /*!< 11 - a well known service description */
+ PARSER_RRTYPE_PTR, /*!< 12 - a domain name pointer */
+ PARSER_RRTYPE_HINFO, /*!< 13 - host information */
+ PARSER_RRTYPE_MINFO, /*!< 14 - mailbox or mail list information */
+ PARSER_RRTYPE_MX, /*!< 15 - mail exchange */
+ PARSER_RRTYPE_TXT, /*!< 16 - text strings */
+ PARSER_RRTYPE_RP, /*!< 17 - RFC1183 */
+ PARSER_RRTYPE_AFSDB, /*!< 18 - RFC1183 */
+ PARSER_RRTYPE_X25, /*!< 19 - RFC1183 */
+ PARSER_RRTYPE_ISDN, /*!< 20 - RFC1183 */
+ PARSER_RRTYPE_RT, /*!< 21 - RFC1183 */
+ PARSER_RRTYPE_NSAP, /*!< 22 - RFC1706 */
+
+ PARSER_RRTYPE_SIG = 24, /*!< 24 - 2535typecode */
+ PARSER_RRTYPE_KEY, /*!< 25 - 2535typecode */
+ PARSER_RRTYPE_PX, /*!< 26 - RFC2163 */
+
+ PARSER_RRTYPE_AAAA = 28, /*!< 28 - ipv6 address */
+ PARSER_RRTYPE_LOC, /*!< 29 - LOC record RFC1876 */
+ PARSER_RRTYPE_NXT, /*!< 30 - 2535typecode */
+
+ PARSER_RRTYPE_SRV = 33, /*!< 33 - SRV record RFC2782 */
+
+ PARSER_RRTYPE_NAPTR = 35, /*!< 35 - RFC2915 */
+ PARSER_RRTYPE_KX, /*!< 36 - RFC2230 Key Exchange Delegation Record */
+ PARSER_RRTYPE_CERT, /*!< 37 - RFC2538 */
+ PARSER_RRTYPE_A6, /*!< 38 - RFC2874 */
+ PARSER_RRTYPE_DNAME, /*!< 39 - RFC2672 */
+
+ PARSER_RRTYPE_OPT = 41, /*!< 41 - Pseudo OPT record... */
+ PARSER_RRTYPE_APL, /*!< 42 - RFC3123 */
+ PARSER_RRTYPE_DS, /*!< 43 - RFC 4033, 4034, and 4035 */
+ PARSER_RRTYPE_SSHFP, /*!< 44 - SSH Key Fingerprint */
+ PARSER_RRTYPE_IPSECKEY, /*!< 45 - public key for ipsec use. RFC 4025 */
+ PARSER_RRTYPE_RRSIG, /*!< 46 - RFC 4033, 4034, and 4035 */
+ PARSER_RRTYPE_NSEC, /*!< 47 - RFC 4033, 4034, and 4035 */
+ PARSER_RRTYPE_DNSKEY, /*!< 48 - RFC 4033, 4034, and 4035 */
+ PARSER_RRTYPE_DHCID, /*!< 49 - RFC4701 DHCP information */
+ /*!
+ * \brief 50 - NSEC3, secure denial, prevents zonewalking
+ */
+ PARSER_RRTYPE_NSEC3,
+ /*!
+ * \brief 51 - NSEC3PARAM at zone apex nsec3 parameters
+ */
+ PARSER_RRTYPE_NSEC3PARAM,
+
+ /* TODO consider some better way of doing this, indices too high */
+
+ PARSER_RRTYPE_SPF = 99, /*!< RFC 4408 */
+
+ // not designating any RRs
+ PARSER_RRTYPE_TSIG = 250,
+ PARSER_RRTYPE_IXFR = 251,
+ PARSER_RRTYPE_AXFR = 252,
+ /*!
+ * \brief A request for mailbox-related records (MB, MG or MR)
+ */
+ PARSER_RRTYPE_MAILB = 253,
+ /*!
+ * \brief A request for mail agent RRs (Obsolete - see MX)
+ */
+ PARSER_RRTYPE_MAILA = 254,
+ PARSER_RRTYPE_ANY = 255, /*!< any type (wildcard) */
+
+ // totally weird numbers (cannot use for indexing)
+ PARSER_RRTYPE_TA = 32768, /*!< DNSSEC Trust Authorities */
+ PARSER_RRTYPE_DLV = 32769, /*!< RFC 4431 */
+ PARSER_RRTYPE_TYPEXXX = 32770
+};
+
+/*!
+ * \brief Enum containing RR type codes.
+ *
+ * \todo Not all indices can be used for indexing.
+ */
+typedef enum parser_rr_type parser_rr_type_t;
+
+static uint const PARSER_RRTYPE_LAST = PARSER_RRTYPE_NSEC3PARAM;
+
+enum parser_rdata_wireformat {
+ /*!
+ * \brief Possibly compressed domain name.
+ */
+ PARSER_RDATA_WF_COMPRESSED_DNAME = 50,
+ PARSER_RDATA_WF_UNCOMPRESSED_DNAME = 51, /*!< Uncompressed domain name. */
+ PARSER_RDATA_WF_LITERAL_DNAME = 52, /*!< Literal (not downcased) dname. */
+ PARSER_RDATA_WF_BYTE = 1, /*!< 8-bit integer. */
+ PARSER_RDATA_WF_SHORT = 2, /*!< 16-bit integer. */
+ PARSER_RDATA_WF_LONG = 4, /*!< 32-bit integer. */
+ PARSER_RDATA_WF_TEXT = 53, /*!< Text string. */
+ PARSER_RDATA_WF_A = 58, /*!< 32-bit IPv4 address. */
+ PARSER_RDATA_WF_AAAA = 16, /*!< 128-bit IPv6 address. */
+ PARSER_RDATA_WF_BINARY = 54, /*!< Binary data (unknown length). */
+ /*!
+ * \brief Binary data preceded by 1 byte length
+ */
+ PARSER_RDATA_WF_BINARYWITHLENGTH = 55,
+ PARSER_RDATA_WF_APL = 56, /*!< APL data. */
+ PARSER_RDATA_WF_IPSECGATEWAY = 57 /*!< IPSECKEY gateway ip4, ip6 or dname. */
+};
+
+/*!
+ * \brief Enum containing wireformat codes. Taken from NSD's "dns.h"
+ */
+typedef enum parser_rdatawireformat parser_rdata_wireformat_t;
+
+struct parser_rrtype_descriptor {
+ uint16_t type; /*!< RR type */
+ int token; /*< Token used in zoneparser */
+ const char *name; /*!< Textual name. */
+ uint8_t length; /*!< Maximum number of RDATA items. */
+ /*!
+ * \brief rdata_wireformat_type
+ */
+ uint8_t wireformat[PARSER_MAX_RDATA_ITEMS];
+ bool fixed_items; /*!< Has fixed number of RDATA items? */
+};
+
+/*!
+ * \brief Structure holding RR descriptor
+ */
+typedef struct parser_rrtype_descriptor parser_rrtype_descriptor_t;
+
+/*!
+ * \brief Gets RR descriptor for given RR type.
+ *
+ * \param type Code of RR type whose descriptor should be returned.
+ *
+ * \return RR descriptor for given type code, NULL descriptor if
+ * unknown type.
+ *
+ * \todo Change return value to const.
+ */
+parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_type(uint16_t type);
+
+/*!
+ * \brief Gets RR descriptor for given RR name.
+ *
+ * \param name Mnemonic of RR type whose descriptor should be returned.
+ *
+ * \return RR descriptor for given name, NULL descriptor if
+ * unknown type.
+ *
+ * \todo Change return value to const.
+ */
+parser_rrtype_descriptor_t *parser_rrtype_descriptor_by_name(const char *name);
+
+/*!
+ * \brief Converts numeric type representation to mnemonic string.
+ *
+ * \param rrtype Type RR type code to be converted.
+ *
+ * \return Mnemonic string if found, str(TYPE[rrtype]) otherwise.
+ */
+const char *parser_rrtype_to_string(uint16_t rrtype);
+
+/*!
+ * \brief Converts mnemonic string representation of a type to numeric one.
+ *
+ * \param name Mnemonic string to be converted.
+ *
+ * \return Correct code if found, 0 otherwise.
+ */
+uint16_t parser_rrtype_from_string(const char *name);
+
+/*!
+ * \brief Converts numeric class representation to string one.
+ *
+ * \param rrclass Class code to be converted.
+ *
+ * \return String represenation of class if found,
+ * str(CLASS[rrclass]) otherwise.
+ */
+const char *parser_rrclass_to_string(uint16_t rrclass);
+
+/*!
+ * \brief Converts string representation of a class to numeric one.
+ *
+ * \param name Class string to be converted.
+ *
+ * \return Correct code if found, 0 otherwise.
+ */
+uint16_t parser_rrclass_from_string(const char *name);
+
+#endif /* _KNOTD_PARSER_DESCRIPTOR_H_ */
+
+/*! @} */
diff --git a/src/zcompile/parser-util.c b/src/zcompile/parser-util.c
new file mode 100644
index 0000000..e7733ef
--- /dev/null
+++ b/src/zcompile/parser-util.c
@@ -0,0 +1,2435 @@
+/*!
+ * \file parser-util.c
+ *
+ * \author NLnet Labs
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief utility functions for zone parser.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+//#include "common.h"
+#include "common/base32hex.h"
+#include "zcompile/parser-util.h"
+#include "zcompile/zcompile.h"
+#include "libknot/util/descriptor.h"
+#include "libknot/util/utils.h"
+#include "zcompile/zcompile-error.h"
+
+#define IP6ADDRLEN (128/8)
+#define NS_INT16SZ 2
+#define NS_INADDRSZ 4
+#define NS_IN6ADDRSZ 16
+#define APL_NEGATION_MASK 0x80U
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ * Paul Vixie, 1996.
+ */
+int inet_pton(int af, const char *src, void *dst)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+ case AF_INET6:
+ return (inet_pton6(src, dst));
+ default:
+ errno = EAFNOSUPPORT;
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+//int my_b32_pton(const char *src, uint8_t *target, size_t tsize)
+//{
+// char ch;
+// size_t p = 0;
+
+// memset(target, '\0', tsize);
+// while ((ch = *src++)) {
+// uint8_t d;
+// size_t b;
+// size_t n;
+
+// if (p + 5 >= tsize * 8) {
+// return -1;
+// }
+
+// if (isspace(ch)) {
+// continue;
+// }
+
+// if (ch >= '0' && ch <= '9') {
+// d = ch - '0';
+// } else if (ch >= 'A' && ch <= 'V') {
+// d = ch - 'A' + 10;
+// } else if (ch >= 'a' && ch <= 'v') {
+// d = ch - 'a' + 10;
+// } else {
+// return -1;
+// }
+
+// b = 7 - p % 8;
+// n = p / 8;
+
+// if (b >= 4) {
+// target[n] |= d << (b - 4);
+// } else {
+// target[n] |= d >> (4 - b);
+// target[n+1] |= d << (b + 4);
+// }
+// p += 5;
+// }
+// return (p + 7) / 8;
+//}
+
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+int inet_pton4(const char *src, uint8_t *dst)
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ uint8_t tmp[NS_INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ uint32_t new = *tp * 10 + (pch - digits);
+
+ if (new > 255) {
+ return (0);
+ }
+ *tp = new;
+ if (! saw_digit) {
+ if (++octets > 4) {
+ return (0);
+ }
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4) {
+ return (0);
+ }
+ *++tp = 0;
+ saw_digit = 0;
+ } else {
+ return (0);
+ }
+ }
+ if (octets < 4) {
+ return (0);
+ }
+
+ memcpy(dst, tmp, NS_INADDRSZ);
+ return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+int inet_pton6(const char *src, uint8_t *dst)
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ uint8_t tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ uint32_t val;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':') {
+ return (0);
+ }
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) {
+ pch = strchr((xdigits = xdigits_u), ch);
+ }
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (val > 0xffff) {
+ return (0);
+ }
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp) {
+ return (0);
+ }
+ colonp = tp;
+ continue;
+ }
+ if (tp + NS_INT16SZ > endp) {
+ return (0);
+ }
+ *tp++ = (uint8_t)(val >> 8) & 0xff;
+ *tp++ = (uint8_t) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp) {
+ return (0);
+ }
+ *tp++ = (uint8_t)(val >> 8) & 0xff;
+ *tp++ = (uint8_t) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp) {
+ return (0);
+ }
+ memcpy(dst, tmp, NS_IN6ADDRSZ);
+ return (1);
+}
+
+
+#ifndef IN6ADDRSZ
+#define IN6ADDRSZ 16 /* IPv6 T_AAAA */
+#endif
+
+#ifndef INT16SZ
+#define INT16SZ 2 /* for systems without 16-bit ints */
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ * Paul Vixie, 1996.
+ */
+//const char *inet_ntop(int af, const void *src, char *dst, size_t size)
+//{
+// switch (af) {
+// case AF_INET:
+// return (inet_ntop4(src, dst, size));
+// case AF_INET6:
+// return (inet_ntop6(src, dst, size));
+// default:
+// errno = EAFNOSUPPORT;
+// return (NULL);
+// }
+// /* NOTREACHED */
+//}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address, more or less like inet_ntoa()
+ * return:
+ * `dst' (as a const)
+ * notes:
+ * (1) uses no statics
+ * (2) takes a u_char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *inet_ntop4(const u_char *src, char *dst, size_t size)
+{
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+ int l;
+
+ l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]);
+ if (l <= 0 || l >= (int)size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ knot_strlcpy(dst, tmp, size);
+ return (dst);
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+const char *inet_ntop6(const u_char *src, char *dst, size_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+ char *tp, *ep;
+ struct {
+ int base, len;
+ } best, cur;
+ best.base = cur.base =-1;
+ best.len = cur.len = 0;
+ u_int words[IN6ADDRSZ / INT16SZ];
+ int i;
+ int advance;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < IN6ADDRSZ; i++) {
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ }
+
+ for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1) {
+ cur.base = i, cur.len = 1;
+ } else {
+ cur.len++;
+ }
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len) {
+ best = cur;
+ }
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len) {
+ best = cur;
+ }
+ }
+ if (best.base != -1 && best.len < 2) {
+ best.base = -1;
+ }
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ ep = tmp + sizeof(tmp);
+ for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base) {
+ if (tp + 1 >= ep) {
+ return (NULL);
+ }
+ *tp++ = ':';
+ }
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0) {
+ if (tp + 1 >= ep) {
+ return (NULL);
+ }
+ *tp++ = ':';
+ }
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 ||
+ (best.len == 5 && words[5] == 0xffff))) {
+ if (!inet_ntop4(src + 12, tp, (size_t)(ep - tp))) {
+ return (NULL);
+ }
+ tp += strlen(tp);
+ break;
+ }
+ advance = snprintf(tp, ep - tp, "%x", words[i]);
+ if (advance <= 0 || advance >= ep - tp) {
+ return (NULL);
+ }
+ tp += advance;
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) ==
+ (IN6ADDRSZ / INT16SZ)) {
+ if (tp + 1 >= ep) {
+ return (NULL);
+ }
+ *tp++ = ':';
+ }
+ if (tp + 1 >= ep) {
+ return (NULL);
+ }
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+ knot_strlcpy(dst, tmp, size);
+ return (dst);
+}
+
+
+static int b64rmap_initialized = 0;
+static uint8_t b64rmap[256];
+
+static const uint8_t b64rmap_special = 0xf0;
+static const uint8_t b64rmap_end = 0xfd;
+static const uint8_t b64rmap_space = 0xfe;
+static const uint8_t b64rmap_invalid = 0xff;
+
+/**
+ * Initializing the reverse map is not thread safe.
+ * Which is fine for NSD. For now...
+ **/
+void b64_initialize_rmap()
+{
+ int i;
+ char ch;
+
+ /* Null: end of string, stop parsing */
+ b64rmap[0] = b64rmap_end;
+
+ for (i = 1; i < 256; ++i) {
+ ch = (char)i;
+ /* Whitespaces */
+ if (isspace(ch)) {
+ b64rmap[i] = b64rmap_space;
+ }
+ /* Padding: stop parsing */
+ else if (ch == Pad64) {
+ b64rmap[i] = b64rmap_end;
+ }
+ /* Non-base64 char */
+ else {
+ b64rmap[i] = b64rmap_invalid;
+ }
+ }
+
+ /* Fill reverse mapping for base64 chars */
+ for (i = 0; Base64[i] != '\0'; ++i) {
+ b64rmap[(uint8_t)Base64[i]] = i;
+ }
+
+ b64rmap_initialized = 1;
+}
+
+int b64_pton_do(char const *src, uint8_t *target, size_t targsize)
+{
+ int tarindex, state, ch;
+ uint8_t ofs;
+
+ state = 0;
+ tarindex = 0;
+
+ while (1) {
+ ch = *src++;
+ ofs = b64rmap[ch];
+
+ if (ofs >= b64rmap_special) {
+ /* Ignore whitespaces */
+ if (ofs == b64rmap_space) {
+ continue;
+ }
+ /* End of base64 characters */
+ if (ofs == b64rmap_end) {
+ break;
+ }
+ /* A non-base64 character. */
+ return (-1);
+ }
+
+ switch (state) {
+ case 0:
+ if ((size_t)tarindex >= targsize) {
+ return (-1);
+ }
+ target[tarindex] = ofs << 2;
+ state = 1;
+ break;
+ case 1:
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-1);
+ }
+ target[tarindex] |= ofs >> 4;
+ target[tarindex+1] = (ofs & 0x0f)
+ << 4 ;
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if ((size_t)tarindex + 1 >= targsize) {
+ return (-1);
+ }
+ target[tarindex] |= ofs >> 2;
+ target[tarindex+1] = (ofs & 0x03)
+ << 6;
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if ((size_t)tarindex >= targsize) {
+ return (-1);
+ }
+ target[tarindex] |= ofs;
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ break;
+ }
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64) {
+ return (-1);
+ }
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ return (-1);
+ }
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target[tarindex] != 0) {
+ return (-1);
+ }
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0) {
+ return (-1);
+ }
+ }
+
+ return (tarindex);
+}
+
+
+int b64_pton_len(char const *src)
+{
+ int tarindex, state, ch;
+ uint8_t ofs;
+
+ state = 0;
+ tarindex = 0;
+
+ while (1) {
+ ch = *src++;
+ ofs = b64rmap[ch];
+
+ if (ofs >= b64rmap_special) {
+ /* Ignore whitespaces */
+ if (ofs == b64rmap_space) {
+ continue;
+ }
+ /* End of base64 characters */
+ if (ofs == b64rmap_end) {
+ break;
+ }
+ /* A non-base64 character. */
+ return (-1);
+ }
+
+ switch (state) {
+ case 0:
+ state = 1;
+ break;
+ case 1:
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ break;
+ }
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64) {
+ return (-1);
+ }
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (b64rmap[ch] != b64rmap_space) {
+ return (-1);
+ }
+
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0) {
+ return (-1);
+ }
+ }
+
+ return (tarindex);
+}
+
+int b64_pton(char const *src, uint8_t *target, size_t targsize)
+{
+ if (!b64rmap_initialized) {
+ b64_initialize_rmap();
+ }
+
+ if (target) {
+ return b64_pton_do(src, target, targsize);
+ } else {
+ return b64_pton_len(src);
+ }
+}
+
+void set_bit(uint8_t bits[], size_t index)
+{
+ /*
+ * The bits are counted from left to right, so bit #0 is the
+ * left most bit.
+ */
+ bits[index / 8] |= (1 << (7 - index % 8));
+}
+
+uint32_t strtoserial(const char *nptr, const char **endptr)
+{
+ uint32_t i = 0;
+ uint32_t serial = 0;
+
+ for (*endptr = nptr; **endptr; (*endptr)++) {
+ switch (**endptr) {
+ case ' ':
+ case '\t':
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i *= 10;
+ i += (**endptr - '0');
+ break;
+ default:
+ break;
+ }
+ }
+ serial += i;
+ return serial;
+}
+
+inline void write_uint32(void *dst, uint32_t data)
+{
+#ifdef ALLOW_UNALIGNED_ACCESSES
+ *(uint32_t *) dst = htonl(data);
+#else
+ uint8_t *p = (uint8_t *) dst;
+ p[0] = (uint8_t)((data >> 24) & 0xff);
+ p[1] = (uint8_t)((data >> 16) & 0xff);
+ p[2] = (uint8_t)((data >> 8) & 0xff);
+ p[3] = (uint8_t)(data & 0xff);
+#endif
+}
+
+uint32_t strtottl(const char *nptr, const char **endptr)
+{
+ uint32_t i = 0;
+ uint32_t seconds = 0;
+
+ for (*endptr = nptr; **endptr; (*endptr)++) {
+ switch (**endptr) {
+ case ' ':
+ case '\t':
+ break;
+ case 's':
+ case 'S':
+ seconds += i;
+ i = 0;
+ break;
+ case 'm':
+ case 'M':
+ seconds += i * 60;
+ i = 0;
+ break;
+ case 'h':
+ case 'H':
+ seconds += i * 60 * 60;
+ i = 0;
+ break;
+ case 'd':
+ case 'D':
+ seconds += i * 60 * 60 * 24;
+ i = 0;
+ break;
+ case 'w':
+ case 'W':
+ seconds += i * 60 * 60 * 24 * 7;
+ i = 0;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ i *= 10;
+ i += (**endptr - '0');
+ break;
+ default:
+ seconds += i;
+ return seconds;
+ }
+ }
+ seconds += i;
+ return seconds;
+}
+
+/* Number of days per month (except for February in leap years). */
+static const int mdays[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static int is_leap_year(int year)
+{
+ return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
+}
+
+static int leap_days(int y1, int y2)
+{
+ --y1;
+ --y2;
+ return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400);
+}
+
+/*
+ * Code adapted from Python 2.4.1 sources (Lib/calendar.py).
+ */
+time_t mktime_from_utc(const struct tm *tm)
+{
+ int year = 1900 + tm->tm_year;
+ time_t days = 365 * (year - 1970) + leap_days(1970, year);
+ time_t hours;
+ time_t minutes;
+ time_t seconds;
+ int i;
+
+ for (i = 0; i < tm->tm_mon; ++i) {
+ days += mdays[i];
+ }
+ if (tm->tm_mon > 1 && is_leap_year(year)) {
+ ++days;
+ }
+ days += tm->tm_mday - 1;
+
+ hours = days * 24 + tm->tm_hour;
+ minutes = hours * 60 + tm->tm_min;
+ seconds = minutes * 60 + tm->tm_sec;
+
+ return seconds;
+}
+
+/*!< Following functions are conversions from text to wire. */
+
+//#define DEBUG_UNKNOWN_RDATA
+
+#ifdef DEBUG_UNKNOWN_RDATA
+#define dbg_rdata(msg...) fprintf(stderr, msg)
+#define DBG_RDATA(cmds) do { cmds } while (0)
+#else
+#define dbg_rdata(msg...)
+#define DBG_RDATA(cmds)
+#endif
+
+
+
+#define IP6ADDRLEN (128/8)
+#define NS_INT16SZ 2
+#define NS_INADDRSZ 4
+#define NS_IN6ADDRSZ 16
+#define APL_NEGATION_MASK 0x80U
+#define APL_LENGTH_MASK (~APL_NEGATION_MASK)
+
+//#define ZP_DEBUG
+
+#ifdef ZP_DEBUG
+#define dbg_zp(msg...) fprintf(stderr, msg)
+#else
+#define dbg_zp(msg...)
+#endif
+
+
+/*!
+ * \brief Return data of raw data item.
+ *
+ * \param item Item.
+ * \return uint16_t * Raw data.
+ */
+static inline uint16_t * rdata_atom_data(knot_rdata_item_t item)
+{
+ return (uint16_t *)(item.raw_data + 1);
+}
+
+/*!
+ * \brief Return type of RRSet covered by given RRSIG.
+ *
+ * \param rrset RRSIG.
+ * \return uint16_t Type covered.
+ */
+uint16_t rrsig_type_covered(knot_rrset_t *rrset)
+{
+ assert(rrset->rdata->items[0].raw_data[0] == sizeof(uint16_t));
+
+ return ntohs(*(uint16_t *) rdata_atom_data(rrset->rdata->items[0]));
+}
+
+/*!
+ * \brief Checks if item contains domain.
+ *
+ * \param type Type of RRSet.
+ * \param index Index to check.
+ *
+ * \return > 1 if item is domain, 0 otherwise.
+ */
+static inline int rdata_atom_is_domain(uint16_t type, size_t index)
+{
+ const knot_rrtype_descriptor_t *descriptor
+ = knot_rrtype_descriptor_by_type(type);
+ return (index < descriptor->length
+ && (descriptor->wireformat[index] ==
+ KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ descriptor->wireformat[index] ==
+ KNOT_RDATA_WF_UNCOMPRESSED_DNAME));
+}
+
+/*!
+ * \brief Returns which wireformat type is on given index.
+ *
+ * \param type Type of RRSet.
+ * \param index Index.
+ *
+ * \return uint8_t Wireformat type.
+ */
+static inline uint8_t rdata_atom_wireformat_type(uint16_t type, size_t index)
+{
+ const knot_rrtype_descriptor_t *descriptor =
+ knot_rrtype_descriptor_by_type(type);
+ assert(index < descriptor->length);
+ return descriptor->wireformat[index];
+}
+
+/*!
+ * \brief Converts rdata wireformat to rdata items.
+ *
+ * \param wireformat Wireformat/.
+ * \param rrtype RR type.
+ * \param data_size Size of wireformat.
+ * \param items created rdata items.
+ *
+ * \return Number of items converted.
+ */
+static ssize_t rdata_wireformat_to_rdata_atoms(const uint16_t *wireformat,
+ uint16_t rrtype,
+ const uint16_t data_size,
+ knot_rdata_item_t **items)
+{
+ dbg_rdata("read length: %d\n", data_size);
+ uint16_t const *end = (uint16_t *)((uint8_t *)wireformat + (data_size));
+ dbg_rdata("set end pointer: %p which means length: %d\n", end,
+ (uint8_t *)end - (uint8_t *)wireformat);
+ size_t i;
+ knot_rdata_item_t *temp_rdatas =
+ malloc(sizeof(*temp_rdatas) * MAXRDATALEN);
+ if (temp_rdatas == NULL) {
+ ERR_ALLOC_FAILED;
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+ memset(temp_rdatas, 0, sizeof(*temp_rdatas) * MAXRDATALEN);
+
+ knot_rrtype_descriptor_t *descriptor =
+ knot_rrtype_descriptor_by_type(rrtype);
+
+ assert(descriptor->length <= MAXRDATALEN);
+
+ dbg_rdata("will be parsing %d items, total size: %d\n",
+ descriptor->length, data_size);
+
+ for (i = 0; i < descriptor->length; ++i) {
+ int is_domain = 0;
+ int is_wirestore = 0;
+ size_t length = 0;
+ length = 0;
+ int required = descriptor->length;
+
+ switch (rdata_atom_wireformat_type(rrtype, i)) {
+ case KNOT_RDATA_WF_COMPRESSED_DNAME:
+ case KNOT_RDATA_WF_UNCOMPRESSED_DNAME:
+ is_domain = 1;
+ break;
+ case KNOT_RDATA_WF_LITERAL_DNAME:
+ is_domain = 1;
+ is_wirestore = 1;
+ break;
+ case KNOT_RDATA_WF_BYTE:
+ length = sizeof(uint8_t);
+ break;
+ case KNOT_RDATA_WF_SHORT:
+ length = sizeof(uint16_t);
+ break;
+ case KNOT_RDATA_WF_LONG:
+ length = sizeof(uint32_t);
+ break;
+ case KNOT_RDATA_WF_TEXT:
+ case KNOT_RDATA_WF_BINARYWITHLENGTH:
+ /* Length is stored in the first byte. */
+ length = 1;
+ if ((uint8_t *)wireformat + length <= (uint8_t *)end) {
+ // length += wireformat[length - 1];
+ length += *((uint8_t *)wireformat);
+ dbg_rdata("%d: set new length: %d\n", i,
+ length);
+ }
+ /*if (buffer_position(packet) + length <= end) {
+ length += buffer_current(packet)[length - 1];
+ }*/
+ break;
+ case KNOT_RDATA_WF_A:
+ length = sizeof(in_addr_t);
+ break;
+ case KNOT_RDATA_WF_AAAA:
+ length = IP6ADDRLEN;
+ break;
+ case KNOT_RDATA_WF_BINARY:
+ /* Remaining RDATA is binary. */
+ dbg_rdata("%d: guessing length from pointers: %p %p\n",
+ i,
+ wireformat, end);
+ length = (uint8_t *)end - (uint8_t *)wireformat;
+// length = end - buffer_position(packet);
+ break;
+ case KNOT_RDATA_WF_APL:
+ length = (sizeof(uint16_t) /* address family */
+ + sizeof(uint8_t) /* prefix */
+ + sizeof(uint8_t)); /* length */
+ if ((uint8_t *)wireformat + length <= (uint8_t *)end) {
+ /* Mask out negation bit. */
+ length += (wireformat[length - 1]
+ & APL_LENGTH_MASK);
+ }
+ break;
+ case KNOT_RDATA_WF_IPSECGATEWAY:
+ switch (rdata_atom_data(temp_rdatas[1])[0]) {
+ /* gateway type */
+ default:
+ case IPSECKEY_NOGATEWAY:
+ length = 0;
+ break;
+ case IPSECKEY_IP4:
+ length = 4;
+ break;
+ case IPSECKEY_IP6:
+ length = IP6ADDRLEN;
+ break;
+ case IPSECKEY_DNAME:
+ is_domain = 1;
+ is_wirestore = 1;
+ break;
+ }
+ break;
+ }
+
+ if (is_domain) {
+ knot_dname_t *dname;
+
+ if (!required && (wireformat == end)) {
+ break;
+ }
+
+ dname = knot_dname_new_from_str((char *)wireformat,
+ length,
+ NULL);
+
+ if (dname == NULL) {
+ dbg_rdata("malformed dname!\n");
+ /*! \todo rdata purge */
+ free(temp_rdatas);
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+ dbg_rdata("%d: created dname: %s\n", i,
+ knot_dname_to_str(dname));
+
+ if (is_wirestore) {
+ /*temp_rdatas[i].raw_data =
+ (uint16_t *) region_alloc(
+ region, sizeof(uint16_t) + dname->name_size);
+ temp_rdatas[i].data[0] = dname->name_size;
+ memcpy(temp_rdatas[i].data+1, dname_name(dname),
+ dname->name_size); */
+ temp_rdatas[i].raw_data =
+ malloc(sizeof(uint16_t) +
+ sizeof(uint8_t) * dname->size);
+ if (temp_rdatas[i].raw_data == NULL) {
+ ERR_ALLOC_FAILED;
+ /*! \todo rdata purge */
+ free(temp_rdatas);
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ temp_rdatas[i].raw_data[0] = dname->size;
+ memcpy(temp_rdatas[i].raw_data + 1,
+ dname->name, dname->size);
+
+ knot_dname_release(dname);
+ } else {
+ temp_rdatas[i].dname = dname;
+ }
+
+ } else {
+ dbg_rdata("%d :length: %d %d %p %p\n", i, length,
+ end - wireformat,
+ wireformat, end);
+ if ((uint8_t *)wireformat + length > (uint8_t *)end) {
+ if (required) {
+ /* Truncated RDATA. */
+ /*! \todo rdata purge */
+ free(temp_rdatas);
+ dbg_rdata("truncated rdata\n");
+ return KNOTDZCOMPILE_EBRDATA;
+ } else {
+ break;
+ }
+ }
+
+ assert(wireformat <= end); /*!< \todo remove! */
+ dbg_rdata("calling init with: %p and length : %d\n",
+ wireformat, length);
+ temp_rdatas[i].raw_data = alloc_rdata_init(wireformat,
+ length);
+ if (temp_rdatas[i].raw_data == NULL) {
+ ERR_ALLOC_FAILED;
+ /*! \todo rdata purge */
+ free(temp_rdatas);
+ return -1;
+ }
+
+// temp_rdatas[i].raw_data[0] = length;
+// memcpy(temp_rdatas[i].raw_data + 1, wireformat, length);
+
+/* temp_rdatas[i].data = (uint16_t *) region_alloc(
+ region, sizeof(uint16_t) + length);
+ temp_rdatas[i].data[0] = length;
+ buffer_read(packet,
+ temp_rdatas[i].data + 1, length); */
+ }
+ dbg_rdata("%d: adding length: %d (remaining: %d)\n", i, length,
+ (uint8_t *)end - ((uint8_t *)wireformat + length));
+// hex_print(temp_rdatas[i].raw_data + 1, length);
+ wireformat = (uint16_t *)((uint8_t *)wireformat + length);
+// wireformat = wireformat + length;
+ dbg_rdata("wire: %p\n", wireformat);
+ dbg_rdata("remaining now: %d\n",
+ end - wireformat);
+
+ }
+
+ dbg_rdata("%p %p\n", wireformat, (uint8_t *)wireformat);
+
+ if (wireformat < end) {
+ /* Trailing garbage. */
+ dbg_rdata("w: %p e: %p %d\n", wireformat, end, end - wireformat);
+// region_destroy(temp_region);
+ free(temp_rdatas);
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+
+ *items = temp_rdatas;
+ /* *rdatas = (rdata_atom_type *) region_alloc_init(
+ region, temp_rdatas, i * sizeof(rdata_atom_type)); */
+ return (ssize_t)i;
+}
+
+/* Taken from RFC 2535, section 7. */
+knot_lookup_table_t dns_algorithms[] = {
+ { 1, "RSAMD5" }, /* RFC 2537 */
+ { 2, "DH" }, /* RFC 2539 */
+ { 3, "DSA" }, /* RFC 2536 */
+ { 4, "ECC" },
+ { 5, "RSASHA1" }, /* RFC 3110 */
+ { 252, "INDIRECT" },
+ { 253, "PRIVATEDNS" },
+ { 254, "PRIVATEOID" },
+ { 0, NULL }
+};
+
+/* Taken from RFC 4398, section 2.1. */
+knot_lookup_table_t dns_certificate_types[] = {
+ /* 0 Reserved */
+ { 1, "PKIX" }, /* X.509 as per PKIX */
+ { 2, "SPKI" }, /* SPKI cert */
+ { 3, "PGP" }, /* OpenPGP packet */
+ { 4, "IPKIX" }, /* The URL of an X.509 data object */
+ { 5, "ISPKI" }, /* The URL of an SPKI certificate */
+ { 6, "IPGP" }, /* The fingerprint and URL of an OpenPGP packet */
+ { 7, "ACPKIX" }, /* Attribute Certificate */
+ { 8, "IACPKIX" }, /* The URL of an Attribute Certificate */
+ { 253, "URI" }, /* URI private */
+ { 254, "OID" }, /* OID private */
+ /* 255 Reserved */
+ /* 256-65279 Available for IANA assignment */
+ /* 65280-65534 Experimental */
+ /* 65535 Reserved */
+ { 0, NULL }
+};
+
+/* Imported from lexer. */
+extern int hexdigit_to_int(char ch);
+
+extern uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE];
+extern uint16_t nsec_highest_rcode;
+
+/*!
+ * \brief Allocate SIZE+sizeof(uint16_t) bytes and store SIZE in the first
+ * element. Return a pointer to the allocation.
+ *
+ * \param size How many bytes to allocate.
+ */
+static uint16_t * alloc_rdata(size_t size)
+{
+ uint16_t *result = malloc(sizeof(uint16_t) + size);
+ *result = size;
+ return result;
+}
+
+uint16_t *alloc_rdata_init(const void *data, size_t size)
+{
+ uint16_t *result = malloc(sizeof(uint16_t) + size);
+ if (result == NULL) {
+ return NULL;
+ }
+ *result = size;
+ memcpy(result + 1, data, size);
+ return result;
+}
+
+/*
+ * These are parser function for generic zone file stuff.
+ */
+uint16_t * zparser_conv_hex(const char *hex, size_t len)
+{
+ /* convert a hex value to wireformat */
+ uint16_t *r = NULL;
+ uint8_t *t;
+ int i;
+
+ if (len % 2 != 0) {
+ zc_error_prev_line("number of hex digits "
+ "must be a multiple of 2");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else if (len > MAX_RDLENGTH * 2) {
+ zc_error_prev_line("hex data exceeds maximum rdata length (%d)",
+ MAX_RDLENGTH);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ /* the length part */
+
+ r = alloc_rdata(len / 2);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ t = (uint8_t *)(r + 1);
+
+ /* Now process octet by octet... */
+ while (*hex) {
+ *t = 0;
+ for (i = 16; i >= 1; i -= 15) {
+ if (isxdigit((int)*hex)) {
+ *t += hexdigit_to_int(*hex) * i;
+ } else {
+ zc_error_prev_line(
+ "illegal hex character '%c'",
+ (int) *hex);
+ parser->error_occurred =
+ KNOTDZCOMPILE_EBRDATA;
+ free(r);
+ return NULL;
+ }
+ ++hex;
+ }
+ ++t;
+ }
+ }
+
+ return r;
+}
+
+/* convert hex, precede by a 1-byte length */
+uint16_t * zparser_conv_hex_length(const char *hex, size_t len)
+{
+ uint16_t *r = NULL;
+ uint8_t *t;
+ int i;
+ if (len % 2 != 0) {
+ zc_error_prev_line("number of hex digits must be a "
+ "multiple of 2");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else if (len > 255 * 2) {
+ zc_error_prev_line("hex data exceeds 255 bytes");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ uint8_t *l;
+
+ /* the length part */
+ r = alloc_rdata(len / 2 + 1);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+
+ t = (uint8_t *)(r + 1);
+
+ l = t++;
+ *l = '\0';
+
+ /* Now process octet by octet... */
+ while (*hex) {
+ *t = 0;
+ for (i = 16; i >= 1; i -= 15) {
+ if (isxdigit((int)*hex)) {
+ *t += hexdigit_to_int(*hex) * i;
+ } else {
+ zc_error_prev_line(
+ "illegal hex character '%c'",
+ (int) *hex);
+ parser->error_occurred =
+ KNOTDZCOMPILE_EBRDATA;
+ free(r);
+ return NULL;
+ }
+ ++hex;
+ }
+ ++t;
+ ++*l;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_time(const char *time)
+{
+ /* convert a time YYHM to wireformat */
+ uint16_t *r = NULL;
+ struct tm tm;
+
+ /* Try to scan the time... */
+ if (!strptime(time, "%Y%m%d%H%M%S", &tm)) {
+ zc_error_prev_line("date and time is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ uint32_t l = htonl(mktime_from_utc(&tm));
+ r = alloc_rdata_init(&l, sizeof(l));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_services(const char *protostr, char *servicestr)
+{
+ /*
+ * Convert a protocol and a list of service port numbers
+ * (separated by spaces) in the rdata to wireformat
+ */
+ uint16_t *r = NULL;
+ uint8_t *p;
+ uint8_t bitmap[65536/8];
+ char sep[] = " ";
+ char *word;
+ int max_port = -8;
+ /* convert a protocol in the rdata to wireformat */
+ struct protoent *proto;
+
+ memset(bitmap, 0, sizeof(bitmap));
+
+ proto = getprotobyname(protostr);
+ if (!proto) {
+ proto = getprotobynumber(atoi(protostr));
+ }
+ if (!proto) {
+ zc_error_prev_line("unknown protocol '%s'", protostr);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ return NULL;
+ }
+
+ char *sp = 0;
+ while ((word = strtok_r(servicestr, sep, &sp))) {
+ struct servent *service;
+ int port;
+
+ service = getservbyname(word, proto->p_name);
+ if (service) {
+ /* Note: ntohs not ntohl! Strange but true. */
+ port = ntohs((uint16_t) service->s_port);
+ } else {
+ char *end;
+ port = strtol(word, &end, 10);
+ if (*end != '\0') {
+ zc_error_prev_line(
+ "unknown service '%s' for"
+ " protocol '%s'",
+ word, protostr);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ continue;
+ }
+ }
+
+ if (port < 0 || port > 65535) {
+ zc_error_prev_line("bad port number %d", port);
+ } else {
+ set_bit(bitmap, port);
+ if (port > max_port) {
+ max_port = port;
+ }
+ }
+ }
+
+ r = alloc_rdata(sizeof(uint8_t) + max_port / 8 + 1);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+
+ p = (uint8_t *)(r + 1);
+ *p = proto->p_proto;
+ memcpy(p + 1, bitmap, *r);
+
+ return r;
+}
+
+uint16_t * zparser_conv_serial(const char *serialstr)
+{
+ uint16_t *r = NULL;
+ uint32_t serial;
+ const char *t;
+
+ serial = strtoserial(serialstr, &t);
+ if (*t != '\0') {
+ zc_error_prev_line("serial is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ serial = htonl(serial);
+ r = alloc_rdata_init(&serial, sizeof(serial));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_period(const char *periodstr)
+{
+ /* convert a time period (think TTL's) to wireformat) */
+ uint16_t *r = NULL;
+ uint32_t period;
+ const char *end;
+
+ /* Allocate required space... */
+ period = strtottl(periodstr, &end);
+ if (*end != '\0') {
+ zc_error_prev_line("time period is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ period = htonl(period);
+ r = alloc_rdata_init(&period, sizeof(period));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_short(const char *text)
+{
+ uint16_t *r = NULL;
+ uint16_t value;
+ char *end;
+
+ value = htons((uint16_t) strtol(text, &end, 10));
+ if (*end != '\0') {
+ zc_error_prev_line("integer value is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ r = alloc_rdata_init(&value, sizeof(value));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_byte(const char *text)
+{
+ uint16_t *r = NULL;
+ uint8_t value;
+ char *end;
+
+ value = (uint8_t) strtol(text, &end, 10);
+ if (*end != '\0') {
+ zc_error_prev_line("integer value is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ r = alloc_rdata_init(&value, sizeof(value));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_algorithm(const char *text)
+{
+ const knot_lookup_table_t *alg;
+ uint8_t id;
+
+ alg = knot_lookup_by_name(dns_algorithms, text);
+ if (alg) {
+ id = (uint8_t) alg->id;
+ } else {
+ char *end;
+ id = (uint8_t) strtol(text, &end, 10);
+ if (*end != '\0') {
+ zc_error_prev_line("algorithm is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ return NULL;
+ }
+ }
+
+ uint16_t *r = alloc_rdata_init(&id, sizeof(id));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+
+ return r;
+}
+
+uint16_t * zparser_conv_certificate_type(const char *text)
+{
+ /* convert a algoritm string to integer */
+ const knot_lookup_table_t *type;
+ uint16_t id;
+
+ type = knot_lookup_by_name(dns_certificate_types, text);
+ if (type) {
+ id = htons((uint16_t) type->id);
+ } else {
+ char *end;
+ id = htons((uint16_t) strtol(text, &end, 10));
+ if (*end != '\0') {
+ zc_error_prev_line("certificate type is expected");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ return NULL;
+ }
+ }
+
+ uint16_t *r = alloc_rdata_init(&id, sizeof(id));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+
+ return r;
+}
+
+uint16_t * zparser_conv_a(const char *text)
+{
+ in_addr_t address;
+ uint16_t *r = NULL;
+
+ if (inet_pton(AF_INET, text, &address) != 1) {
+ zc_error_prev_line("invalid IPv4 address '%s'", text);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ r = alloc_rdata_init(&address, sizeof(address));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+
+ return r;
+}
+
+uint16_t * zparser_conv_aaaa(const char *text)
+{
+ uint8_t address[IP6ADDRLEN];
+ uint16_t *r = NULL;
+
+ if (inet_pton(AF_INET6, text, address) != 1) {
+ zc_error_prev_line("invalid IPv6 address '%s'", text);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ r = alloc_rdata_init(address, sizeof(address));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_text(const char *text, size_t len)
+{
+ uint16_t *r = NULL;
+
+ dbg_zp("Converting text: %s\n", text);
+
+ if (len > 255) {
+ zc_error_prev_line("text string is longer than 255 characters,"
+ " try splitting it into multiple parts");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ uint8_t *p;
+ r = alloc_rdata(len + 1);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ p = (uint8_t *)(r + 1);
+ *p = len;
+ memcpy(p + 1, text, len);
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_dns_name(const uint8_t *name, size_t len)
+{
+ uint16_t *r = NULL;
+ uint8_t *p = NULL;
+ r = alloc_rdata(len);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ p = (uint8_t *)(r + 1);
+ memcpy(p, name, len);
+
+ return r;
+}
+
+uint16_t * zparser_conv_b32(const char *b32)
+{
+ uint8_t buffer[B64BUFSIZE];
+ uint16_t *r = NULL;
+ size_t i = B64BUFSIZE - 1;
+
+ if (strcmp(b32, "-") == 0) {
+ r = alloc_rdata_init("", 1);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ return r;
+ }
+
+ /*!< \todo BLEEDING EYES! */
+
+ char b32_copy[strlen(b32) + 1];
+
+ for (int i = 0; i < strlen(b32); i++) {
+ b32_copy[i] = toupper(b32[i]);
+ }
+
+ /*!< \todo BLEEDING EYES! */
+ b32_copy[strlen(b32)] = '\0';
+
+ if (!base32hex_decode(b32_copy,
+ strlen(b32_copy), (char *)buffer + 1, &i)) {
+ zc_error_prev_line("invalid base32 data");
+ parser->error_occurred = 1;
+ } else {
+ buffer[0] = i; /* store length byte */
+ r = alloc_rdata_init(buffer, i + 1);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_b64(const char *b64)
+{
+ uint8_t buffer[B64BUFSIZE];
+ uint16_t *r = NULL;
+ int i;
+
+ i = b64_pton(b64, buffer, B64BUFSIZE);
+ if (i == -1) {
+ zc_error_prev_line("invalid base64 data\n");
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ r = alloc_rdata_init(buffer, i);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_rrtype(const char *text)
+{
+ uint16_t *r = NULL;
+ uint16_t type = knot_rrtype_from_string(text);
+
+ if (type == 0) {
+ zc_error_prev_line("unrecognized RR type '%s'", text);
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ } else {
+ type = htons(type);
+ r = alloc_rdata_init(&type, sizeof(type));
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+ }
+ return r;
+}
+
+uint16_t * zparser_conv_nxt(uint8_t nxtbits[])
+{
+ /* nxtbits[] consists of 16 bytes with some zero's in it
+ * copy every byte with zero to r and write the length in
+ * the first byte
+ */
+ uint16_t i;
+ uint16_t last = 0;
+
+ for (i = 0; i < 16; i++) {
+ if (nxtbits[i] != 0) {
+ last = i + 1;
+ }
+ }
+
+ uint16_t *r = alloc_rdata_init(nxtbits, last);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ return NULL;
+ }
+
+ return r;
+}
+
+
+/* we potentially have 256 windows, each one is numbered. empty ones
+ * should be discarded
+ */
+uint16_t * zparser_conv_nsec(uint8_t nsecbits[NSEC_WINDOW_COUNT]
+ [NSEC_WINDOW_BITS_SIZE])
+{
+ /* nsecbits contains up to 64K of bits which represent the
+ * types available for a name. Walk the bits according to
+ * nsec++ draft from jakob
+ */
+ uint16_t *r;
+ uint8_t *ptr;
+ size_t i, j;
+ uint16_t window_count = 0;
+ uint16_t total_size = 0;
+ uint16_t window_max = 0;
+
+ /* The used windows. */
+ int used[NSEC_WINDOW_COUNT];
+ /* The last byte used in each the window. */
+ int size[NSEC_WINDOW_COUNT];
+
+ window_max = 1 + (nsec_highest_rcode / 256);
+
+ /* used[i] is the i-th window included in the nsec
+ * size[used[0]] is the size of window 0
+ */
+
+ /* walk through the 256 windows */
+ for (i = 0; i < window_max; ++i) {
+ int empty_window = 1;
+ /* check each of the 32 bytes */
+ for (j = 0; j < NSEC_WINDOW_BITS_SIZE; ++j) {
+ if (nsecbits[i][j] != 0) {
+ size[i] = j + 1;
+ empty_window = 0;
+ }
+ }
+ if (!empty_window) {
+ used[window_count] = i;
+ window_count++;
+ }
+ }
+
+ for (i = 0; i < window_count; ++i) {
+ total_size += sizeof(uint16_t) + size[used[i]];
+ }
+
+ r = alloc_rdata(total_size);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ parser->error_occurred = KNOTDZCOMPILE_EBRDATA;
+ return NULL;
+ }
+ ptr = (uint8_t *)(r + 1);
+
+ /* now walk used and copy it */
+ for (i = 0; i < window_count; ++i) {
+ ptr[0] = used[i];
+ ptr[1] = size[used[i]];
+ memcpy(ptr + 2, &nsecbits[used[i]], size[used[i]]);
+ ptr += size[used[i]] + 2;
+ }
+
+ return r;
+}
+
+/* Parse an int terminated in the specified range. */
+static int parse_int(const char *str,
+ char **end,
+ int *result,
+ const char *name,
+ int min,
+ int max)
+{
+ long value;
+ value = strtol(str, end, 10);
+ if (value < min || value > max) {
+ zc_error_prev_line("%s must be within the range [%d .. %d]",
+ name,
+ min,
+ max);
+ return 0;
+ } else {
+ *result = (int) value;
+ return 1;
+ }
+}
+
+/* RFC1876 conversion routines */
+static uint32_t poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
+ 1000000, 10000000, 100000000, 1000000000
+ };
+
+/*
+ * Converts ascii size/precision X * 10**Y(cm) to 0xXY.
+ * Sets the given pointer to the last used character.
+ *
+ */
+static uint8_t precsize_aton(char *cp, char **endptr)
+{
+ unsigned int mval = 0, cmval = 0;
+ uint8_t retval = 0;
+ int exponent;
+ int mantissa;
+
+ while (isdigit((int)*cp)) {
+ mval = mval * 10 + hexdigit_to_int(*cp++);
+ }
+
+ if (*cp == '.') { /* centimeters */
+ cp++;
+ if (isdigit((int)*cp)) {
+ cmval = hexdigit_to_int(*cp++) * 10;
+ if (isdigit((int)*cp)) {
+ cmval += hexdigit_to_int(*cp++);
+ }
+ }
+ }
+
+ if (mval >= poweroften[7]) {
+ /* integer overflow possible for *100 */
+ mantissa = mval / poweroften[7];
+ exponent = 9; /* max */
+ } else {
+ cmval = (mval * 100) + cmval;
+
+ for (exponent = 0; exponent < 9; exponent++)
+ if (cmval < poweroften[exponent+1]) {
+ break;
+ }
+
+ mantissa = cmval / poweroften[exponent];
+ }
+ if (mantissa > 9) {
+ mantissa = 9;
+ }
+
+ retval = (mantissa << 4) | exponent;
+
+ if (*cp == 'm') {
+ cp++;
+ }
+
+ *endptr = cp;
+
+ return (retval);
+}
+
+/*
+ * Parses a specific part of rdata.
+ *
+ * Returns:
+ *
+ * number of elements parsed
+ * zero on error
+ *
+ */
+uint16_t * zparser_conv_loc(char *str)
+{
+ uint16_t *r;
+ uint32_t *p;
+ int i;
+ int deg, min, secs; /* Secs is stored times 1000. */
+ uint32_t lat = 0, lon = 0, alt = 0;
+ /* encoded defaults: version=0 sz=1m hp=10000m vp=10m */
+ uint8_t vszhpvp[4] = {0, 0x12, 0x16, 0x13};
+ char *start;
+ double d;
+
+ for (;;) {
+ deg = min = secs = 0;
+
+ /* Degrees */
+ if (*str == '\0') {
+ zc_error_prev_line("unexpected end of LOC data");
+ return NULL;
+ }
+
+ if (!parse_int(str, &str, &deg, "degrees", 0, 180)) {
+ return NULL;
+ }
+ if (!isspace((int)*str)) {
+ zc_error_prev_line("space expected after degrees");
+ return NULL;
+ }
+ ++str;
+
+ /* Minutes? */
+ if (isdigit((int)*str)) {
+ if (!parse_int(str, &str, &min, "minutes", 0, 60)) {
+ return NULL;
+ }
+ if (!isspace((int)*str)) {
+ zc_error_prev_line("space expected after minutes");
+ return NULL;
+ }
+ ++str;
+ }
+
+ /* Seconds? */
+ if (isdigit((int)*str)) {
+ start = str;
+ if (!parse_int(str, &str, &i, "seconds", 0, 60)) {
+ return NULL;
+ }
+
+ if (*str == '.' && !parse_int(str + 1, &str, &i,
+ "seconds fraction",
+ 0, 999)) {
+ return NULL;
+ }
+
+ if (!isspace((int)*str)) {
+ zc_error_prev_line("space expected after seconds");
+ return NULL;
+ }
+
+ if (sscanf(start, "%lf", &d) != 1) {
+ zc_error_prev_line("error parsing seconds");
+ }
+
+ if (d < 0.0 || d > 60.0) {
+ zc_error_prev_line(
+ "seconds not in range 0.0 .. 60.0");
+ }
+
+ secs = (int)(d * 1000.0 + 0.5);
+ ++str;
+ }
+
+ switch (*str) {
+ case 'N':
+ case 'n':
+ lat = ((uint32_t)1 << 31) +
+ (deg * 3600000 + min * 60000 + secs);
+ break;
+ case 'E':
+ case 'e':
+ lon = ((uint32_t)1 << 31) +
+ (deg * 3600000 + min * 60000 + secs);
+ break;
+ case 'S':
+ case 's':
+ lat = ((uint32_t)1 << 31) -
+ (deg * 3600000 + min * 60000 + secs);
+ break;
+ case 'W':
+ case 'w':
+ lon = ((uint32_t)1 << 31) -
+ (deg * 3600000 + min * 60000 + secs);
+ break;
+ default:
+ zc_error_prev_line(
+ "invalid latitude/longtitude: '%c'", *str);
+ return NULL;
+ }
+ ++str;
+
+ if (lat != 0 && lon != 0) {
+ break;
+ }
+
+ if (!isspace((int)*str)) {
+ zc_error_prev_line("space expected after"
+ " latitude/longitude");
+ return NULL;
+ }
+ ++str;
+ }
+
+ /* Altitude */
+ if (*str == '\0') {
+ zc_error_prev_line("unexpected end of LOC data");
+ return NULL;
+ }
+
+ if (!isspace((int)*str)) {
+ zc_error_prev_line("space expected before altitude");
+ return NULL;
+ }
+ ++str;
+
+ start = str;
+
+ /* Sign */
+ if (*str == '+' || *str == '-') {
+ ++str;
+ }
+
+ /* Meters of altitude... */
+ int ret = strtol(str, &str, 10);
+ UNUSED(ret); // Result checked in following switch
+
+ switch (*str) {
+ case ' ':
+ case '\0':
+ case 'm':
+ break;
+ case '.':
+ if (!parse_int(str + 1, &str, &i, "altitude fraction", 0, 99)) {
+ return NULL;
+ }
+ if (!isspace((int)*str) && *str != '\0' && *str != 'm') {
+ zc_error_prev_line("altitude fraction must be a number");
+ return NULL;
+ }
+ break;
+ default:
+ zc_error_prev_line("altitude must be expressed in meters");
+ return NULL;
+ }
+ if (!isspace((int)*str) && *str != '\0') {
+ ++str;
+ }
+
+ if (sscanf(start, "%lf", &d) != 1) {
+ zc_error_prev_line("error parsing altitude");
+ }
+
+ alt = (uint32_t)(10000000.0 + d * 100 + 0.5);
+
+ if (!isspace((int)*str) && *str != '\0') {
+ zc_error_prev_line("unexpected character after altitude");
+ return NULL;
+ }
+
+ /* Now parse size, horizontal precision and vertical precision if any */
+ for (i = 1; isspace((int)*str) && i <= 3; i++) {
+ vszhpvp[i] = precsize_aton(str + 1, &str);
+
+ if (!isspace((int)*str) && *str != '\0') {
+ zc_error_prev_line("invalid size or precision");
+ return NULL;
+ }
+ }
+
+ /* Allocate required space... */
+ r = alloc_rdata(16);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+ p = (uint32_t *)(r + 1);
+
+ memmove(p, vszhpvp, 4);
+ write_uint32(p + 1, lat);
+ write_uint32(p + 2, lon);
+ write_uint32(p + 3, alt);
+
+ return r;
+}
+
+/*
+ * Convert an APL RR RDATA element.
+ */
+uint16_t * zparser_conv_apl_rdata(char *str)
+{
+ int negated = 0;
+ uint16_t address_family;
+ uint8_t prefix;
+ uint8_t maximum_prefix;
+ uint8_t length;
+ uint8_t address[IP6ADDRLEN];
+ char *colon = strchr(str, ':');
+ char *slash = strchr(str, '/');
+ int af;
+ int rc;
+ uint16_t rdlength;
+ uint16_t *r;
+ uint8_t *t;
+ char *end;
+ long p;
+
+ if (!colon) {
+ zc_error_prev_line("address family separator is missing");
+ return NULL;
+ }
+ if (!slash) {
+ zc_error_prev_line("prefix separator is missing");
+ return NULL;
+ }
+
+ *colon = '\0';
+ *slash = '\0';
+
+ if (*str == '!') {
+ negated = 1;
+ ++str;
+ }
+
+ if (strcmp(str, "1") == 0) {
+ address_family = htons(1);
+ af = AF_INET;
+ length = sizeof(in_addr_t);
+ maximum_prefix = length * 8;
+ } else if (strcmp(str, "2") == 0) {
+ address_family = htons(2);
+ af = AF_INET6;
+ length = IP6ADDRLEN;
+ maximum_prefix = length * 8;
+ } else {
+ zc_error_prev_line("invalid address family '%s'", str);
+ return NULL;
+ }
+
+ rc = inet_pton(af, colon + 1, address);
+ if (rc == 0) {
+ zc_error_prev_line("invalid address '%s'", colon + 1);
+ return NULL;
+ } else if (rc == -1) {
+ char ebuf[256];
+ zc_error_prev_line("inet_pton failed: %s",
+ strerror_r(errno, ebuf, sizeof(ebuf)));
+ return NULL;
+ }
+
+ /* Strip trailing zero octets. */
+ while (length > 0 && address[length - 1] == 0) {
+ --length;
+ }
+
+
+ p = strtol(slash + 1, &end, 10);
+ if (p < 0 || p > maximum_prefix) {
+ zc_error_prev_line("prefix not in the range 0 .. %d",
+ maximum_prefix);
+ return NULL;
+ } else if (*end != '\0') {
+ zc_error_prev_line("invalid prefix '%s'", slash + 1);
+ return NULL;
+ }
+ prefix = (uint8_t) p;
+
+ rdlength = (sizeof(address_family) + sizeof(prefix) + sizeof(length)
+ + length);
+ r = alloc_rdata(rdlength);
+ if (r == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+ t = (uint8_t *)(r + 1);
+
+ memcpy(t, &address_family, sizeof(address_family));
+ t += sizeof(address_family);
+ memcpy(t, &prefix, sizeof(prefix));
+ t += sizeof(prefix);
+ memcpy(t, &length, sizeof(length));
+ if (negated) {
+ *t |= APL_NEGATION_MASK;
+ }
+ t += sizeof(length);
+ memcpy(t, address, length);
+
+ return r;
+}
+
+/*
+ * Below some function that also convert but not to wireformat
+ * but to "normal" (int,long,char) types
+ */
+
+uint32_t zparser_ttl2int(const char *ttlstr, int *error)
+{
+ /* convert a ttl value to a integer
+ * return the ttl in a int
+ * -1 on error
+ */
+
+ uint32_t ttl;
+ const char *t;
+
+ ttl = strtottl(ttlstr, &t);
+ if (*t != 0) {
+ zc_error_prev_line("invalid TTL value: %s", ttlstr);
+ *error = 1;
+ }
+
+ return ttl;
+}
+
+void zadd_rdata_wireformat(uint16_t *data)
+{
+ parser->temporary_items[parser->rdata_count].raw_data = data;
+ parser->rdata_count++;
+}
+
+/**
+ * Used for TXT RR's to grow with undefined number of strings.
+ */
+void zadd_rdata_txt_wireformat(uint16_t *data, int first)
+{
+ dbg_zp("Adding text!\n");
+// hex_print(data + 1, data[0]);
+ knot_rdata_item_t *rd;
+
+ /* First STR in str_seq, allocate 65K in first unused rdata
+ * else find last used rdata */
+ if (first) {
+ rd = &parser->temporary_items[parser->rdata_count];
+// if ((rd->data = (uint8_t *) region_alloc(parser->rr_region,
+// sizeof(uint8_t) + 65535 * sizeof(uint8_t))) == NULL) {
+// zc_error_prev_line("Could not allocate memory for TXT RR");
+// return;
+// }
+ rd->raw_data = alloc_rdata(65535 * sizeof(uint8_t));
+ if (rd->raw_data == NULL) {
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ }
+ parser->rdata_count++;
+ rd->raw_data[0] = 0;
+ } else {
+// assert(0);
+ rd = &parser->temporary_items[parser->rdata_count-1];
+ }
+
+ if ((size_t)rd->raw_data[0] + (size_t)data[0] > 65535) {
+ zc_error_prev_line("too large rdata element");
+ return;
+ }
+
+ memcpy((uint8_t *)rd->raw_data + 2 + rd->raw_data[0],
+ data + 1, data[0]);
+ rd->raw_data[0] += data[0];
+ free(data);
+ dbg_zp("Item after add\n");
+// hex_print(rd->raw_data + 1, rd->raw_data[0]);
+}
+
+void zadd_rdata_domain(knot_dname_t *dname)
+{
+ knot_dname_retain(dname);
+// printf("Adding rdata name: %s %p\n", dname->name, dname);
+ parser->temporary_items[parser->rdata_count].dname = dname;
+ parser->rdata_count++;
+}
+
+void parse_unknown_rdata(uint16_t type, uint16_t *wireformat)
+{
+ dbg_rdata("parsing unknown rdata for type: %d\n", type);
+// buffer_type packet;
+ uint16_t size;
+ ssize_t rdata_count;
+ ssize_t i;
+ knot_rdata_item_t *items = NULL;
+
+ if (wireformat) {
+ size = *wireformat;
+ } else {
+ return;
+ }
+
+// buffer_create_from(&packet, wireformat + 1, *wireformat);
+ rdata_count = rdata_wireformat_to_rdata_atoms(wireformat + 1, type,
+ size, &items);
+// dbg_rdata("got %d items\n", rdata_count);
+ dbg_rdata("wf to items returned error: %s (%d)\n",
+ error_to_str(knot_zcompile_error_msgs, rdata_count),
+ rdata_count);
+ if (rdata_count < 0) {
+ zc_error_prev_line("bad unknown RDATA\n");
+ /*!< \todo leaks */
+ return;
+ }
+
+ for (i = 0; i < rdata_count; ++i) {
+ if (rdata_atom_is_domain(type, i)) {
+ zadd_rdata_domain(items[i].dname);
+ } else {
+ //XXX won't this create size two times?
+ zadd_rdata_wireformat((uint16_t *)items[i].raw_data);
+ }
+ }
+ free(items);
+ /* Free wireformat */
+ free(wireformat);
+}
+
+void set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE],
+ uint16_t index)
+{
+ /*
+ * The bits are counted from left to right, so bit #0 is the
+ * left most bit.
+ */
+ uint8_t window = index / 256;
+ uint8_t bit = index % 256;
+
+ bits[window][bit / 8] |= (1 << (7 - bit % 8));
+}
+
diff --git a/src/zcompile/parser-util.h b/src/zcompile/parser-util.h
new file mode 100644
index 0000000..57258dc
--- /dev/null
+++ b/src/zcompile/parser-util.h
@@ -0,0 +1,357 @@
+/*!
+ * \file parser-util.h
+ *
+ * \author NLnet Labs
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ * Minor modifications by CZ.NIC, z.s.p.o.
+ *
+ * \brief Zone compiler utility functions.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KNOTD_PARSER_UTIL_H_
+#define _KNOTD_PARSER_UTIL_H_
+
+#include <assert.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "zcompile/zcompile.h"
+#include "libknot/util/descriptor.h"
+
+int inet_pton4(const char *src, uint8_t *dst);
+int inet_pton6(const char *src, uint8_t *dst);
+//int my_b32_pton(const char *src, uint8_t *target, size_t tsize);
+const char *inet_ntop4(const u_char *src, char *dst, size_t size);
+const char *inet_ntop6(const u_char *src, char *dst, size_t size);
+int inet_pton(int af, const char *src, void *dst);
+void b64_initialize_rmap();
+int b64_pton_do(char const *src, uint8_t *target, size_t targsize);
+int b64_pton_len(char const *src);
+int b64_pton(char const *src, uint8_t *target, size_t targsize);
+void set_bit(uint8_t bits[], size_t index);
+uint32_t strtoserial(const char *nptr, const char **endptr);
+void write_uint32(void *dst, uint32_t data);
+uint32_t strtottl(const char *nptr, const char **endptr);
+time_t mktime_from_utc(const struct tm *tm);
+
+/*!< Conversions from text to wire. */
+/*!
+ * \brief Converts hex text format to wireformat.
+ *
+ * \param hex String to be converted.
+ * \param len Length of string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_hex(const char *hex, size_t len);
+
+/*!
+ * \brief Converts hex text format with length to wireformat.
+ *
+ * \param hex String to be converted/.
+ * \param len Length of string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_hex_length(const char *hex, size_t len);
+
+/*!
+ * \brief Converts time string to wireformat.
+ *
+ * \param time Time string to be converted.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_time(const char *time);
+/*!
+ * \brief Converts a protocol and a list of service port numbers
+ * (separated by spaces) in the rdata to wireformat
+ *
+ * \param protostr Protocol string.
+ * \param servicestr Service string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_services(const char *protostr, char *servicestr);
+
+/*!
+ * \brief Converts serial to wireformat.
+ *
+ * \param serialstr Serial string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_serial(const char *serialstr);
+/*!
+ * \brief Converts period to wireformat.
+ *
+ * \param periodstr Period string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_period(const char *periodstr);
+
+/*!
+ * \brief Converts short int to wireformat.
+ *
+ * \param text String containing short int.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_short(const char *text);
+
+/*!
+ * \brief Converts long int to wireformat.
+ *
+ * \param text String containing long int.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_long(const char *text);
+
+/*!
+ * \brief Converts byte to wireformat.
+ *
+ * \param text String containing byte.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_byte(const char *text);
+
+/*!
+ * \brief Converts A rdata string to wireformat.
+ *
+ * \param text String containing A rdata.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_a(const char *text);
+
+/*!
+ * \brief Converts AAAA rdata string to wireformat.
+ *
+ * \param text String containing AAAA rdata.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_aaaa(const char *text);
+
+/*!
+ * \brief Converts text string to wireformat.
+ *
+ * \param text Text string.
+ * \param len Length of string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_text(const char *text, size_t len);
+
+/*!
+ * \brief Converts domain name string to wireformat.
+ *
+ * \param name Domain name string.
+ * \param len Length of string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_dns_name(const uint8_t* name, size_t len);
+
+/*!
+ * \brief Converts base32 encoded string to wireformat.
+ * TODO consider replacing with our implementation.
+ *
+ * \param b32 Base32 encoded string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_b32(const char *b32);
+
+/*!
+ * \brief Converts base64 encoded string to wireformat.
+ * TODO consider replacing with our implementation.
+ *
+ * \param b64 Base64 encoded string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_b64(const char *b64);
+
+/*!
+ * \brief Converts RR type string to wireformat.
+ *
+ * \param rr RR type string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_rrtype(const char *rr);
+
+/*!
+ * \brief Converts NXT string to wireformat.
+ *
+ * \param nxtbits NXT string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_nxt(uint8_t *nxtbits);
+
+/*!
+ * \brief Converts NSEC bitmap to wireformat.
+ *
+ * \param nsecbits[][] NSEC bits.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_nsec(uint8_t nsecbits[NSEC_WINDOW_COUNT]
+ [NSEC_WINDOW_BITS_SIZE]);
+/*!
+ * \brief Converts LOC string to wireformat.
+ *
+ * \param str LOC string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_loc(char *str);
+
+/*!
+ * \brief Converts algorithm string to wireformat.
+ *
+ * \param algstr Algorithm string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_algorithm(const char *algstr);
+
+/*!
+ * \brief Converts certificate type string to wireformat.
+ *
+ * \param typestr Certificate type mnemonic string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_certificate_type(const char *typestr);
+
+/*!
+ * \brief Converts APL data to wireformat.
+ *
+ * \param str APL data string.
+ *
+ * \return Converted wireformat.
+ */
+uint16_t *zparser_conv_apl_rdata(char *str);
+
+/*!
+ * \brief Parses unknown rdata.
+ *
+ * \param type Type of data.
+ * \param wireformat Wireformat of data.
+ *
+ * \return Converted wireformat.
+ */
+void parse_unknown_rdata(uint16_t type, uint16_t *wireformat);
+
+/*!
+ * \brief Converts TTL string to int.
+ *
+ * \param ttlstr String
+ * \param error Error code.
+ *
+ * \return Converted wireformat.
+ */
+uint32_t zparser_ttl2int(const char *ttlstr, int* error);
+
+/*!
+ * \brief Adds wireformat to temporary list of rdata items.
+ *
+ * \param data Wireformat to be added.
+ */
+void zadd_rdata_wireformat(uint16_t *data);
+
+/*!
+ * \brief Adds TXT wireformat to temporary list of rdata items.
+ *
+ * \param data Wireformat to be added.
+ * \param first This is first text to be added.
+ */
+void zadd_rdata_txt_wireformat(uint16_t *data, int first);
+
+/*!
+ * \brief Cleans after using zadd_rdata_txt_wireformat().
+ */
+void zadd_rdata_txt_clean_wireformat();
+
+/*!
+ * \brief Adds domain name to temporary list of rdata items.
+ *
+ * \param domain Domain name to be added.
+ */
+void zadd_rdata_domain(knot_dname_t *domain);
+
+/*!
+ * \brief Sets bit in NSEC bitmap.
+ *
+ * \param bits[][] NSEC bitmaps.
+ * \param index Index on which bit is to be set.
+ */
+void set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE],
+ uint16_t index);
+
+/*!
+ * \brief Allocate and init wireformat.
+ *
+ * \param data Data to be copied into newly created wireformat.
+ * \param size Size of data.
+ *
+ * \return Allocated wireformat.
+ */
+uint16_t *alloc_rdata_init(const void *data, size_t size);
+uint16_t rrsig_type_covered(knot_rrset_t *rrset);
+
+
+#endif /* _KNOTD_PARSER_UTIL_H_ */
+
+/*! @} */
diff --git a/src/zcompile/tests/unittests_zp_main.c b/src/zcompile/tests/unittests_zp_main.c
new file mode 100644
index 0000000..5d8c5e9
--- /dev/null
+++ b/src/zcompile/tests/unittests_zp_main.c
@@ -0,0 +1,62 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "knot/common.h"
+#include "common/libtap/tap_unit.h"
+
+// Units to test
+#include "zcompile_tests.c"
+
+// Run all loaded units
+int main(int argc, char *argv[])
+{
+ // Open log
+ //log_init(LOG_UPTO(LOG_ERR), LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING));
+
+ // Build test set
+ unit_api *tests[] = {
+ &zoneparser_tests_api, //! Zoneparser unit
+ NULL
+ };
+
+ // Plan number of tests
+ int id = 0;
+ int test_count = 0;
+ note("Units:");
+ while (tests[id] != NULL) {
+ note("- %s : %d tests", tests[id]->name,
+ tests[id]->count(argc, argv));
+ test_count += tests[id]->count(argc, argv);
+ ++id;
+ }
+
+ plan(test_count);
+
+ // Run tests
+ id = 0;
+ while (tests[id] != NULL) {
+ diag("Testing unit: %s", tests[id]->name);
+ tests[id]->run(argc, argv);
+ ++id;
+ }
+
+ //log_close();
+
+ // Evaluate
+ return exit_status();
+}
+
diff --git a/src/zcompile/tests/zcompile_tests.c b/src/zcompile/tests/zcompile_tests.c
new file mode 100644
index 0000000..5d3dce6
--- /dev/null
+++ b/src/zcompile/tests/zcompile_tests.c
@@ -0,0 +1,425 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "libknot/zone/zone.h"
+#include "knot/zone/zone-load.h"
+#include "knot/common.h"
+#include "libknot/rrset.h"
+#include "libknot/util/descriptor.h"
+#include "zcompile/zcompile.h"
+
+#ifdef TEST_WITH_LDNS
+#include "ldns/ldns.h"
+#endif
+
+static int zoneparser_tests_count(int argc, char *argv[]);
+static int zoneparser_tests_run(int argc, char *argv[]);
+
+/*
+ * Unit API.
+ */
+unit_api zoneparser_tests_api = {
+ "Zoneparser",
+ &zoneparser_tests_count,
+ &zoneparser_tests_run
+};
+
+#ifdef TEST_WITH_LDNS
+/*
+ * Unit implementation.
+ */static int compare_wires_simple_zp(uint8_t *wire1,
+ uint8_t *wire2, uint count)
+{
+ int i = 0;
+ while (i < count &&
+ wire1[i] == wire2[i]) {
+ i++;
+ }
+ return (!(count == i));
+}
+
+/* compares only one rdata */
+static int compare_rr_rdata_silent(knot_rdata_t *rdata, ldns_rr *rr,
+ uint16_t type)
+{
+ knot_rrtype_descriptor_t *desc =
+ knot_rrtype_descriptor_by_type(type);
+ for (int i = 0; i < rdata->count; i++) {
+ /* TODO check for ldns "descriptors" as well */
+ if (desc->wireformat[i] == KNOT_RDATA_WF_COMPRESSED_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_LITERAL_DNAME ||
+ desc->wireformat[i] == KNOT_RDATA_WF_UNCOMPRESSED_DNAME) {
+ assert(ldns_rr_rdf(rr, i));
+ if (rdata->items[i].dname->size !=
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) {
+ return 1;
+ }
+ if (compare_wires_simple_zp(rdata->items[i].dname->name,
+ ldns_rdf_data(ldns_rr_rdf(rr, i)),
+ rdata->items[i].dname->size) != 0) {
+ return 1;
+ }
+ } else {
+ if (ldns_rr_rdf(rr, i) == NULL &&
+ rdata->items[i].raw_data[0] != 0) {
+ return 1;
+ } else {
+ continue;
+ }
+ if (rdata->items[i].raw_data[0] !=
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) {
+
+ /* ldns stores the size including the
+ * length, dnslib does not */
+ if (abs(rdata->items[i].raw_data[0] -
+ ldns_rdf_size(ldns_rr_rdf(rr, i))) != 1) {
+ return 1;
+ }
+ }
+ if (compare_wires_simple_zp((uint8_t *)
+ (rdata->items[i].raw_data + 1),
+ ldns_rdf_data(ldns_rr_rdf(rr, i)),
+ rdata->items[i].raw_data[0]) != 0) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int compare_rrset_w_ldns_rrset(const knot_rrset_t *rrset,
+ ldns_rr_list *rrs,
+ char check_rdata, char verbose)
+{
+ /* We should have only one rrset from ldns, although it is
+ * represented as rr_list ... */
+
+ /* TODO errors */
+
+ assert(rrs);
+ assert(rrset);
+
+ ldns_rr_list_sort(rrs);
+
+ /* compare headers */
+
+ ldns_rr *rr = ldns_rr_list_rr(rrs, 0);
+
+ if (rrset->owner->size != ldns_rdf_size(ldns_rr_owner(rr))) {
+ diag("RRSet owner names differ in length");
+ if (!verbose) {
+ return 1;
+ }
+ diag("ldns: %d, dnslib: %d", ldns_rdf_size(ldns_rr_owner(rr)),
+ rrset->owner->size);
+ diag("%s", knot_dname_to_str(rrset->owner));
+ diag("%s", ldns_rdf_data(ldns_rr_owner(rr)));
+ return 1;
+ }
+
+ if (compare_wires_simple_zp(rrset->owner->name,
+ ldns_rdf_data(ldns_rr_owner(rr)),
+ rrset->owner->size) != 0) {
+ diag("RRSet owner wireformats differ");
+ return 1;
+ }
+
+ if (rrset->type != ldns_rr_get_type(rr)) {
+ diag("RRset types differ");
+ if (!verbose) {
+ return 1;
+ }
+ diag("Dnslib type: %d Ldns type: %d", rrset->type,
+ ldns_rr_get_type(rr));
+ return 1;
+ }
+
+ if (rrset->rclass != ldns_rr_get_class(rr)) {
+ diag("RRset classes differ");
+ return 1;
+ }
+
+ if (rrset->ttl != ldns_rr_ttl(rr)) {
+ diag("RRset TTLs differ");
+ if (!verbose) {
+ return 1;
+ }
+ diag("dnslib: %d ldns: %d", rrset->ttl, ldns_rr_ttl(rr));
+ return 1;
+ }
+
+ if (!check_rdata) {
+ return 0;
+ }
+
+ /* compare rdatas */
+
+ /* sort dnslib rdata */
+
+ knot_rdata_t *tmp_rdata = rrset->rdata;
+
+ rr = ldns_rr_list_pop_rr(rrs);
+
+ char found;
+
+ while (rr != NULL) {
+ found = 0;
+ tmp_rdata = rrset->rdata;
+ while (!found &&
+ tmp_rdata->next != rrset->rdata) {
+ if (compare_rr_rdata_silent(tmp_rdata, rr,
+ rrset->type) == 0) {
+ found = 1;
+ }
+ tmp_rdata = tmp_rdata->next;
+ }
+
+ if (!found &&
+ compare_rr_rdata_silent(tmp_rdata, rr, rrset->type) == 0) {
+ found = 1;
+ }
+
+ /* remove the found rdata from list */
+ if (!found) {
+ diag("RRsets rdata differ");
+ return 1;
+ }
+ ldns_rr_free(rr);
+
+ rr = ldns_rr_list_pop_rr(rrs);
+ }
+
+ return 0;
+}
+
+int compare_zones(knot_zone_contents_t *zone,
+ ldns_rr_list *ldns_list, char verbose)
+{
+ /* TODO currently test fail when encountering first error -
+ * it should finish going through the zone */
+ knot_rrset_t *tmp_rrset = NULL;
+
+ knot_dname_t *tmp_dname = NULL;
+
+ knot_node_t *node = NULL;
+
+ ldns_rr_list *ldns_rrset = ldns_rr_list_pop_rrset(ldns_list);
+
+ if (ldns_rrset == NULL) {
+ diag("Error: empty node");
+ return 1;
+ }
+
+ ldns_rr *rr = NULL;
+
+ /*
+ * Following cycle works like this: First, we get RR from ldns rrset,
+ * then we search for the node containing the rrset, then we get the
+ * rrset, which is then compared with whole ldns rrset.
+ */
+
+ /* ldns_rr_list_pop_rrset should pop the first rrset */
+ while (ldns_rrset != NULL) {
+ rr = ldns_rr_list_rr(ldns_rrset, 0);
+ tmp_dname =
+ knot_dname_new_from_wire(ldns_rdf_data(ldns_rr_owner(rr)),
+ ldns_rdf_size(ldns_rr_owner(rr)),
+ NULL);
+
+ node = knot_zone_contents_get_node(zone, tmp_dname);
+
+ if (node == NULL) {
+ node = knot_zone_contents_get_nsec3_node(zone,
+ tmp_dname);
+ }
+
+ if (node == NULL) {
+ diag("Could not find node");
+ diag("%s", knot_dname_to_str(tmp_dname));
+ return 1;
+ }
+
+ knot_dname_free(&tmp_dname);
+
+ tmp_rrset = knot_node_get_rrset(node,
+ ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset,
+ 0)));
+
+ if (tmp_rrset == NULL &&
+ (uint)(ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset, 0))) !=
+ (uint)KNOT_RRTYPE_RRSIG) {
+ diag("Could not find rrset");
+ if (!verbose) {
+ return 1;
+ }
+ ldns_rr_list_print(stdout, ldns_rrset);
+ diag("%s", knot_dname_to_str(node->owner));
+ return 1;
+ } else if ((uint)(ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset,
+ 0))) ==
+ (uint)KNOT_RRTYPE_RRSIG) {
+ knot_rrset_t *rrsigs = NULL;
+ /* read type covered from ldns rrset */
+ for (int i = 0; i < ldns_rrset->_rr_count; i++) {
+ uint16_t type_covered =
+ ldns_rdf_data(ldns_rr_rdf(
+ ldns_rr_list_rr(ldns_rrset, i), 0))[1];
+
+ /*
+ * Dnslib stores RRSIGs separately -
+ * we have to find get it from its "parent"
+ * rrset.
+ */
+
+ tmp_rrset = knot_node_get_rrset(node,
+ type_covered);
+
+ if (tmp_rrset == NULL) {
+ if (!verbose) {
+ return 1;
+ }
+ diag("following rrset "
+ "could not be found");
+ ldns_rr_list_print(stdout, ldns_rrset);
+ return 1;
+ }
+
+ if (rrsigs == NULL) {
+ rrsigs = tmp_rrset->rrsigs;
+ } else {
+ knot_rrset_merge((void *)&rrsigs,
+ (void *)&(tmp_rrset->rrsigs));
+ }
+ }
+ tmp_rrset = rrsigs;
+ }
+
+/* diag("dnslib type: %d", tmp_rrset->type);
+ diag("dnslib dname: %s", tmp_rrset->owner->name);
+
+ diag("ldns type: %d",
+ ldns_rr_get_type(ldns_rr_list_rr(ldns_rrset, 0)));
+ diag("ldns dname : %s", ldns_rdf_data(ldns_rr_owner(
+ ldns_rr_list_rr(ldns_rrset, 0)))); */
+
+// knot_rrset_dump(tmp_rrset, 1);
+
+ if (compare_rrset_w_ldns_rrset(tmp_rrset, ldns_rrset,
+ 1, 0) != 0) {
+ diag("RRSets did not match");
+// knot_rrset_dump(tmp_rrset, 1);
+ return 1;
+ }
+
+ ldns_rr_list_deep_free(ldns_rrset);
+
+ ldns_rrset = ldns_rr_list_pop_rrset(ldns_list);
+
+ if (ldns_rrset == NULL) {
+ ldns_rrset = ldns_rr_list_pop_rrset(ldns_list);
+ }
+ }
+
+ return 0;
+}
+
+#endif
+
+static int test_zoneparser_zone_read(const char *origin, const char *filename,
+ const char *outfile)
+{
+#ifndef TEST_WITH_LDNS
+ diag("Zoneparser tests without usage of ldns are not implemented");
+ return 0;
+#endif
+
+#ifdef TEST_WITH_LDNS
+ /* Calls zcompile. */
+ parser = zparser_create();
+ int ret = zone_read(origin, filename, outfile, 0);
+ if (ret != 0) {
+ diag("Could not load zone from file: %s", filename);
+ return 0;
+ }
+
+ knot_zone_t *dnsl_zone = NULL;
+ zloader_t *loader = NULL;
+ if (knot_zload_open(&loader, outfile) != 0) {
+ diag("Could not create zone loader.\n");
+ return 0;
+ }
+ dnsl_zone = knot_zload_load(loader);
+ remove(outfile);
+ if (!dnsl_zone) {
+ diag("Could not load dumped zone.\n");
+ return 0;
+ }
+
+ ldns_zone *ldns_zone = NULL;
+ FILE *f = fopen(filename, "r");
+ if (ldns_zone_new_frm_fp(&ldns_zone, f, NULL,
+ 0, LDNS_RR_CLASS_IN) != LDNS_STATUS_OK) {
+ diag("Could not load zone from file: %s (ldns)", filename);
+ return 0;
+ }
+
+// ldns_zone_sort(ldns_zone);
+
+ /*
+ * LDNS stores SOA record independently - create a list with all
+ * records in it.
+ */
+
+ ldns_rr_list *ldns_list = ldns_zone_rrs(ldns_zone);
+
+ ldns_rr_list_push_rr(ldns_list, ldns_zone_soa(ldns_zone));
+
+ if (compare_zones(dnsl_zone->contents, ldns_list, 0) != 0) {
+ return 0;
+ }
+
+ knot_zone_deep_free(&dnsl_zone, 0);
+ ldns_zone_free(ldns_zone);
+ fclose(f);
+ return 1;
+#endif
+}
+
+static const int ZONEPARSER_TEST_COUNT = 1;
+
+/*! API: return number of tests. */
+static int zoneparser_tests_count(int argc, char *argv[])
+{
+ return ZONEPARSER_TEST_COUNT;
+}
+
+/*! API: run tests. */
+static int zoneparser_tests_run(int argc, char *argv[])
+{
+ if (argc == 3) {
+ ok(test_zoneparser_zone_read(argv[1], argv[2],
+ "foo_test_zone"),
+ "zoneparser: read (%s)",
+ argv[2]);
+ } else {
+ diag("Wrong parameters\n usage: "
+ "knot-zcompile-unittests origin zonefile");
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/zcompile/zcompile-error.c b/src/zcompile/zcompile-error.c
new file mode 100644
index 0000000..9357cde
--- /dev/null
+++ b/src/zcompile/zcompile-error.c
@@ -0,0 +1,52 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "zcompile/zcompile-error.h"
+
+#include "common/errors.h"
+
+/*! \brief Table linking error messages to error codes. */
+const error_table_t knot_zcompile_error_msgs[KNOTDZCOMPILE_ERROR_COUNT] = {
+
+ /* Mapped errors. */
+ {KNOTDZCOMPILE_EOK, "OK"},
+ {KNOTDZCOMPILE_ENOMEM, "Not enough memory."},
+ {KNOTDZCOMPILE_EINVAL, "Invalid parameter passed."},
+ {KNOTDZCOMPILE_ENOTSUP, "Parameter not supported."},
+ {KNOTDZCOMPILE_EBUSY, "Requested resource is busy."},
+ {KNOTDZCOMPILE_EAGAIN,
+ "The system lacked the necessary resource, try again."},
+ {KNOTDZCOMPILE_EACCES,
+ "Permission to perform requested operation is denied."},
+ {KNOTDZCOMPILE_ECONNREFUSED, "Connection is refused."},
+ {KNOTDZCOMPILE_EISCONN, "Already connected."},
+ {KNOTDZCOMPILE_EADDRINUSE, "Address already in use."},
+ {KNOTDZCOMPILE_ENOENT, "Resource not found."},
+ {KNOTDZCOMPILE_ERANGE, "Value is out of range."},
+
+ /* Custom errors. */
+ {KNOTDZCOMPILE_ERROR, "Generic error."},
+ {KNOTDZCOMPILE_EBRDATA, "Malformed RDATA."},
+ {KNOTDZCOMPILE_ESOA, "Multiple SOA records."},
+ {KNOTDZCOMPILE_EBADSOA, "SOA record has different owner "
+ "than in config - parser will not continue!"},
+ {KNOTDZCOMPILE_EBADNODE, "Error handling node."},
+ {KNOTDZCOMPILE_EZONEINVAL, "Invalid zone file."},
+ {KNOTDZCOMPILE_EPARSEFAIL, "Parser failed."},
+ {KNOTDZCOMPILE_ENOIPV6, "IPv6 support disabled."},
+ {KNOTDZCOMPILE_ESYNT, "Parser syntactic error."},
+ {KNOTDZCOMPILE_ERROR, 0}
+};
diff --git a/src/zcompile/zcompile-error.h b/src/zcompile/zcompile-error.h
new file mode 100644
index 0000000..c6d999c
--- /dev/null
+++ b/src/zcompile/zcompile-error.h
@@ -0,0 +1,90 @@
+/*!
+ * \file zcompile-error.h
+ *
+ * \author Lubos Slovak <lubos.slovak@nic.cz>
+ * \author Marek Vavrusa <marek.vavrusa@nic.cz>
+ * \author Jan Kadlec <jan.kadlec@nic.cz>
+ *
+ * \brief Error codes and function for getting error message.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _KNOTD_ZCOMPILE_ERROR_H_
+#define _KNOTD_ZCOMPILE_ERROR_H_
+
+#include "common/errors.h"
+
+/*!
+ * \brief Error codes used in the server.
+ *
+ * Some viable errors are directly mapped
+ * to libc errno codes.
+ */
+enum knot_zcompile_error {
+
+ /* Directly mapped error codes. */
+ KNOTDZCOMPILE_EOK = 0,
+ KNOTDZCOMPILE_ENOMEM = -ENOMEM, /*!< \brief Out of memory. */
+ KNOTDZCOMPILE_EINVAL = -EINVAL, /*!< \brief Invalid parameter passed. */
+ /*!
+ * \brief Parameter not supported.
+ */
+ KNOTDZCOMPILE_ENOTSUP = -ENOTSUP,
+ KNOTDZCOMPILE_EBUSY = -EBUSY, /*!< \brief Requested resource is busy. */
+ /*!
+ * \brief OS lacked necessary resources.
+ */
+ KNOTDZCOMPILE_EAGAIN = -EAGAIN,
+ KNOTDZCOMPILE_EACCES = -EACCES, /*!< \brief Permission is denied. */
+ /*!
+ * \brief Connection is refused.
+ */
+ KNOTDZCOMPILE_ECONNREFUSED = -ECONNREFUSED,
+ KNOTDZCOMPILE_EISCONN = -EISCONN, /*!< \brief Already connected. */
+ /*!
+ * \brief Address already in use.
+ */
+ KNOTDZCOMPILE_EADDRINUSE = -EADDRINUSE,
+ KNOTDZCOMPILE_ENOENT = -ENOENT, /*!< \brief Resource not found. */
+ KNOTDZCOMPILE_ERANGE = -ERANGE, /*!< \brief Value is out of range. */
+
+ /* Custom error codes. */
+ KNOTDZCOMPILE_ERROR = -16384, /*!< \brief Generic error. */
+ KNOTDZCOMPILE_ESYNT, /*!< \brief Syntax error. */
+ KNOTDZCOMPILE_EBADNODE, /*!< \brief Node error. */
+ KNOTDZCOMPILE_EBRDATA, /*!< \brief RDATA error. */
+ KNOTDZCOMPILE_EBADSOA, /*!< \brief SOA owner error. */
+ KNOTDZCOMPILE_ESOA, /*!< \brief Multiple SOA records. */
+
+ KNOTDZCOMPILE_EZONEINVAL, /*!< \brief Invalid zone file. */
+ KNOTDZCOMPILE_EPARSEFAIL, /*!< \brief Parser fail. */
+ KNOTDZCOMPILE_ENOIPV6, /*! \brief No IPv6 support. */
+
+ KNOTDZCOMPILE_ERROR_COUNT = 22
+};
+
+typedef enum knot_zcompile_error knot_zcompile_error_t;
+
+/*! \brief Table linking error messages to error codes. */
+extern const error_table_t knot_zcompile_error_msgs[KNOTDZCOMPILE_ERROR_COUNT];
+
+#endif /* _KNOTD_ZCOMPILE_ERROR_H_ */
+
+/*! @} */
diff --git a/src/zcompile/zcompile.c b/src/zcompile/zcompile.c
new file mode 100644
index 0000000..ec3cbe2
--- /dev/null
+++ b/src/zcompile/zcompile.c
@@ -0,0 +1,639 @@
+/*!
+ * \file zcompile.c
+ *
+ * \author Jan Kadlec <jan.kadlec@nic.cz>. Minor portions of code taken from
+ * NSD.
+ *
+ * \brief Zone compiler.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "common/base32hex.h"
+#include "zcompile/zcompile.h"
+#include "zcompile/parser-util.h"
+#include "knot/zone/zone-dump-text.h"
+#include "zparser.h"
+#include "zcompile/zcompile-error.h"
+#include "knot/zone/zone-dump.h"
+#include "libknot/libknot.h"
+#include "libknot/util/utils.h"
+
+/* Some global flags... */
+static int vflag = 0;
+/* if -v then print progress each 'progress' RRs */
+static int progress = 10000;
+
+/* Total errors counter */
+static long int totalerrors = 0;
+static long int totalrrs = 0;
+
+extern FILE *zp_get_in(void *scanner);
+
+//#define ZP_DEBUG
+
+#ifdef ZP_DEBUG
+#define dbg_zp(msg...) fprintf(stderr, msg)
+#else
+#define dbg_zp(msg...)
+#endif
+
+/*!
+ * \brief Adds RRSet to list.
+ *
+ * \param head Head of list.
+ * \param rrsig RRSet to be added.
+ */
+static int rrset_list_add(rrset_list_t **head, knot_rrset_t *rrsig)
+{
+ if (*head == NULL) {
+ *head = malloc(sizeof(rrset_list_t));
+ if (*head == NULL) {
+ ERR_ALLOC_FAILED;
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+ (*head)->next = NULL;
+ (*head)->data = rrsig;
+ } else {
+ rrset_list_t *tmp = malloc(sizeof(*tmp));
+ if (tmp == NULL) {
+ ERR_ALLOC_FAILED;
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+ tmp->next = *head;
+ tmp->data = rrsig;
+ *head = tmp;
+ }
+
+ return KNOTDZCOMPILE_EOK;
+}
+
+/*!
+ * \brief Deletes RRSet list. Sets pointer to NULL.
+ *
+ * \param head Head of list to be deleted.
+ */
+static void rrset_list_delete(rrset_list_t **head)
+{
+ rrset_list_t *tmp;
+ if (*head == NULL) {
+ return;
+ }
+
+ while (*head != NULL) {
+ tmp = *head;
+ *head = (*head)->next;
+ free(tmp);
+ }
+
+ *head = NULL;
+}
+
+static int find_rrset_for_rrsig_in_zone(knot_zone_contents_t *zone,
+ knot_rrset_t *rrsig)
+{
+ assert(rrsig != NULL);
+ assert(rrsig->rdata->items[0].raw_data);
+
+ knot_node_t *tmp_node = NULL;
+
+ if (rrsig->type != KNOT_RRTYPE_NSEC3) {
+ tmp_node = knot_zone_contents_get_node(zone, rrsig->owner);
+ } else {
+ tmp_node = knot_zone_contents_get_nsec3_node(zone,
+ rrsig->owner);
+ }
+
+ if (tmp_node == NULL) {
+ return KNOTDZCOMPILE_EINVAL;
+ }
+
+ knot_rrset_t *tmp_rrset =
+ knot_node_get_rrset(tmp_node, rrsig->type);
+
+ if (tmp_rrset == NULL) {
+ return KNOTDZCOMPILE_EINVAL;
+ }
+
+ if (tmp_rrset->rrsigs != NULL) {
+ knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &tmp_node,
+ KNOT_RRSET_DUPL_MERGE, 1);
+ knot_rrset_free(&rrsig);
+ } else {
+ knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &tmp_node,
+ KNOT_RRSET_DUPL_SKIP, 1);
+ }
+
+ return KNOTDZCOMPILE_EOK;
+}
+
+static int find_rrset_for_rrsig_in_node(knot_zone_contents_t *zone,
+ knot_node_t *node,
+ knot_rrset_t *rrsig)
+{
+ assert(rrsig != NULL);
+ assert(rrsig->rdata->items[0].raw_data);
+ assert(node);
+
+ assert(knot_dname_compare(rrsig->owner, node->owner) == 0);
+
+ knot_rrset_t *tmp_rrset =
+ knot_node_get_rrset(node, rrsig_type_covered(rrsig));
+
+ if (tmp_rrset == NULL) {
+ return KNOTDZCOMPILE_EINVAL;
+ }
+
+ if (tmp_rrset->rrsigs != NULL) {
+ if (knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &node,
+ KNOT_RRSET_DUPL_MERGE, 1) < 0) {
+ return KNOTDZCOMPILE_EINVAL;
+ }
+ knot_rrset_free(&rrsig);
+ } else {
+ if (knot_zone_contents_add_rrsigs(zone, rrsig, &tmp_rrset, &node,
+ KNOT_RRSET_DUPL_SKIP, 1) < 0) {
+ return KNOTDZCOMPILE_EINVAL;
+ }
+ }
+
+ assert(tmp_rrset->rrsigs != NULL);
+
+ return KNOTDZCOMPILE_EOK;
+}
+
+static knot_node_t *create_node(knot_zone_contents_t *zone,
+ knot_rrset_t *current_rrset,
+ int (*node_add_func)(knot_zone_contents_t *zone, knot_node_t *node,
+ int create_parents, uint8_t, int),
+ knot_node_t *(*node_get_func)(const knot_zone_contents_t *zone,
+ const knot_dname_t *owner))
+{
+ knot_node_t *node =
+ knot_node_new(current_rrset->owner, NULL, 0);
+ if (node_add_func(zone, node, 1, 0, 1) != 0) {
+ return NULL;
+ }
+
+ current_rrset->owner = node->owner;
+
+ return node;
+}
+
+static void process_rrsigs_in_node(knot_zone_contents_t *zone,
+ knot_node_t *node)
+{
+ rrset_list_t *tmp = parser->node_rrsigs;
+ while (tmp != NULL) {
+ if (find_rrset_for_rrsig_in_node(zone, node,
+ tmp->data) != 0) {
+ rrset_list_add(&parser->rrsig_orphans,
+ tmp->data);
+ parser->rrsig_orphan_count++;
+ }
+ tmp = tmp->next;
+ }
+}
+
+int process_rr(void)
+{
+ knot_zone_t *zone = parser->current_zone;
+ assert(zone != NULL);
+ knot_zone_contents_t *contents = knot_zone_get_contents(zone);
+ assert(contents != NULL);
+ knot_rrset_t *current_rrset = parser->current_rrset;
+ knot_rrset_t *rrset;
+ knot_rrtype_descriptor_t *descriptor =
+ knot_rrtype_descriptor_by_type(current_rrset->type);
+
+ dbg_zp("%s\n", knot_dname_to_str(parser->current_rrset->owner));
+ dbg_zp("type: %s\n", knot_rrtype_to_string(parser->current_rrset->type));
+ dbg_zp("rdata count: %d\n", parser->current_rrset->rdata->count);
+// hex_print(parser->current_rrset->rdata->items[0].raw_data,
+// parser->current_rrset->rdata->items[0].raw_data[0]);
+
+ if (descriptor->fixed_items) {
+ assert(current_rrset->rdata->count == descriptor->length);
+ }
+
+ assert(current_rrset->rdata->count > 0);
+
+ assert(knot_dname_is_fqdn(current_rrset->owner));
+
+ int (*node_add_func)(knot_zone_contents_t *, knot_node_t *, int,
+ uint8_t, int);
+ knot_node_t *(*node_get_func)(const knot_zone_contents_t *,
+ const knot_dname_t *);
+
+
+ /* If we have RRSIG of NSEC3 type first node will have
+ * to be created in NSEC3 part of the zone */
+
+ uint16_t type_covered = 0;
+ if (current_rrset->type == KNOT_RRTYPE_RRSIG) {
+ type_covered = rrsig_type_covered(current_rrset);
+ }
+
+ if (current_rrset->type != KNOT_RRTYPE_NSEC3 &&
+ type_covered != KNOT_RRTYPE_NSEC3) {
+ node_add_func = &knot_zone_contents_add_node;
+ node_get_func = &knot_zone_contents_get_node;
+ } else {
+ node_add_func = &knot_zone_contents_add_nsec3_node;
+ node_get_func = &knot_zone_contents_get_nsec3_node;
+ }
+
+ if ((current_rrset->type == KNOT_RRTYPE_SOA) && (zone != NULL)) {
+ if (knot_node_rrset(knot_zone_contents_apex(contents),
+ KNOT_RRTYPE_SOA) != NULL) {
+ /* Receiving another SOA. */
+ if (!knot_rrset_compare(current_rrset,
+ knot_node_rrset(knot_zone_contents_apex(contents),
+ KNOT_RRTYPE_SOA), KNOT_RRSET_COMPARE_WHOLE)) {
+ return KNOTDZCOMPILE_ESOA;
+ } else {
+ zc_warning_prev_line("encountered identical "
+ "extra SOA record");
+ return KNOTDZCOMPILE_EOK;
+ }
+ }
+ }
+
+ /*!< \todo Make sure the maximum RDLENGTH does not exceed 65535 bytes.*/
+
+ if (current_rrset->type == KNOT_RRTYPE_SOA) {
+ if (knot_dname_compare(current_rrset->owner,
+ parser->origin_from_config) != 0) {
+ zc_error_prev_line("SOA record has a different "
+ "owner than the one specified "
+ "in config! \n");
+ /* Such SOA cannot even be added, because
+ * it would not be in the zone apex. */
+ return KNOTDZCOMPILE_EBADSOA;
+ }
+ }
+
+ if (current_rrset->type == KNOT_RRTYPE_RRSIG) {
+ /*!< \todo Still a leak somewhere. */
+ knot_rrset_t *tmp_rrsig =
+ knot_rrset_new(current_rrset->owner,
+ KNOT_RRTYPE_RRSIG,
+ current_rrset->rclass,
+ current_rrset->ttl);
+ if (tmp_rrsig == NULL) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ if (knot_rrset_add_rdata(tmp_rrsig,
+ current_rrset->rdata) != 0) {
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+
+ if (parser->last_node &&
+ knot_dname_compare(parser->last_node->owner,
+ current_rrset->owner) != 0) {
+ /* RRSIG is first in the node, so we have to create it
+ * before we return
+ */
+ if (parser->node_rrsigs != NULL) {
+ process_rrsigs_in_node(contents,
+ parser->last_node);
+ rrset_list_delete(&parser->node_rrsigs);
+ }
+
+ if ((parser->last_node = create_node(contents,
+ current_rrset, node_add_func,
+ node_get_func)) == NULL) {
+ knot_rrset_free(&tmp_rrsig);
+ return KNOTDZCOMPILE_EBADNODE;
+ }
+ }
+
+ if (rrset_list_add(&parser->node_rrsigs, tmp_rrsig) != 0) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ return KNOTDZCOMPILE_EOK;
+ }
+
+ assert(current_rrset->type != KNOT_RRTYPE_RRSIG);
+
+ knot_node_t *node = NULL;
+ /* \note this could probably be much simpler */
+ if (parser->last_node && current_rrset->type != KNOT_RRTYPE_SOA &&
+ knot_dname_compare(parser->last_node->owner,
+ current_rrset->owner) ==
+ 0) {
+ node = parser->last_node;
+ } else {
+ if (parser->last_node && parser->node_rrsigs) {
+ process_rrsigs_in_node(contents,
+ parser->last_node);
+ }
+
+ rrset_list_delete(&parser->node_rrsigs);
+
+ /* new node */
+ node = node_get_func(contents, current_rrset->owner);
+ }
+
+ if (node == NULL) {
+ if (parser->last_node && parser->node_rrsigs) {
+ process_rrsigs_in_node(contents,
+ parser->last_node);
+ }
+
+ if ((node = create_node(contents, current_rrset,
+ node_add_func,
+ node_get_func)) == NULL) {
+ return KNOTDZCOMPILE_EBADNODE;
+ }
+ }
+
+ rrset = knot_node_get_rrset(node, current_rrset->type);
+ if (!rrset) {
+ rrset = knot_rrset_new(current_rrset->owner,
+ current_rrset->type,
+ current_rrset->rclass,
+ current_rrset->ttl);
+ if (rrset == NULL) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ if (knot_rrset_add_rdata(rrset, current_rrset->rdata) != 0) {
+ free(rrset);
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+
+ /* I chose skip, but there should not really be
+ * any rrset to skip */
+ if (knot_zone_contents_add_rrset(contents, rrset, &node,
+ KNOT_RRSET_DUPL_SKIP, 1) < 0) {
+ free(rrset);
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+ } else {
+ if (current_rrset->type !=
+ KNOT_RRTYPE_RRSIG && rrset->ttl !=
+ current_rrset->ttl) {
+ zc_error_prev_line(
+ "TTL does not match the TTL of the RRset");
+ }
+
+ if (knot_zone_contents_add_rrset(contents, current_rrset,
+ &node,
+ KNOT_RRSET_DUPL_MERGE, 1) < 0) {
+ return KNOTDZCOMPILE_EBRDATA;
+ }
+ }
+
+ if (vflag > 1 && totalrrs > 0 && (totalrrs % progress == 0)) {
+ zc_error_prev_line("Total errors: %ld\n", totalrrs);
+ }
+
+ parser->last_node = node;
+
+ ++totalrrs;
+
+ return KNOTDZCOMPILE_EOK;
+}
+
+static uint find_rrsets_orphans(knot_zone_contents_t *zone, rrset_list_t
+ *head)
+{
+ uint found_rrsets = 0;
+ while (head != NULL) {
+ if (find_rrset_for_rrsig_in_zone(zone, head->data) == 0) {
+ found_rrsets += 1;
+ dbg_zp("RRSET succesfully found: owner %s type %s\n",
+ knot_dname_to_str(head->data->owner),
+ knot_rrtype_to_string(head->data->type));
+ }
+ else { /* we can throw it away now */
+ knot_rrset_free(&head->data);
+ }
+ head = head->next;
+ }
+ return found_rrsets;
+}
+
+/*
+ *
+ * Opens a zone file.
+ *
+ * Returns:
+ *
+ * - pointer to the parser structure
+ * - NULL on error and errno set
+ *
+ */
+static int zone_open(const char *filename, uint32_t ttl, uint16_t rclass,
+ knot_node_t *origin, void *scanner, knot_dname_t *origin_from_config)
+{
+ /* Open the zone file... */
+ if (strcmp(filename, "-") == 0) {
+ zp_set_in(stdin, scanner);
+ filename = "<stdin>";
+ } else {
+ FILE *f = fopen(filename, "r");
+ if (f == NULL) {
+ return 0;
+ }
+ zp_set_in(f, scanner);
+ if (zp_get_in(scanner) == 0) {
+ return 0;
+ }
+ }
+
+// int fd = fileno(zp_get_in(scanner));
+// if (fd == -1) {
+// return 0;
+// }
+
+// if (fcntl(fd, F_SETLK, knot_file_lock(F_RDLCK, SEEK_SET)) == -1) {
+// fprintf(stderr, "Could not lock zone file for read!\n");
+// return 0;
+// }
+
+ zparser_init(filename, ttl, rclass, origin, origin_from_config);
+
+ return 1;
+}
+
+/*
+ * Reads the specified zone into the memory
+ *
+ */
+int zone_read(const char *name, const char *zonefile, const char *outfile,
+ int semantic_checks)
+{
+ if (!outfile) {
+ zc_error_prev_line("Missing output file for '%s'\n",
+ zonefile);
+ return KNOTDZCOMPILE_EINVAL;
+ }
+
+ /* Check that we can write to outfile. */
+ FILE *f = fopen(outfile, "wb");
+ if (f == NULL) {
+ fprintf(stderr, "Cannot write zone db to file '%s'\n",
+ outfile);
+ return KNOTDZCOMPILE_EINVAL;
+ }
+ fclose(f);
+
+
+// char ebuf[256];
+
+ knot_dname_t *dname =
+ knot_dname_new_from_str(name, strlen(name), NULL);
+ if (dname == NULL) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ knot_node_t *origin_node = knot_node_new(dname, NULL, 0);
+
+ /*!< \todo Another copy is probably not needed. */
+ knot_dname_t *origin_from_config =
+ knot_dname_new_from_str(name, strlen(name), NULL);
+ if (origin_from_config == NULL) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ //assert(origin_node->next == NULL);
+
+ assert(knot_node_parent(origin_node, 0) == NULL);
+ if (origin_node == NULL) {
+ knot_dname_release(dname);
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ void *scanner = NULL;
+ zp_lex_init(&scanner);
+ if (scanner == NULL) {
+ return KNOTDZCOMPILE_ENOMEM;
+ }
+
+ if (!zone_open(zonefile, 3600, KNOT_CLASS_IN, origin_node, scanner,
+ origin_from_config)) {
+ zc_error_prev_line("Cannot open '%s'\n",
+ zonefile);
+ zparser_free();
+ return KNOTDZCOMPILE_EZONEINVAL;
+ }
+
+ if (zp_parse(scanner) != 0) {
+// int fd = fileno(zp_get_in(scanner));
+// if (fcntl(fd, F_SETLK,
+// knot_file_lock(F_UNLCK, SEEK_SET)) == -1) {
+// return KNOTDZCOMPILE_EACCES;
+// }
+
+ FILE *in_file = (FILE *)zp_get_in(scanner);
+ fclose(in_file);
+ zp_lex_destroy(scanner);
+
+ return KNOTDZCOMPILE_ESYNT;
+ }
+
+ knot_zone_contents_t *contents =
+ knot_zone_get_contents(parser->current_zone);
+
+ FILE *in_file = (FILE *)zp_get_in(scanner);
+ fclose(in_file);
+ zp_lex_destroy(scanner);
+
+ /* Unlock zone file. */
+// int fd = fileno(zp_get_in(scanner));
+// if (fcntl(fd, F_SETLK, knot_file_lock(F_UNLCK, SEEK_SET)) == -1) {
+// fprintf(stderr, "Could not lock zone file for read!\n");
+// return 0;
+// }
+
+ dbg_zp("zp complete %p\n", parser->current_zone);
+
+ if (parser->last_node && parser->node_rrsigs != NULL) {
+ /* assign rrsigs to last node in the zone*/
+ process_rrsigs_in_node(contents,
+ parser->last_node);
+ rrset_list_delete(&parser->node_rrsigs);
+ }
+
+ dbg_zp("zone parsed\n");
+
+ if (!(parser->current_zone &&
+ knot_node_rrset(parser->current_zone->contents->apex,
+ KNOT_RRTYPE_SOA))) {
+ zc_error_prev_line("Zone file does not contain SOA record!\n");
+ knot_zone_deep_free(&parser->current_zone, 1);
+ zparser_free();
+ return KNOTDZCOMPILE_EZONEINVAL;
+ }
+
+ uint found_orphans;
+ found_orphans = find_rrsets_orphans(contents,
+ parser->rrsig_orphans);
+
+ dbg_zp("%u orphans found\n", found_orphans);
+
+ rrset_list_delete(&parser->rrsig_orphans);
+
+ if (found_orphans != parser->rrsig_orphan_count) {
+ fprintf(stderr,
+ "There are unassigned RRSIGs in the zone!\n");
+ parser->errors++;
+ }
+
+ knot_zone_contents_adjust(contents, 0);
+
+ dbg_zp("rdata adjusted\n");
+
+ if (parser->errors != 0) {
+ fprintf(stderr,
+ "Parser finished with error, not dumping the zone!\n");
+ } else {
+ if (knot_zdump_binary(contents,
+ outfile, semantic_checks,
+ zonefile) != 0) {
+ fprintf(stderr, "Could not dump zone!\n");
+ totalerrors++;
+ }
+ dbg_zp("zone dumped.\n");
+ }
+
+ /* This is *almost* unnecessary */
+ knot_zone_deep_free(&(parser->current_zone), 1);
+
+ fflush(stdout);
+ totalerrors += parser->errors;
+ zparser_free();
+
+ return totalerrors;
+}
+
+/*! @} */
diff --git a/src/zcompile/zcompile.h b/src/zcompile/zcompile.h
new file mode 100644
index 0000000..33dd3ee
--- /dev/null
+++ b/src/zcompile/zcompile.h
@@ -0,0 +1,207 @@
+/*!
+ * \file zoneparser.h
+ *
+ * \author modifications by Jan Kadlec <jan.kadlec@nic.cz>, most of the code
+ * by NLnet Labs.
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief Zone compiler.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _KNOTD_ZONEPARSER_H_
+#define _KNOTD_ZONEPARSER_H_
+
+#include <stdio.h>
+
+#include "libknot/dname.h"
+#include "libknot/rrset.h"
+#include "libknot/zone/node.h"
+#include "libknot/rdata.h"
+#include "libknot/zone/zone.h"
+#include "libknot/zone/dname-table.h"
+#include "libknot/zone/dname-table.h"
+#include "common/slab/slab.h"
+
+#define MAXRDATALEN 64 /*!< Maximum number of RDATA items. */
+#define MAXLABELLEN 63 /*!< Maximum label length. */
+#define MAXDOMAINLEN 255 /*!< Maximum domain name length */
+#define MAX_RDLENGTH 65535 /*!< Maximum length of RDATA item */
+#define MAXTOKENSLEN 512 /*!< Maximum number of tokens per entry. */
+#define B64BUFSIZE 65535 /*!< Buffer size for b64 conversion. */
+#define ROOT (const uint8_t *)"\001" /*!< Root domain name. */
+
+#define NSEC_WINDOW_COUNT 256 /*!< Number of NSEC windows. */
+#define NSEC_WINDOW_BITS_COUNT 256 /*!< Number of bits in NSEC window. */
+/*! \brief Size of NSEC window in bytes. */
+#define NSEC_WINDOW_BITS_SIZE (NSEC_WINDOW_BITS_COUNT / 8)
+
+/*
+ * RFC 4025 - codes for different types that IPSECKEY can hold.
+ */
+#define IPSECKEY_NOGATEWAY 0
+#define IPSECKEY_IP4 1
+#define IPSECKEY_IP6 2
+#define IPSECKEY_DNAME 3
+
+#define LINEBUFSZ 1024 /*!< Buffer size for one line in zone file. */
+
+struct lex_data {
+ size_t len; /*!< holds the label length */
+ char *str; /*!< holds the data */
+};
+
+#define DEFAULT_TTL 3600
+
+int yylex_destroy(void *scanner);
+int zp_parse(void *scanner);
+void zp_set_in(FILE *f, void *scanner);
+int zp_lex_init(void **scanner);
+int zp_lex_destroy(void *scanner);
+
+/*! \todo Implement ZoneDB. */
+typedef void namedb_type;
+
+/*!
+ * \brief One-purpose linked list holding pointers to RRSets.
+ */
+struct rrset_list {
+ knot_rrset_t *data; /*!< List data. */
+ struct rrset_list *next; /*!< Next node. */
+};
+
+typedef struct rrset_list rrset_list_t;
+
+/*!
+ * \brief Main zoneparser structure.
+ */
+struct zparser {
+ const char *filename; /*!< File with zone. */
+ uint32_t default_ttl; /*!< Default TTL. */
+ uint16_t default_class; /*!< Default class. */
+ knot_zone_t *current_zone; /*!< Current zone. */
+ knot_node_t *origin; /*!< Origin node. */
+ knot_dname_t *prev_dname; /*!< Previous dname. */
+ knot_dname_t *origin_from_config; /*!< Zone origin from config. */
+ knot_node_t *default_apex; /*!< Zone default apex. */
+
+ knot_node_t *last_node; /*!< Last processed node. */
+
+ char *dname_str; /*!< Temporary dname. */
+
+ int error_occurred; /*!< Error occured flag */
+ unsigned int errors; /*!< Number of errors. */
+ unsigned int line; /*!< Current line */
+
+ knot_rrset_t *current_rrset; /*!< Current RRSet. */
+ knot_rdata_item_t *temporary_items; /*!< Temporary rdata items. */
+
+ /*!
+ * \brief list of RRSIGs that were not inside their nodes in zone file
+ */
+ rrset_list_t *rrsig_orphans;
+ unsigned long rrsig_orphan_count; /*!< RRSIG orphan count */
+
+ knot_dname_t *root_domain; /*!< Root domain name. */
+ slab_cache_t *parser_slab; /*!< Slab for parser. */
+ rrset_list_t *node_rrsigs; /*!< List of RRSIGs in current node. */
+
+ int rdata_count; /*!< Count of parsed rdata. */
+};
+
+typedef struct zparser zparser_type;
+
+extern zparser_type *parser;
+
+extern void zc_error_prev_line(const char *fmt, ...);
+
+/* used in zonec.lex */
+
+void zc_error_prev_line(const char *fmt, ...);
+void zc_warning_prev_line(const char *fmt, ...);
+
+/*!
+ * \brief Does all the processing of RR - saves to zone, assigns RRSIGs etc.
+ */
+int process_rr();
+
+/*!
+ * \brief Parses and creates zone from given file.
+ *
+ * \param name Origin domain name string.
+ * \param zonefile File containing the zone.
+ * \param outfile File to save dump of the zone to.
+ * \param semantic_checks Enables or disables sematic checks.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int zone_read(const char *name, const char *zonefile, const char *outfile,
+ int semantic_checks);
+
+/*!
+ * \brief Creates zparser instance.
+ *
+ *
+ * \return Created zparser instance.
+ */
+zparser_type *zparser_create();
+
+/*!
+ * \brief Inits zoneparser structure.
+ *
+ * \param filename Name of file with zone.
+ * \param ttl Default TTL.
+ * \param rclass Default class.
+ * \param origin Zone origin.
+ */
+void zparser_init(const char *filename, uint32_t ttl, uint16_t rclass,
+ knot_node_t *origin, knot_dname_t *owner_from_config);
+
+/*!
+ * \brief Frees zoneparser structure.
+ *
+ */
+void zparser_free();
+
+int save_dnames_in_table(knot_dname_table_t *table,
+ knot_rrset_t *rrset);
+
+#endif /* _KNOTD_ZONEPARSER_H_ */
+
+/*! @} */
diff --git a/src/zcompile/zcompile_main.c b/src/zcompile/zcompile_main.c
new file mode 100644
index 0000000..cb862f8
--- /dev/null
+++ b/src/zcompile/zcompile_main.c
@@ -0,0 +1,116 @@
+/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "zcompile/zcompile.h"
+#include "zcompile/zcompile-error.h"
+#include "common/errors.h"
+#include <config.h>
+
+static void help(int argc, char **argv)
+{
+ printf("Usage: %s [parameters] origin zonefile\n",
+ argv[0]);
+ printf("Parameters:\n"
+ " -o <outfile> Override output file.\n"
+ " -v Verbose mode - additional runtime information.\n"
+ " -s Enable semantic checks.\n"
+ " -V Print version of the server.\n"
+ " -h Print help and usage.\n");
+}
+
+int main(int argc, char **argv)
+{
+ // Parse command line arguments
+ int c = 0;
+ int verbose = 0;
+ int semantic_checks = 0;
+ const char* origin = 0;
+ const char* zonefile = 0;
+ const char* outfile = 0;
+ while ((c = getopt (argc, argv, "o:vVsh")) != -1) {
+ switch (c)
+ {
+ case 'o':
+ outfile = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'V':
+ printf("%s, version %s\n", "Knot DNS", PACKAGE_VERSION);
+ return 0;
+ case 's':
+ semantic_checks = 1;
+ break;
+ case 'h':
+ case '?':
+ default:
+ if (optopt == 'o') {
+ fprintf (stderr,
+ "Option -%c requires an argument.\n",
+ optopt);
+ }
+ help(argc, argv);
+ return 1;
+ }
+ }
+
+ UNUSED(verbose);
+
+ // Check if there's at least two remaining non-option
+ if (argc - optind < 2) {
+ help(argc, argv);
+ return 1;
+ }
+
+ origin = argv[optind];
+ zonefile = argv[optind + 1];
+
+ // Initialize log (no output)
+ //log_init(0);
+ //log_levels_set(LOGT_STDOUT, LOG_ANY, LOG_MASK(LOG_DEBUG));
+
+ printf("Parsing file '%s', origin '%s' ...\n",
+ zonefile, origin);
+
+ parser = zparser_create();
+ if (!parser) {
+ fprintf(stderr, "Failed to create parser.\n");
+ //log_close();
+ return 1;
+ }
+
+ int error = zone_read(origin, zonefile, outfile, semantic_checks);
+
+ if (error) {
+ /* FIXME! */
+// if (error < 0) {
+// fprintf(stderr, "Finished with error: %s.\n",
+// error_to_str(knot_zcompile_error_msgs, error));
+// } else {
+// fprintf(stderr, "Finished with %u errors.\n");
+// }
+ } else {
+ printf("Compilation successful.\n");
+ }
+ //log_close();
+
+ return error;
+}
diff --git a/src/zcompile/zlexer.l b/src/zcompile/zlexer.l
new file mode 100644
index 0000000..c6c01fb
--- /dev/null
+++ b/src/zcompile/zlexer.l
@@ -0,0 +1,531 @@
+%{
+/*!
+ * \file zlexer.l
+ *
+ * \author minor modifications by Jan Kadlec <jan.kadlec@nic.cz>,
+ * most of the code by NLnet Labs
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief lexical analyzer for (DNS) zone files.
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#include "common.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <assert.h>
+
+#include "zcompile/zcompile.h"
+#include "libknot/dname.h"
+#include "zcompile/parser-descriptor.h"
+#include "zparser.h"
+
+#define YY_NO_INPUT
+
+/* Utils */
+extern void zc_error(const char *fmt, ...);
+extern void zc_warning(const char *fmt, ...);
+
+void strip_string(char *str)
+{
+ char *start = str;
+ char *end = str + strlen(str) - 1;
+
+ while (isspace(*start))
+ ++start;
+ if (start > end) {
+ /* Completely blank. */
+ str[0] = '\0';
+ } else {
+ while (isspace(*end))
+ --end;
+ *++end = '\0';
+
+ if (str != start)
+ memmove(str, start, end - start + 1);
+ }
+}
+
+int hexdigit_to_int(char ch)
+{
+ switch (ch) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'a': case 'A': return 10;
+ case 'b': case 'B': return 11;
+ case 'c': case 'C': return 12;
+ case 'd': case 'D': return 13;
+ case 'e': case 'E': return 14;
+ case 'f': case 'F': return 15;
+ default:
+ abort();
+ }
+}
+
+extern uint32_t strtottl(const char *nptr, const char **endptr);
+
+#define YY_NO_UNPUT
+#define MAXINCLUDES 10
+
+#define scanner yyscanner
+extern int zp_lex(YYSTYPE *lvalp, void *scanner);
+
+#if 0
+#define LEXOUT(s) printf s /* used ONLY when debugging */
+#else
+#define LEXOUT(s)
+#endif
+
+enum lexer_state {
+ EXPECT_OWNER,
+ PARSING_OWNER,
+ PARSING_TTL_CLASS_TYPE,
+ PARSING_RDATA
+};
+
+static YY_BUFFER_STATE include_stack[MAXINCLUDES];
+static zparser_type zparser_stack[MAXINCLUDES];
+static int include_stack_ptr = 0;
+
+static void pop_parser_state(void *scanner);
+static void push_parser_state(FILE *input, void *scanner);
+static int parse_token(void *scanner, int token, char *in_str,
+ enum lexer_state *lexer_state);
+
+
+/*!< \todo does not compile */
+#ifndef yy_set_bol // compat definition, for flex 2.4.6
+#define yy_set_bol(at_bol) \
+{ \
+ if (!yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \
+}
+#endif
+
+%}
+
+%option nounput
+%option reentrant bison-bridge
+%option prefix = "zp_"
+%option outfile = "lex.yy.c"
+
+SPACE [ \t]
+LETTER [a-zA-Z]
+NEWLINE [\n\r]
+ZONESTR [^ \t\n\r();.\"\$]
+DOLLAR \$
+COMMENT ;
+DOT \.
+BIT [^\]\n]|\\.
+ANY [^\"\n\\]|\\.
+
+%x incl bitlabel quotedstring
+
+%%
+ static int paren_open = 0;
+ static enum lexer_state lexer_state = EXPECT_OWNER;
+
+{SPACE}*{COMMENT}.* /* ignore */
+^{DOLLAR}TTL { lexer_state = PARSING_RDATA; return DOLLAR_TTL; }
+^{DOLLAR}ORIGIN { lexer_state = PARSING_RDATA; return DOLLAR_ORIGIN; }
+
+ /*
+ * Handle $INCLUDE directives. See
+ * http://dinosaur.compilertools.net/flex/flex_12.html#SEC12.
+ */
+^{DOLLAR}INCLUDE {
+ BEGIN(incl);
+}
+<incl>\n |
+<incl><<EOF>> {
+ int error_occurred = parser->error_occurred;
+ BEGIN(INITIAL);
+ zc_error("missing file name in $INCLUDE directive");
+ yy_set_bol(1); /* Set beginning of line, so "^" rules match. */
+ ++parser->line;
+ parser->error_occurred = error_occurred;
+}
+<incl>.+ {
+ char *tmp;
+ /*! \todo pointer to origin. */
+ void *origin = parser->origin;
+ /* domain_type *origin = parser->origin; */
+ int error_occurred = parser->error_occurred;
+
+ BEGIN(INITIAL);
+ if (include_stack_ptr >= MAXINCLUDES ) {
+ zc_error("includes nested too deeply, skipped (>%d)",
+ MAXINCLUDES);
+ } else {
+ FILE *input;
+
+ /* Remove trailing comment. */
+ tmp = strrchr(yytext, ';');
+ if (tmp) {
+ *tmp = '\0';
+ }
+ strip_string(yytext);
+
+ /* Parse origin for include file. */
+ tmp = strrchr(yytext, ' ');
+ if (!tmp) {
+ tmp = strrchr(yytext, '\t');
+ }
+ if (tmp) {
+ /* split the original yytext */
+ *tmp = '\0';
+ strip_string(yytext);
+
+ /*! \todo knot_dname_new_from_wire() (dname.h)
+ * which knot_node to pass as node?
+ */
+ knot_dname_t *dname;
+ dname = knot_dname_new_from_wire((uint8_t*)tmp + 1,
+ strlen(tmp + 1),
+ NULL);
+ if (!dname) {
+ zc_error("incorrect include origin '%s'",
+ tmp + 1);
+ } else {
+ /*! \todo insert to zonedb. */
+ /* origin = domain_table_insert(
+ parser->db->domains, dname); */
+ }
+ }
+
+ if (strlen(yytext) == 0) {
+ zc_error("missing file name in $INCLUDE directive");
+ } else if (!(input = fopen(yytext, "r"))) {
+ char ebuf[256];
+ zc_error("cannot open include file '%s': %s",
+ yytext, strerror_r(errno, ebuf, sizeof(ebuf)));
+ } else {
+ /* Initialize parser for include file. */
+ char *filename = strdup(yytext);
+ push_parser_state(input, scanner); /* Destroys yytext. */
+ parser->filename = filename;
+ parser->line = 1;
+ parser->origin = origin;
+ lexer_state = EXPECT_OWNER;
+ }
+ }
+
+ parser->error_occurred = error_occurred;
+}
+<INITIAL><<EOF>> {
+ yy_set_bol(1); /* Set beginning of line, so "^" rules match. */
+ if (include_stack_ptr == 0) {
+ // from: http://stackoverflow.com/questions/1756275/bison-end-of-file
+ static int once = 0;
+ once++;
+ if (once > 1) {
+ yyterminate();
+ } else {
+ return NL;
+ }
+ } else {
+ fclose(yyin);
+ pop_parser_state(scanner);
+ }
+}
+^{DOLLAR}{LETTER}+ { zc_warning("Unknown directive: %s", yytext); }
+{DOT} {
+ LEXOUT((". "));
+ return parse_token(scanner, '.', yytext, &lexer_state);
+}
+@ {
+ LEXOUT(("@ "));
+ return parse_token(scanner, '@', yytext, &lexer_state);
+}
+\\# {
+ LEXOUT(("\\# "));
+ return parse_token(scanner, URR, yytext, &lexer_state);
+}
+{NEWLINE} {
+ ++parser->line;
+ if (!paren_open) {
+ lexer_state = EXPECT_OWNER;
+ LEXOUT(("NL\n"));
+ return NL;
+ } else {
+ LEXOUT(("SP "));
+ return SP;
+ }
+}
+\( {
+ if (paren_open) {
+ zc_error("nested parentheses");
+ yyterminate();
+ }
+ LEXOUT(("( "));
+ paren_open = 1;
+ return SP;
+}
+\) {
+ if (!paren_open) {
+ zc_error("closing parentheses without opening parentheses");
+ yyterminate();
+ }
+ LEXOUT((") "));
+ paren_open = 0;
+ return SP;
+}
+{SPACE}+ {
+ if (!paren_open && lexer_state == EXPECT_OWNER) {
+ lexer_state = PARSING_TTL_CLASS_TYPE;
+ LEXOUT(("PREV "));
+ return PREV;
+ }
+ if (lexer_state == PARSING_OWNER) {
+ lexer_state = PARSING_TTL_CLASS_TYPE;
+ }
+ LEXOUT(("SP "));
+ return SP;
+}
+
+ /* Bitlabels. Strip leading and ending brackets. */
+\\\[ { BEGIN(bitlabel); }
+<bitlabel><<EOF>> {
+ zc_error("EOF inside bitlabel");
+ BEGIN(INITIAL);
+}
+<bitlabel>{BIT}* { yymore(); }
+<bitlabel>\n { ++parser->line; yymore(); }
+<bitlabel>\] {
+ BEGIN(INITIAL);
+ yytext[yyleng - 1] = '\0';
+ return parse_token(scanner, BITLAB, yytext, &lexer_state);
+}
+
+ /* Quoted strings. Strip leading and ending quotes. */
+\" { BEGIN(quotedstring); LEXOUT(("\" ")); }
+<quotedstring><<EOF>> {
+ zc_error("EOF inside quoted string");
+ BEGIN(INITIAL);
+}
+<quotedstring>{ANY}* { LEXOUT(("STR ")); yymore(); }
+<quotedstring>\n { ++parser->line; yymore(); }
+<quotedstring>\" {
+ LEXOUT(("\" "));
+ BEGIN(INITIAL);
+ yytext[yyleng - 1] = '\0';
+ return parse_token(scanner, STR, yytext, &lexer_state);
+}
+
+({ZONESTR}|\\.|\\\n)+ {
+ /* Any allowed word. */
+ return parse_token(scanner, STR, yytext, &lexer_state);
+}
+. {
+ zc_error("unknown character '%c' (\\%03d) seen - is this a zonefile?",
+ (int) yytext[0], (int) yytext[0]);
+}
+%%
+
+/*
+ * Analyze "word" to see if it matches an RR type, possibly by using
+ * the "TYPExxx" notation. If it matches, the corresponding token is
+ * returned and the TYPE parameter is set to the RR type value.
+ */
+static int
+rrtype_to_token(const char *word, uint16_t *type)
+{
+ uint16_t t = parser_rrtype_from_string(word);
+ if (t != 0) {
+ parser_rrtype_descriptor_t *entry = 0;
+ entry = parser_rrtype_descriptor_by_type(t);
+ *type = t;
+
+ /*! \todo entry should return associated token.
+ see nsd/dns.c */
+ return entry->token;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Remove \DDD constructs from the input. See RFC 1035, section 5.1.
+ */
+static size_t
+zoctet(char *text)
+{
+ /*
+ * s follows the string, p lags behind and rebuilds the new
+ * string
+ */
+ char *s;
+ char *p;
+
+ for (s = p = text; *s; ++s, ++p) {
+ assert(p <= s);
+ if (s[0] != '\\') {
+ /* Ordinary character. */
+ *p = *s;
+ } else if (isdigit((int)s[1]) && isdigit((int)s[2]) && isdigit((int)s[3])) {
+ /* \DDD escape. */
+ int val = (hexdigit_to_int(s[1]) * 100 +
+ hexdigit_to_int(s[2]) * 10 +
+ hexdigit_to_int(s[3]));
+ if (0 <= val && val <= 255) {
+ s += 3;
+ *p = val;
+ } else {
+ zc_warning("text escape \\DDD overflow");
+ *p = *++s;
+ }
+ } else if (s[1] != '\0') {
+ /* \X where X is any character, keep X. */
+ *p = *++s;
+ } else {
+ /* Trailing backslash, ignore it. */
+ zc_warning("trailing backslash ignored");
+ --p;
+ }
+ }
+ *p = '\0';
+ return p - text;
+}
+
+static int parse_token(void *scanner, int token, char *in_str,
+ enum lexer_state *lexer_state)
+{
+ size_t len = 0;
+ char *str = NULL;
+
+ struct yyguts_t *yyg = (struct yyguts_t *)scanner;
+
+ if (*lexer_state == EXPECT_OWNER) {
+ *lexer_state = PARSING_OWNER;
+ } else if (*lexer_state == PARSING_TTL_CLASS_TYPE) {
+ const char *t;
+ int token;
+ uint16_t rrclass;
+
+ /* type */
+ token = rrtype_to_token(in_str, &yylval->type);
+ if (token != 0) {
+ *lexer_state = PARSING_RDATA;
+ LEXOUT(("%d[%s] ", token, in_str));
+ return token;
+ }
+
+ /* class */
+ rrclass = parser_rrclass_from_string(in_str);
+ if (rrclass != 0) {
+ yylval->rclass = rrclass;
+ LEXOUT(("CLASS "));
+ return T_RRCLASS;
+ }
+
+ /* ttl */
+ yylval->ttl = strtottl(in_str, &t);
+ if (*t == '\0') {
+ LEXOUT(("TTL "));
+ return T_TTL;
+ }
+ }
+
+ str = strdup(yytext);
+ if (str == NULL) {
+ /* Out of memory */
+ ERR_ALLOC_FAILED;
+ return NO_MEM;
+ }
+ len = zoctet(str);
+
+ yylval->data.str = str;
+ assert(yylval->data.str != NULL);
+ yylval->data.len = len;
+
+ if (strcmp(yytext, ".") == 0) {
+ free(str);
+ yylval->data.str=".";
+ } else if (strcmp(str, "@") == 0) {
+ free(str);
+ yylval->data.str="@";
+ } else if (strcmp(str, "\\#") == 0) {
+ free(str);
+ yylval->data.str="\\#";
+ }
+
+ LEXOUT(("%d[%s] ", token, in_str));
+ return token;
+}
+
+/*
+ * Saves the file specific variables on the include stack.
+ */
+static void push_parser_state(FILE *input, void *scanner)
+{
+ struct yyguts_t *yyg = (struct yyguts_t *)scanner;
+ zparser_stack[include_stack_ptr].filename = parser->filename;
+ zparser_stack[include_stack_ptr].line = parser->line;
+ zparser_stack[include_stack_ptr].origin = parser->origin;
+ include_stack[include_stack_ptr] = YY_CURRENT_BUFFER;
+ yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE, scanner),
+ scanner);
+ ++include_stack_ptr;
+}
+
+/*
+ * Restores the file specific variables from the include stack.
+ */
+void pop_parser_state(void *scanner)
+{
+ struct yyguts_t *yyg = (struct yyguts_t *)scanner;
+ --include_stack_ptr;
+ parser->filename = zparser_stack[include_stack_ptr].filename;
+ parser->line = zparser_stack[include_stack_ptr].line;
+ parser->origin = zparser_stack[include_stack_ptr].origin;
+ yy_delete_buffer(YY_CURRENT_BUFFER, scanner);
+ yy_switch_to_buffer(include_stack[include_stack_ptr], scanner);
+}
diff --git a/src/zcompile/zparser.y b/src/zcompile/zparser.y
new file mode 100644
index 0000000..6f081e5
--- /dev/null
+++ b/src/zcompile/zparser.y
@@ -0,0 +1,1730 @@
+%{
+/*!
+ * \file zparser.y
+ *
+ * \author modifications by Jan Kadlec <jan.kadlec@nic.cz>,
+ * notable changes: normal allocation, parser is reentrant.
+ * most of the code by NLnet Labs
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * \brief yacc grammar for (DNS) zone files
+ *
+ * \addtogroup zoneparser
+ * @{
+ */
+
+/*
+ * Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//#include "common.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "zcompile/parser-util.h"
+
+#include "libknot/libknot.h"
+#include "zcompile/zcompile.h"
+#include "zcompile/parser-descriptor.h"
+#include "zcompile/zcompile-error.h"
+#include "zparser.h"
+
+/* these need to be global, otherwise they cannot be used inside yacc */
+zparser_type *parser;
+
+#ifdef __cplusplus
+extern "C"
+#endif /* __cplusplus */
+int zp_wrap(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 zp_error(void *scanner, const char *message);
+int zp_lex(YYSTYPE *lvalp, void *scanner);
+
+/* helper functions */
+void zc_error(const char *fmt, ...);
+void zc_warning(const char *fmt, ...);
+void zc_error_prev_line(const char *fmt, ...);
+void zc_warning_prev_line(const char *fmt, ...);
+
+#define NSEC3
+#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 */
+
+knot_dname_t *error_dname; //XXX used to be const
+knot_dname_t *error_domain;
+
+%}
+%union {
+ knot_dname_t *domain;
+ knot_dname_t *dname;
+ struct lex_data data;
+ uint32_t ttl;
+ uint16_t rclass;
+ uint16_t type;
+ uint16_t *unknown;
+}
+
+%pure-parser
+%parse-param {void *scanner}
+%lex-param {void *scanner}
+%name-prefix = "zp_"
+
+/*
+ * 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
+
+/* other tokens */
+%token DOLLAR_TTL DOLLAR_ORIGIN NL SP NO_MEM
+%token <data> STR PREV BITLAB
+%token <ttl> T_TTL
+%token <rclass> 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> concatenated_str_seq str_sp_seq str_dot_seq dotted_str
+%type <data> nxt_seq nsec_more
+%type <unknown> rdata_unknown
+
+%%
+lines: /* empty file */
+ | lines line
+ ;
+
+line: NL
+ | sp NL
+ | NO_MEM {
+ zc_error_prev_line("Parser ran out of memory!");
+ YYABORT;
+ }
+ | PREV NL {} /* Lines containing only whitespace. */
+ | ttl_directive
+ {
+ parser->error_occurred = 0;
+ }
+ | origin_directive
+ {
+ parser->error_occurred = 0;
+ }
+ | rr
+ { /* rr should be fully parsed */
+ if (!parser->error_occurred) {
+ /*!< \todo assign error to error occurred */
+ /*! \todo Make sure this does not crash */
+ if (parser->current_rrset->owner == NULL) {
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ knot_rdata_t *tmp_rdata = knot_rdata_new();
+ if (tmp_rdata == NULL) {
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+
+ if (knot_rdata_set_items(tmp_rdata,
+ parser->temporary_items,
+ parser->rdata_count) != 0) {
+ knot_rdata_free(&tmp_rdata);
+ knot_rrset_deep_free(&(parser->current_rrset), 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone), 1);
+ YYABORT;
+ }
+
+ assert(parser->current_rrset->rdata == NULL);
+ if (knot_rrset_add_rdata(parser->current_rrset, tmp_rdata)
+ != 0) {
+ fprintf(stderr, "Could not add rdata!\n");
+ }
+// tmp_rdata->next = tmp_rdata;
+// parser->current_rrset->rdata = tmp_rdata;
+
+ if (!knot_dname_is_fqdn(parser->current_rrset->owner)) {
+ knot_dname_t *tmp_dname =
+ knot_dname_cat(parser->current_rrset->owner,
+ parser->root_domain);
+ if (tmp_dname == NULL) {
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+// knot_rrset_set_owner(parser->current_rrset, tmp_dname);
+ }
+
+ assert(parser->current_rrset->owner != NULL);
+ knot_dname_retain(parser->current_rrset->owner);
+ int ret = 0;
+ if ((ret = process_rr()) != 0) {
+ char *name =
+ knot_dname_to_str(parser->current_rrset->owner);
+ fprintf(stderr, "Error: could not process RRSet\n"
+ "owner: %s reason: %s\n",
+ name,
+ error_to_str(knot_zcompile_error_msgs, ret));
+ free(name);
+
+ /* If the owner is not already in the table, free it. */
+// if (dnslib_dname_table_find_dname(parser->dname_table,
+// parser->current_rrset->owner) == NULL) {
+// dnslib_dname_free(&parser->
+// current_rrset->owner);
+// } /* This would never happen */
+
+ if (ret == KNOTDZCOMPILE_EBADSOA) {
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ } else {
+ YYABORT;
+ /* Free rdata, it will not be added
+ * and hence cannot be
+ * freed with rest of the zone. */
+/* knot_rdata_deep_free(&tmp_rdata,
+ parser->
+ current_rrset->type,
+ 0); */
+ }
+ }
+ } else {
+ /* Error occured. This could either be lack of memory, or one
+ * of the converting function was not able to convert. */
+ if (parser->error_occurred == KNOTDZCOMPILE_ENOMEM) {
+ /* Ran out of memory in converting functions. */
+ fprintf(stderr, "Parser ran out "
+ "of memory, aborting!\n");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ }
+
+// printf("Current rrset name: %p (%s)\n", parser->current_rrset->owner->name,
+// knot_dname_to_str(parser->current_rrset->owner));
+// getchar();
+
+// knot_dname_release(parser->current_rrset->owner);
+
+ parser->current_rrset->type = 0;
+ parser->rdata_count = 0;
+ parser->current_rrset->rdata = NULL;
+ parser->error_occurred = 0;
+ }
+ | error NL
+ ;
+
+/* needed to cope with ( and ) in arbitary places */
+sp: SP
+ | sp SP
+ ;
+
+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;
+ }
+
+ free($3.str);
+ }
+ ;
+
+
+
+origin_directive: DOLLAR_ORIGIN sp abs_dname trail
+ {
+ knot_node_t *origin_node = knot_node_new($3 ,NULL, 0);
+ if (parser->origin != NULL) {
+// knot_node_free(&parser->origin, 1);
+ }
+ parser->origin = origin_node;
+ }
+ | DOLLAR_ORIGIN sp rel_dname trail
+ {
+ zc_error_prev_line("$ORIGIN directive requires"
+ "absolute domain name");
+ }
+ ;
+
+rr: owner classttl type_and_rdata
+ {
+ /* Save the pointer, it might get freed! */
+ parser->current_rrset->owner = $1;
+// parser->current_rrset->owner = $1;
+// printf("new owner assigned: %p\n", $1);
+ parser->current_rrset->type = $3;
+ }
+ ;
+
+owner: dname sp
+ {
+// char *name = knot_dname_to_str($1);
+// printf("Totally new dname: %p %s\n", $1,
+// name);
+// free(name);
+ if (parser->prev_dname != NULL) {
+ // knot_dname_release(parser->prev_dname);
+ }
+ parser->prev_dname = $1;//knot_dname_deep_copy($1);
+// knot_dname_retain(parser->prev_dname);
+ $$ = $1;
+ }
+ | PREV
+ {
+// printf("Name from prev_dname!: %p %s\n", parser->prev_dname,
+// knot_dname_to_str(parser->prev_dname));
+ knot_dname_retain(parser->prev_dname);
+ $$ = parser->prev_dname;//knot_dname_deep_copy(parser->prev_dname);
+ }
+ ;
+
+classttl: /* empty - fill in the default, def. ttl and IN class */
+ {
+ parser->current_rrset->ttl = parser->default_ttl;
+ parser->current_rrset->rclass = parser->default_class;
+ }
+ | T_RRCLASS sp /* no ttl */
+ {
+ parser->current_rrset->ttl = parser->default_ttl;
+ parser->current_rrset->rclass = $1;
+ }
+ | T_TTL sp /* no class */
+ {
+ parser->current_rrset->ttl = $1;
+ parser->current_rrset->rclass = parser->default_class;
+ }
+ | T_TTL sp T_RRCLASS sp /* the lot */
+ {
+ parser->current_rrset->ttl = $1;
+ parser->current_rrset->rclass = $3;
+ }
+ | T_RRCLASS sp T_TTL sp /* the lot - reversed */
+ {
+ parser->current_rrset->ttl = $3;
+ parser->current_rrset->rclass = $1;
+ }
+ ;
+
+dname: abs_dname
+ | rel_dname
+ {
+ if ($1 == error_dname) {
+ $$ = error_domain;
+ } else if ($1->size + parser->origin->owner->size - 1 >
+ MAXDOMAINLEN) {
+ zc_error("domain name exceeds %d character limit",
+ MAXDOMAINLEN);
+ $$ = error_domain;
+ } else {
+ $$ = knot_dname_cat($1,
+ parser->origin->owner);
+// printf("leak: %s\n", knot_dname_to_str($$));
+// getchar();
+ }
+ }
+ ;
+
+abs_dname: '.'
+ {
+ $$ = parser->root_domain;
+ /* TODO how about concatenation now? */
+ }
+ | '@'
+ {
+ $$ = parser->origin->owner;
+ }
+ | rel_dname '.'
+ {
+ if ($1 != error_dname) {
+ $$ = $1;
+ } else {
+ $$ = error_domain;
+ }
+ }
+ ;
+
+label: STR
+ {
+ if ($1.len > MAXLABELLEN) {
+ zc_error("label exceeds %d character limit", MAXLABELLEN);
+ $$ = error_dname;
+ } else {
+// printf("%s\n", $1.str);
+ $$ = knot_dname_new_from_str($1.str, $1.len, NULL);
+// printf("Creating new (label): %s %p\n", $1.str, $$);
+// printf("new: %p %s\n", $$, $1.str);
+ $$->ref.count = 0;
+ }
+
+ free($1.str);
+
+ }
+ | BITLAB
+ {
+ zc_error("bitlabels are not supported."
+ "RFC2673 has status experimental.");
+ $$ = error_dname;
+ }
+ ;
+
+rel_dname: label
+ | rel_dname '.' label
+ {
+ if ($1 == error_dname || $3 == error_dname) {
+ $$ = error_dname;
+ } else if ($1->size + $3->size - 1 > MAXDOMAINLEN) {
+ zc_error("domain name exceeds %d character limit",
+ MAXDOMAINLEN);
+ $$ = error_dname;
+ } else {
+ $$ = knot_dname_cat($1, $3);
+// knot_dname_release($1); /*!< \todo check! */
+ knot_dname_free(&$3);
+ }
+ }
+ ;
+
+/*
+ * Some dnames in rdata are handled as opaque blobs
+ */
+
+wire_dname: wire_abs_dname
+ | wire_rel_dname
+ ;
+
+wire_abs_dname: '.'
+ {
+ char *result = malloc(2 * sizeof(char));
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ result[0] = 0;
+ result[1] = '\0';
+ $$.str = result;
+ $$.len = 1;
+ }
+ | wire_rel_dname '.'
+ {
+ char *result = malloc($1.len + 2 * sizeof(char));
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy(result, $1.str, $1.len);
+ result[$1.len] = 0;
+ result[$1.len+1] = '\0';
+ $$.str = result;
+ $$.len = $1.len + 1;
+
+ free($1.str);
+;
+ }
+ ;
+
+wire_label: STR
+ {
+ char *result = malloc($1.len + sizeof(char));
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+
+ if ($1.len > MAXLABELLEN)
+ zc_error("label exceeds %d character limit", MAXLABELLEN);
+
+ /* make label anyway */
+ result[0] = $1.len;
+ memcpy(result+1, $1.str, $1.len);
+
+ $$.str = result;
+ $$.len = $1.len + 1;
+
+ free($1.str);
+ }
+ ;
+
+wire_rel_dname: wire_label
+ | wire_rel_dname '.' wire_label
+ {
+ if ($1.len + $3.len - 3 > MAXDOMAINLEN)
+ zc_error("domain name exceeds %d character limit",
+ MAXDOMAINLEN);
+
+ /* make dname anyway */
+ $$.len = $1.len + $3.len;
+ $$.str = malloc($$.len + sizeof(char));
+ if ($$.str == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy($$.str, $1.str, $1.len);
+ memcpy($$.str + $1.len, $3.str, $3.len);
+ $$.str[$$.len] = '\0';
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+
+
+str_seq: STR
+ {
+ zadd_rdata_txt_wireformat(zparser_conv_text($1.str, $1.len), 1);
+
+ free($1.str);
+ }
+ | str_seq sp STR
+ {
+ zadd_rdata_txt_wireformat(zparser_conv_text($3.str, $3.len), 0);
+// zc_warning("multiple TXT entries are currently not supported!");
+
+ free($3.str);
+ }
+ ;
+
+/*
+ * Generate a single string from multiple STR tokens, separated by
+ * spaces or dots.
+ */
+concatenated_str_seq: STR
+ | '.'
+ {
+ $$.len = 1;
+ $$.str = strdup(".");
+ }
+ | concatenated_str_seq sp STR
+ {
+ $$.len = $1.len + $3.len + 1;
+ $$.str = malloc($$.len + 1);
+ if ($$.str == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+
+ memcpy($$.str, $1.str, $1.len);
+ memcpy($$.str + $1.len, " ", 1);
+ memcpy($$.str + $1.len + 1, $3.str, $3.len);
+ $$.str[$$.len] = '\0';
+
+ free($1.str);
+ free($3.str);
+ }
+ | concatenated_str_seq '.' STR
+ {
+ $$.len = $1.len + $3.len + 1;
+ $$.str = malloc($$.len + 1);
+ if ($$.str == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy($$.str, $1.str, $1.len);
+ memcpy($$.str + $1.len, ".", 1);
+ memcpy($$.str + $1.len + 1, $3.str, $3.len);
+
+ free($1.str);
+ free($3.str);
+
+ $$.str[$$.len] = '\0';
+ }
+ ;
+
+/* used to convert a nxt list of types */
+nxt_seq: STR
+ {
+ uint16_t type = knot_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);
+ }
+
+ free($1.str);
+ }
+ | nxt_seq sp STR
+ {
+ uint16_t type = knot_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);
+ }
+
+ free($3.str);
+ }
+ ;
+
+nsec_more: SP nsec_more
+ {
+ }
+ | NL
+ {
+ }
+ | STR nsec_seq
+ {
+ uint16_t type = knot_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);
+ }
+
+ free($1.str);
+ }
+ ;
+
+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 = malloc($1.len + $3.len + 1);
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ fprintf(stderr, "Parser ran out of memory, aborting!\n");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy(result, $1.str, $1.len);
+ memcpy(result + $1.len, $3.str, $3.len);
+ $$.str = result;
+ $$.len = $1.len + $3.len;
+ $$.str[$$.len] = '\0';
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+/*
+ * Sequence of STR tokens separated by dots. The dots are not
+ * preserved during concatenation.
+ */
+str_dot_seq: STR
+ | str_dot_seq '.' STR
+ {
+ char *result = malloc($1.len + $3.len + 1);
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ fprintf(stderr, "Parser ran out of memory, aborting!\n");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy(result, $1.str, $1.len);
+ memcpy(result + $1.len, $3.str, $3.len);
+ $$.str = result;
+ $$.len = $1.len + $3.len;
+ $$.str[$$.len] = '\0';
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+/*
+ * A string that can contain dots.
+ */
+dotted_str: STR
+ | '.'
+ {
+ $$.str = ".";
+ $$.len = 1;
+ }
+ | dotted_str '.'
+ {
+ char *result = malloc($1.len + 2);
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ fprintf(stderr, "Parser ran out of memory, aborting!\n");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy(result, $1.str, $1.len);
+ result[$1.len] = '.';
+ $$.str = result;
+ $$.len = $1.len + 1;
+ $$.str[$$.len] = '\0';
+
+ free($1.str);
+ }
+ | dotted_str '.' STR
+ {
+ char *result = malloc($1.len + $3.len + 2);
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ fprintf(stderr, "Parser ran out of memory, aborting!\n");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ 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';
+
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+/* 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_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); }
+ | 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_UTYPE sp rdata_unknown { $$ = $1; parse_unknown_rdata($1, $3); }
+
+ | STR error NL
+ {
+ zc_error_prev_line("unrecognized RR type '%s'", $1.str);
+ free($1.str);
+ }
+ | NO_MEM
+ {
+ zc_error_prev_line("parser ran out of memory!");
+ YYABORT;
+ }
+ ;
+
+/*
+ *
+ * below are all the definition for all the different rdata
+ *
+ */
+
+rdata_a: dotted_str trail
+ {
+ zadd_rdata_wireformat(zparser_conv_a($1.str));
+ free($1.str);
+ }
+ ;
+
+rdata_domain_name: dname trail
+ {
+ /* convert a single dname record */
+ if ($1 != NULL) {
+ if (!knot_dname_is_fqdn($1)) {
+ knot_dname_cat($1, parser->root_domain);
+// parser->current_rrset->owner =
+// knot_dname_cat($1, parser->root_domain);
+ }
+ }
+ zadd_rdata_domain($1);
+ }
+ ;
+
+rdata_soa: dname sp dname sp STR sp STR sp STR sp STR sp STR trail
+ {
+ /* convert the soa data */
+ if (!knot_dname_is_fqdn($1)) {
+ knot_dname_cat($1, parser->root_domain);
+// parser->current_rrset->owner =
+// knot_dname_cat($1, parser->root_domain);
+
+ }
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+// parser->current_rrset->owner =
+// knot_dname_cat($3, parser->root_domain);
+
+ }
+ zadd_rdata_domain($1); /* prim. ns */
+ zadd_rdata_domain($3); /* email */
+ zadd_rdata_wireformat(zparser_conv_serial($5.str)); /* serial */
+ zadd_rdata_wireformat(zparser_conv_period($7.str)); /* refresh */
+ zadd_rdata_wireformat(zparser_conv_period($9.str)); /* retry */
+ zadd_rdata_wireformat(zparser_conv_period($11.str)); /* expire */
+ zadd_rdata_wireformat(zparser_conv_period($13.str)); /* minimum */
+
+ free($5.str);
+ free($7.str);
+ free($9.str);
+ free($11.str);
+ free($13.str);
+ }
+ ;
+
+rdata_wks: dotted_str sp STR sp concatenated_str_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_a($1.str)); /* address */
+ zadd_rdata_wireformat(zparser_conv_services($3.str, $5.str));
+ /* protocol and services */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ }
+ ;
+
+rdata_hinfo: STR sp STR trail
+ {
+ zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len)); /* CPU */
+ zadd_rdata_wireformat(zparser_conv_text($3.str, $3.len)); /* OS*/
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+rdata_minfo: dname sp dname trail
+ {
+ if (!knot_dname_is_fqdn($1)) {
+
+ knot_dname_cat($1, parser->root_domain);
+
+ }
+ if (!knot_dname_is_fqdn($3)) {
+
+ knot_dname_cat($3, parser->root_domain);
+
+ }
+
+ /* convert a single dname record */
+ zadd_rdata_domain($1);
+ zadd_rdata_domain($3);
+ }
+ ;
+
+rdata_mx: STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* priority */
+ zadd_rdata_domain($3); /* MX host */
+
+ free($1.str);
+ }
+ ;
+
+rdata_txt: str_seq trail
+ {
+ ; //zadd_rdata_txt_clean_wireformat();
+ }
+ ;
+
+/* RFC 1183 */
+rdata_rp: dname sp dname trail
+ {
+ if (!knot_dname_is_fqdn($1)) {
+ knot_dname_cat($1, parser->root_domain);
+ }
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+
+ zadd_rdata_domain($1); /* mbox d-name */
+ zadd_rdata_domain($3); /* txt d-name */
+ }
+ ;
+
+/* RFC 1183 */
+rdata_afsdb: STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* subtype */
+ zadd_rdata_domain($3); /* domain name */
+
+ free($1.str);
+ }
+ ;
+
+/* RFC 1183 */
+rdata_x25: STR trail
+ {
+ zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len));
+ /* X.25 address. */
+
+ free($1.str);
+ }
+ ;
+
+/* RFC 1183 */
+rdata_isdn: STR trail
+ {
+ zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len));
+ /* address */
+
+ free($1.str);
+ }
+ | STR sp STR trail
+ {
+ zadd_rdata_wireformat(zparser_conv_text($1.str, $1.len));
+ /* address */
+ zadd_rdata_wireformat(zparser_conv_text($3.str, $3.len));
+ /* sub-address */
+
+ free($1.str);
+ free($3.str);
+ }
+ ;
+
+/* RFC 1183 */
+rdata_rt: STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* preference */
+ zadd_rdata_domain($3); /* intermediate host */
+
+ free($1.str);
+ }
+ ;
+
+/* 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($1.str + 2,
+ $1.len - 2));
+ /* NSAP */
+ }
+
+ free($1.str);
+ }
+ ;
+
+/* RFC 2163 */
+rdata_px: STR sp dname sp dname trail
+ {
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+ if (!knot_dname_is_fqdn($5)) {
+ knot_dname_cat($5, parser->root_domain);
+ }
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* preference */
+ zadd_rdata_domain($3); /* MAP822 */
+ zadd_rdata_domain($5); /* MAPX400 */
+
+ free($1.str);
+ }
+ ;
+
+rdata_aaaa: dotted_str trail
+ {
+ zadd_rdata_wireformat(zparser_conv_aaaa($1.str));
+ /* IPv6 address */
+
+ free($1.str);
+ }
+ ;
+
+rdata_loc: concatenated_str_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_loc($1.str)); /* Location */
+
+ free($1.str);
+ }
+ ;
+
+rdata_nxt: dname sp nxt_seq trail
+ {
+ if (!knot_dname_is_fqdn($1)) {
+ knot_dname_cat($1, parser->root_domain);
+ }
+ zadd_rdata_domain($1); /* nxt name */
+ zadd_rdata_wireformat(zparser_conv_nxt(nxtbits)); /* nxt bitlist */
+ memset(nxtbits, 0, sizeof(nxtbits));
+ }
+ ;
+
+rdata_srv: STR sp STR sp STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($7)) {
+ knot_dname_cat($7, parser->root_domain);
+
+ }
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* prio */
+ zadd_rdata_wireformat(zparser_conv_short($3.str)); /* weight */
+ zadd_rdata_wireformat(zparser_conv_short($5.str)); /* port */
+ zadd_rdata_domain($7); /* target name */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ }
+ ;
+
+/* RFC 2915 */
+rdata_naptr: STR sp STR sp STR sp STR sp STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($11)) {
+ knot_dname_cat($11, parser->root_domain);
+
+ }
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* order */
+ zadd_rdata_wireformat(zparser_conv_short($3.str)); /* preference */
+ zadd_rdata_wireformat(zparser_conv_text($5.str, $5.len));
+ /* flags */
+ zadd_rdata_wireformat(zparser_conv_text($7.str, $7.len));
+ /* service */
+ zadd_rdata_wireformat(zparser_conv_text($9.str, $9.len));
+ /* regexp */
+ zadd_rdata_domain($11); /* target name */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ free($9.str);
+ }
+ ;
+
+/* RFC 2230 */
+rdata_kx: STR sp dname trail
+ {
+ if (!knot_dname_is_fqdn($3)) {
+ knot_dname_cat($3, parser->root_domain);
+ }
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* preference */
+ zadd_rdata_domain($3); /* exchanger */
+
+ free($1.str);
+ }
+ ;
+
+/* RFC 2538 */
+rdata_cert: STR sp STR sp STR sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_certificate_type($1.str));
+ /* type */
+ zadd_rdata_wireformat(zparser_conv_short($3.str)); /* key tag */
+ zadd_rdata_wireformat(zparser_conv_algorithm($5.str));
+ /* algorithm */
+ zadd_rdata_wireformat(zparser_conv_b64($7.str));
+ /* certificate or CRL */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ }
+ ;
+
+/* RFC 3123 */
+rdata_apl: rdata_apl_seq trail
+ ;
+
+rdata_apl_seq: dotted_str
+ {
+ zadd_rdata_wireformat(zparser_conv_apl_rdata($1.str));
+
+ free($1.str);
+ }
+ | rdata_apl_seq sp dotted_str
+ {
+ zadd_rdata_wireformat(zparser_conv_apl_rdata($3.str));
+
+ free($3.str);
+ }
+ ;
+
+rdata_ds: STR sp STR sp STR sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* keytag */
+ zadd_rdata_wireformat(zparser_conv_algorithm($3.str)); /* alg */
+ zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* type */
+ zadd_rdata_wireformat(zparser_conv_hex($7.str, $7.len)); /* hash */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ }
+ ;
+
+rdata_dlv: STR sp STR sp STR sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* keytag */
+ zadd_rdata_wireformat(zparser_conv_algorithm($3.str)); /* alg */
+ zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* type */
+ zadd_rdata_wireformat(zparser_conv_hex($7.str, $7.len)); /* hash */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ }
+ ;
+
+rdata_sshfp: STR sp STR sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_byte($1.str)); /* alg */
+ zadd_rdata_wireformat(zparser_conv_byte($3.str)); /* fp type */
+ zadd_rdata_wireformat(zparser_conv_hex($5.str, $5.len)); /* hash */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ }
+ ;
+
+rdata_dhcid: str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_b64($1.str)); /* data blob */
+
+ free($1.str);
+ }
+ ;
+
+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($1.str));
+ /* rr covered */
+ zadd_rdata_wireformat(zparser_conv_algorithm($3.str)); /* alg */
+ zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* # labels */
+ zadd_rdata_wireformat(zparser_conv_period($7.str));
+ /* # orig TTL */
+ zadd_rdata_wireformat(zparser_conv_time($9.str)); /* sig exp */
+ zadd_rdata_wireformat(zparser_conv_time($11.str)); /* sig inc */
+ zadd_rdata_wireformat(zparser_conv_short($13.str)); /* key id */
+/* zadd_rdata_wireformat(zparser_conv_dns_name((const uint8_t*)
+ $15.str,
+ $15.len));*/
+ knot_dname_t *dname =
+ knot_dname_new_from_wire((uint8_t *)$15.str, $15.len, NULL);
+ if (dname == NULL) {
+ parser->error_occurred = KNOTDZCOMPILE_ENOMEM;
+ } else {
+ knot_dname_cat(dname, parser->root_domain);
+ }
+
+ zadd_rdata_domain(dname);
+ /* sig name */
+ zadd_rdata_wireformat(zparser_conv_b64($17.str)); /* sig data */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ free($9.str);
+ free($11.str);
+ free($13.str);
+ free($15.str);
+ free($17.str);
+ }
+ ;
+
+rdata_nsec: wire_dname nsec_seq
+ {
+/* zadd_rdata_wireformat(zparser_conv_dns_name((const uint8_t*)
+ $1.str,
+ $1.len));*/
+
+ knot_dname_t *dname =
+ knot_dname_new_from_wire((uint8_t *)$1.str, $1.len, NULL);
+
+ free($1.str);
+
+ knot_dname_cat(dname, parser->root_domain);
+
+ zadd_rdata_domain(dname);
+ /* nsec name */
+ zadd_rdata_wireformat(zparser_conv_nsec(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);
+
+/* knot_dname_t *dname =
+ knot_dname_new_from_str($9.str, $9.len, NULL);
+
+ zadd_rdata_domain(dname); */
+
+ zadd_rdata_wireformat(zparser_conv_b32($9.str));
+ /* next hashed name */
+ zadd_rdata_wireformat(zparser_conv_nsec(nsecbits));
+ /* nsec bitlist */
+ memset(nsecbits, 0, sizeof(nsecbits));
+ nsec_highest_rcode = 0;
+#else
+ zc_error_prev_line("nsec3 not supported");
+#endif /* NSEC3 */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ free($9.str);
+ }
+ ;
+
+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 */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ }
+ ;
+
+rdata_dnskey: STR sp STR sp STR sp str_sp_seq trail
+ {
+ zadd_rdata_wireformat(zparser_conv_short($1.str)); /* flags */
+ zadd_rdata_wireformat(zparser_conv_byte($3.str)); /* proto */
+ zadd_rdata_wireformat(zparser_conv_algorithm($5.str)); /* alg */
+ zadd_rdata_wireformat(zparser_conv_b64($7.str)); /* hash */
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+ }
+ ;
+
+rdata_ipsec_base: STR sp STR sp STR sp dotted_str
+ {
+ knot_dname_t* name = 0;
+ zadd_rdata_wireformat(zparser_conv_byte($1.str)); /* precedence */
+ zadd_rdata_wireformat(zparser_conv_byte($3.str));
+ /* gateway type */
+ zadd_rdata_wireformat(zparser_conv_byte($5.str)); /* algorithm */
+ switch(atoi($3.str)) {
+ case IPSECKEY_NOGATEWAY:
+ zadd_rdata_wireformat(alloc_rdata_init("", 0));
+ break;
+ case IPSECKEY_IP4:
+ zadd_rdata_wireformat(zparser_conv_a($7.str));
+ break;
+ case IPSECKEY_IP6:
+ zadd_rdata_wireformat(zparser_conv_aaaa($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");
+ name = knot_dname_new_from_wire((uint8_t*)$7.str + 1,
+ strlen($7.str + 1),
+ NULL);
+ if(!name) {
+ zc_error_prev_line("IPSECKEY bad gateway"
+ "dname %s", $7.str);
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ if($7.str[strlen($7.str)-1] != '.') {
+ knot_dname_t* tmpd =
+ knot_dname_new_from_wire(name->name,
+ name->size,
+ NULL);
+ if (tmpd == NULL) {
+ zc_error_prev_line("Could not create dname!");
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ name = knot_dname_cat(tmpd,
+ knot_node_parent(parser->origin, 0)->owner);
+ }
+
+ free($1.str);
+ free($3.str);
+ free($5.str);
+ free($7.str);
+
+ uint8_t* dncpy = malloc(sizeof(uint8_t) * name->size);
+ if (dncpy == NULL) {
+ ERR_ALLOC_FAILED;
+ knot_rrset_deep_free(&(parser->current_rrset),
+ 0, 0, 0);
+ knot_zone_deep_free(&(parser->current_zone),
+ 1);
+ YYABORT;
+ }
+ memcpy(dncpy, name->name, name->size);
+ zadd_rdata_wireformat((uint16_t *)dncpy);
+ //knot_dname_free(&name);
+ 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($3.str)); /* public key */
+
+ free($3.str);
+ }
+ | rdata_ipsec_base trail
+ ;
+
+rdata_unknown: URR sp STR sp str_sp_seq trail
+ {
+ /* $2 is the number of octects, currently ignored */
+ $$ = zparser_conv_hex($5.str, $5.len);
+ free($5.str);
+ free($3.str);
+ }
+ | URR sp STR trail
+ {
+ $$ = zparser_conv_hex("", 0);
+ free($3.str);
+ }
+ | URR error NL
+ {
+ $$ = zparser_conv_hex("", 0);
+ }
+ ;
+%%
+
+int zp_wrap(void)
+{
+ return 1;
+}
+
+/*
+ * Create the parser.
+ */
+zparser_type *zparser_create()
+{
+ zparser_type *result = malloc(sizeof(zparser_type));
+ if (result == NULL) {
+ ERR_ALLOC_FAILED;
+ return NULL;
+ }
+
+ result->temporary_items = malloc(MAXRDATALEN *
+ sizeof(knot_rdata_item_t));
+ if (result->temporary_items == NULL) {
+ ERR_ALLOC_FAILED;
+ free(result);
+ return NULL;
+ }
+
+ result->current_rrset = knot_rrset_new(NULL, 0, 0, 0);
+ if (result->current_rrset == NULL) {
+ ERR_ALLOC_FAILED;
+ free(result->temporary_items);
+ free(result);
+ return NULL;
+ }
+
+ result->root_domain = knot_dname_new_from_str(".", 1, NULL);
+// printf("THE NEW ROOT: %p\n", result->root_domain);
+ if (result->root_domain == NULL) {
+ ERR_ALLOC_FAILED;
+ free(result->temporary_items);
+ free(result->current_rrset);
+ free(result);
+ return NULL;
+ }
+
+ return result;
+}
+
+/*
+ * Initialize the parser for a new zone file.
+ */
+void
+zparser_init(const char *filename, uint32_t ttl, uint16_t rclass,
+ knot_node_t *origin, knot_dname_t *origin_from_config)
+{
+ memset(nxtbits, 0, sizeof(nxtbits));
+ memset(nsecbits, 0, sizeof(nsecbits));
+ nsec_highest_rcode = 0;
+
+ parser->current_zone = NULL;
+ parser->prev_dname = NULL;
+
+ parser->default_ttl = ttl;
+ parser->default_class = rclass;
+
+ parser->origin = origin;
+ parser->prev_dname = NULL;//parser->origin->owner;
+
+ parser->default_apex = origin;
+ parser->error_occurred = 0;
+ parser->errors = 0;
+ parser->line = 1;
+ parser->filename = filename;
+ parser->rdata_count = 0;
+ parser->origin_from_config = origin_from_config;
+
+ parser->last_node = origin;
+// parser->root_domain = NULL;
+
+ /* Create zone */
+ parser->current_zone = knot_zone_new(origin, 0, 1);
+
+ parser->node_rrsigs = NULL;
+ parser->rrsig_orphans = NULL;
+ parser->rrsig_orphan_count = 0;
+
+ parser->current_rrset->rclass = parser->default_class;
+ parser->current_rrset->rdata = NULL;
+}
+
+
+void zparser_free()
+{
+// knot_dname_release(parser->root_domain);
+// knot_dname_release(parser->prev_dname);
+ knot_dname_free(&parser->origin_from_config);
+ free(parser->temporary_items);
+ if (parser->current_rrset != NULL) {
+ free(parser->current_rrset);
+ }
+ free(parser);
+}
+
+void
+yyerror(void *scanner, const char *message)
+{
+ zc_error("%s", message);
+}
+
+static void
+error_va_list(unsigned line, const char *fmt, va_list args)
+{
+ if (parser->filename) {
+ fprintf(stderr, "%s:%u: ", parser->filename, line);
+ }
+ fprintf(stderr, "error: ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+
+ ++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) {
+ fprintf(stderr, "%s:%u: ", parser->filename, line);
+ }
+ fprintf(stderr, "warning: ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+}
+
+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(hashalgo_str));
+ zadd_rdata_wireformat(zparser_conv_byte(flag_str));
+ zadd_rdata_wireformat(zparser_conv_short(iter_str));
+
+ /* salt */
+ if(strcmp(salt_str, "-") != 0)
+ zadd_rdata_wireformat(zparser_conv_hex_length(salt_str,
+ salt_len));
+ else
+ zadd_rdata_wireformat(alloc_rdata_init("", 1));
+
+}
+#endif /* NSEC3 */