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/parser-util.c | |
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/parser-util.c')
-rw-r--r-- | src/zcompile/parser-util.c | 2435 |
1 files changed, 2435 insertions, 0 deletions
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)); +} + |