diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-11-02 22:44:12 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-11-02 22:44:12 +0100 |
commit | c8d5977bb546dae9ed59d81556639c49badd8121 (patch) | |
tree | 4c86750db26c1c3502b60f2cd78ca9611cfa01d6 /src/zcompile | |
download | knot-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/LICENSE | 30 | ||||
-rw-r--r-- | src/zcompile/parser-descriptor.c | 535 | ||||
-rw-r--r-- | src/zcompile/parser-descriptor.h | 278 | ||||
-rw-r--r-- | src/zcompile/parser-util.c | 2435 | ||||
-rw-r--r-- | src/zcompile/parser-util.h | 357 | ||||
-rw-r--r-- | src/zcompile/tests/unittests_zp_main.c | 62 | ||||
-rw-r--r-- | src/zcompile/tests/zcompile_tests.c | 425 | ||||
-rw-r--r-- | src/zcompile/zcompile-error.c | 52 | ||||
-rw-r--r-- | src/zcompile/zcompile-error.h | 90 | ||||
-rw-r--r-- | src/zcompile/zcompile.c | 639 | ||||
-rw-r--r-- | src/zcompile/zcompile.h | 207 | ||||
-rw-r--r-- | src/zcompile/zcompile_main.c | 116 | ||||
-rw-r--r-- | src/zcompile/zlexer.l | 531 | ||||
-rw-r--r-- | src/zcompile/zparser.y | 1730 |
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, °, "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 */ |