xref: /openbsd-src/usr.sbin/nsd/zonec.c (revision 3efee2e132f9af6db74577d714f3304be2b3af74)
162ac0c33Sjakob /*
262ac0c33Sjakob  * zonec.c -- zone compiler.
362ac0c33Sjakob  *
4dd5b221eSsthen  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
562ac0c33Sjakob  *
662ac0c33Sjakob  * See LICENSE for the license.
762ac0c33Sjakob  *
862ac0c33Sjakob  */
962ac0c33Sjakob 
109c620270Ssthen #include "config.h"
1162ac0c33Sjakob 
1262ac0c33Sjakob #include <assert.h>
1362ac0c33Sjakob #include <fcntl.h>
1462ac0c33Sjakob #include <ctype.h>
1562ac0c33Sjakob #include <errno.h>
1662ac0c33Sjakob #include <limits.h>
1762ac0c33Sjakob #include <stdio.h>
1862ac0c33Sjakob #include <string.h>
1962ac0c33Sjakob #ifdef HAVE_STRINGS_H
2062ac0c33Sjakob #include <strings.h>
2162ac0c33Sjakob #endif
2262ac0c33Sjakob #include <unistd.h>
2362ac0c33Sjakob #include <stdlib.h>
2462ac0c33Sjakob #include <time.h>
25dd5b221eSsthen #ifdef HAVE_SYS_STAT_H
26dd5b221eSsthen #include <sys/stat.h>
27dd5b221eSsthen #endif
2862ac0c33Sjakob 
2962ac0c33Sjakob #include <netinet/in.h>
3062ac0c33Sjakob 
3162ac0c33Sjakob #ifdef HAVE_NETDB_H
3262ac0c33Sjakob #include <netdb.h>
3362ac0c33Sjakob #endif
3462ac0c33Sjakob 
3562ac0c33Sjakob #include "zonec.h"
3662ac0c33Sjakob 
3762ac0c33Sjakob #include "dname.h"
3862ac0c33Sjakob #include "dns.h"
3962ac0c33Sjakob #include "namedb.h"
4062ac0c33Sjakob #include "rdata.h"
4162ac0c33Sjakob #include "region-allocator.h"
4262ac0c33Sjakob #include "util.h"
43dd5b221eSsthen #include "zparser.h"
4462ac0c33Sjakob #include "options.h"
4562ac0c33Sjakob #include "nsec3.h"
4662ac0c33Sjakob 
4775343be4Ssthen #define ILNP_MAXDIGITS 4
4875343be4Ssthen #define ILNP_NUMGROUPS 4
49063644e9Sflorian #define SVCB_MAX_COMMA_SEPARATED_VALUES 1000
50063644e9Sflorian 
5175343be4Ssthen 
5262ac0c33Sjakob const dname_type *error_dname;
5362ac0c33Sjakob domain_type *error_domain;
5462ac0c33Sjakob 
55dd5b221eSsthen static time_t startzonec = 0;
5662ac0c33Sjakob static long int totalrrs = 0;
5762ac0c33Sjakob 
5862ac0c33Sjakob extern uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE];
5962ac0c33Sjakob extern uint16_t nsec_highest_rcode;
6062ac0c33Sjakob 
6162ac0c33Sjakob 
6262ac0c33Sjakob /*
6362ac0c33Sjakob  * Allocate SIZE+sizeof(uint16_t) bytes and store SIZE in the first
6462ac0c33Sjakob  * element.  Return a pointer to the allocation.
6562ac0c33Sjakob  */
6662ac0c33Sjakob static uint16_t *
alloc_rdata(region_type * region,size_t size)6762ac0c33Sjakob alloc_rdata(region_type *region, size_t size)
6862ac0c33Sjakob {
6962ac0c33Sjakob 	uint16_t *result = region_alloc(region, sizeof(uint16_t) + size);
7062ac0c33Sjakob 	*result = size;
7162ac0c33Sjakob 	return result;
7262ac0c33Sjakob }
7362ac0c33Sjakob 
7462ac0c33Sjakob uint16_t *
alloc_rdata_init(region_type * region,const void * data,size_t size)7562ac0c33Sjakob alloc_rdata_init(region_type *region, const void *data, size_t size)
7662ac0c33Sjakob {
7762ac0c33Sjakob 	uint16_t *result = region_alloc(region, sizeof(uint16_t) + size);
7862ac0c33Sjakob 	*result = size;
7962ac0c33Sjakob 	memcpy(result + 1, data, size);
8062ac0c33Sjakob 	return result;
8162ac0c33Sjakob }
8262ac0c33Sjakob 
8362ac0c33Sjakob /*
8462ac0c33Sjakob  * These are parser function for generic zone file stuff.
8562ac0c33Sjakob  */
8662ac0c33Sjakob uint16_t *
zparser_conv_hex(region_type * region,const char * hex,size_t len)8762ac0c33Sjakob zparser_conv_hex(region_type *region, const char *hex, size_t len)
8862ac0c33Sjakob {
8962ac0c33Sjakob 	/* convert a hex value to wireformat */
9062ac0c33Sjakob 	uint16_t *r = NULL;
9162ac0c33Sjakob 	uint8_t *t;
9262ac0c33Sjakob 	int i;
9362ac0c33Sjakob 
94fb800cb5Sflorian 	if(len == 1 && hex[0] == '0') {
95fb800cb5Sflorian 		/* single 0 represents empty buffer */
96fb800cb5Sflorian 		return alloc_rdata(region, 0);
97fb800cb5Sflorian 	}
9862ac0c33Sjakob 	if (len % 2 != 0) {
9962ac0c33Sjakob 		zc_error_prev_line("number of hex digits must be a multiple of 2");
10062ac0c33Sjakob 	} else if (len > MAX_RDLENGTH * 2) {
10162ac0c33Sjakob 		zc_error_prev_line("hex data exceeds maximum rdata length (%d)",
10262ac0c33Sjakob 				   MAX_RDLENGTH);
10362ac0c33Sjakob 	} else {
10462ac0c33Sjakob 		/* the length part */
10562ac0c33Sjakob 		r = alloc_rdata(region, len/2);
10662ac0c33Sjakob 		t = (uint8_t *)(r + 1);
10762ac0c33Sjakob 
10862ac0c33Sjakob 		/* Now process octet by octet... */
10962ac0c33Sjakob 		while (*hex) {
11062ac0c33Sjakob 			*t = 0;
11162ac0c33Sjakob 			for (i = 16; i >= 1; i -= 15) {
11282cafdebSmillert 				if (isxdigit((unsigned char)*hex)) {
11362ac0c33Sjakob 					*t += hexdigit_to_int(*hex) * i;
11462ac0c33Sjakob 				} else {
11562ac0c33Sjakob 					zc_error_prev_line(
11662ac0c33Sjakob 						"illegal hex character '%c'",
117c1404d4fSbrad 						(int) *hex);
11862ac0c33Sjakob 					return NULL;
11962ac0c33Sjakob 				}
12062ac0c33Sjakob 				++hex;
12162ac0c33Sjakob 			}
12262ac0c33Sjakob 			++t;
12362ac0c33Sjakob 		}
12462ac0c33Sjakob 	}
12562ac0c33Sjakob 	return r;
12662ac0c33Sjakob }
12762ac0c33Sjakob 
12862ac0c33Sjakob /* convert hex, precede by a 1-byte length */
12962ac0c33Sjakob uint16_t *
zparser_conv_hex_length(region_type * region,const char * hex,size_t len)13062ac0c33Sjakob zparser_conv_hex_length(region_type *region, const char *hex, size_t len)
13162ac0c33Sjakob {
13262ac0c33Sjakob 	uint16_t *r = NULL;
13362ac0c33Sjakob 	uint8_t *t;
13462ac0c33Sjakob 	int i;
13562ac0c33Sjakob 	if (len % 2 != 0) {
13662ac0c33Sjakob 		zc_error_prev_line("number of hex digits must be a multiple of 2");
13762ac0c33Sjakob 	} else if (len > 255 * 2) {
13862ac0c33Sjakob 		zc_error_prev_line("hex data exceeds 255 bytes");
13962ac0c33Sjakob 	} else {
14062ac0c33Sjakob 		uint8_t *l;
14162ac0c33Sjakob 
14262ac0c33Sjakob 		/* the length part */
14362ac0c33Sjakob 		r = alloc_rdata(region, len/2+1);
14462ac0c33Sjakob 		t = (uint8_t *)(r + 1);
14562ac0c33Sjakob 
14662ac0c33Sjakob 		l = t++;
14762ac0c33Sjakob 		*l = '\0';
14862ac0c33Sjakob 
14962ac0c33Sjakob 		/* Now process octet by octet... */
15062ac0c33Sjakob 		while (*hex) {
15162ac0c33Sjakob 			*t = 0;
15262ac0c33Sjakob 			for (i = 16; i >= 1; i -= 15) {
15382cafdebSmillert 				if (isxdigit((unsigned char)*hex)) {
15462ac0c33Sjakob 					*t += hexdigit_to_int(*hex) * i;
15562ac0c33Sjakob 				} else {
15662ac0c33Sjakob 					zc_error_prev_line(
15762ac0c33Sjakob 						"illegal hex character '%c'",
158c1404d4fSbrad 						(int) *hex);
15962ac0c33Sjakob 					return NULL;
16062ac0c33Sjakob 				}
16162ac0c33Sjakob 				++hex;
16262ac0c33Sjakob 			}
16362ac0c33Sjakob 			++t;
16462ac0c33Sjakob 			++*l;
16562ac0c33Sjakob 		}
16662ac0c33Sjakob 	}
16762ac0c33Sjakob 	return r;
16862ac0c33Sjakob }
16962ac0c33Sjakob 
17062ac0c33Sjakob uint16_t *
zparser_conv_time(region_type * region,const char * time)17162ac0c33Sjakob zparser_conv_time(region_type *region, const char *time)
17262ac0c33Sjakob {
17362ac0c33Sjakob 	/* convert a time YYHM to wireformat */
17462ac0c33Sjakob 	uint16_t *r = NULL;
17562ac0c33Sjakob 	struct tm tm;
17662ac0c33Sjakob 
17762ac0c33Sjakob 	/* Try to scan the time... */
17862ac0c33Sjakob 	if (!strptime(time, "%Y%m%d%H%M%S", &tm)) {
17962ac0c33Sjakob 		zc_error_prev_line("date and time is expected");
18062ac0c33Sjakob 	} else {
18162ac0c33Sjakob 		uint32_t l = htonl(mktime_from_utc(&tm));
18262ac0c33Sjakob 		r = alloc_rdata_init(region, &l, sizeof(l));
18362ac0c33Sjakob 	}
18462ac0c33Sjakob 	return r;
18562ac0c33Sjakob }
18662ac0c33Sjakob 
18762ac0c33Sjakob uint16_t *
zparser_conv_services(region_type * region,const char * protostr,char * servicestr)18862ac0c33Sjakob zparser_conv_services(region_type *region, const char *protostr,
18962ac0c33Sjakob 		      char *servicestr)
19062ac0c33Sjakob {
19162ac0c33Sjakob 	/*
19262ac0c33Sjakob 	 * Convert a protocol and a list of service port numbers
19362ac0c33Sjakob 	 * (separated by spaces) in the rdata to wireformat
19462ac0c33Sjakob 	 */
19562ac0c33Sjakob 	uint16_t *r = NULL;
19662ac0c33Sjakob 	uint8_t *p;
19762ac0c33Sjakob 	uint8_t bitmap[65536/8];
19862ac0c33Sjakob 	char sep[] = " ";
19962ac0c33Sjakob 	char *word;
20062ac0c33Sjakob 	int max_port = -8;
20162ac0c33Sjakob 	/* convert a protocol in the rdata to wireformat */
20262ac0c33Sjakob 	struct protoent *proto;
20362ac0c33Sjakob 
20462ac0c33Sjakob 	memset(bitmap, 0, sizeof(bitmap));
20562ac0c33Sjakob 
20662ac0c33Sjakob 	proto = getprotobyname(protostr);
20762ac0c33Sjakob 	if (!proto) {
20862ac0c33Sjakob 		proto = getprotobynumber(atoi(protostr));
20962ac0c33Sjakob 	}
21062ac0c33Sjakob 	if (!proto) {
21162ac0c33Sjakob 		zc_error_prev_line("unknown protocol '%s'", protostr);
21262ac0c33Sjakob 		return NULL;
21362ac0c33Sjakob 	}
21462ac0c33Sjakob 
21562ac0c33Sjakob 	for (word = strtok(servicestr, sep); word; word = strtok(NULL, sep)) {
21662ac0c33Sjakob 		struct servent *service;
21762ac0c33Sjakob 		int port;
21862ac0c33Sjakob 
21962ac0c33Sjakob 		service = getservbyname(word, proto->p_name);
22062ac0c33Sjakob 		if (service) {
22162ac0c33Sjakob 			/* Note: ntohs not ntohl!  Strange but true.  */
22262ac0c33Sjakob 			port = ntohs((uint16_t) service->s_port);
22362ac0c33Sjakob 		} else {
22462ac0c33Sjakob 			char *end;
22562ac0c33Sjakob 			port = strtol(word, &end, 10);
22662ac0c33Sjakob 			if (*end != '\0') {
22762ac0c33Sjakob 				zc_error_prev_line("unknown service '%s' for protocol '%s'",
22862ac0c33Sjakob 						   word, protostr);
22962ac0c33Sjakob 				continue;
23062ac0c33Sjakob 			}
23162ac0c33Sjakob 		}
23262ac0c33Sjakob 
23362ac0c33Sjakob 		if (port < 0 || port > 65535) {
23462ac0c33Sjakob 			zc_error_prev_line("bad port number %d", port);
23562ac0c33Sjakob 		} else {
23662ac0c33Sjakob 			set_bit(bitmap, port);
23762ac0c33Sjakob 			if (port > max_port)
23862ac0c33Sjakob 				max_port = port;
23962ac0c33Sjakob 		}
24062ac0c33Sjakob 	}
24162ac0c33Sjakob 
24262ac0c33Sjakob 	r = alloc_rdata(region, sizeof(uint8_t) + max_port / 8 + 1);
24362ac0c33Sjakob 	p = (uint8_t *) (r + 1);
24462ac0c33Sjakob 	*p = proto->p_proto;
245a302926fSbrad 	memcpy(p + 1, bitmap, *r-1);
24662ac0c33Sjakob 
24762ac0c33Sjakob 	return r;
24862ac0c33Sjakob }
24962ac0c33Sjakob 
25062ac0c33Sjakob uint16_t *
zparser_conv_serial(region_type * region,const char * serialstr)25162ac0c33Sjakob zparser_conv_serial(region_type *region, const char *serialstr)
25262ac0c33Sjakob {
25362ac0c33Sjakob 	uint16_t *r = NULL;
25462ac0c33Sjakob 	uint32_t serial;
25562ac0c33Sjakob 	const char *t;
25662ac0c33Sjakob 
25762ac0c33Sjakob 	serial = strtoserial(serialstr, &t);
25862ac0c33Sjakob 	if (*t != '\0') {
259db7d0d02Sflorian 		zc_error_prev_line("serial is expected or serial too big");
26062ac0c33Sjakob 	} else {
26162ac0c33Sjakob 		serial = htonl(serial);
26262ac0c33Sjakob 		r = alloc_rdata_init(region, &serial, sizeof(serial));
26362ac0c33Sjakob 	}
26462ac0c33Sjakob 	return r;
26562ac0c33Sjakob }
26662ac0c33Sjakob 
26762ac0c33Sjakob uint16_t *
zparser_conv_period(region_type * region,const char * periodstr)26862ac0c33Sjakob zparser_conv_period(region_type *region, const char *periodstr)
26962ac0c33Sjakob {
27062ac0c33Sjakob 	/* convert a time period (think TTL's) to wireformat) */
27162ac0c33Sjakob 	uint16_t *r = NULL;
27262ac0c33Sjakob 	uint32_t period;
27362ac0c33Sjakob 	const char *end;
27462ac0c33Sjakob 
27562ac0c33Sjakob 	/* Allocate required space... */
27662ac0c33Sjakob 	period = strtottl(periodstr, &end);
27762ac0c33Sjakob 	if (*end != '\0') {
27862ac0c33Sjakob 		zc_error_prev_line("time period is expected");
27962ac0c33Sjakob 	} else {
28062ac0c33Sjakob 		period = htonl(period);
28162ac0c33Sjakob 		r = alloc_rdata_init(region, &period, sizeof(period));
28262ac0c33Sjakob 	}
28362ac0c33Sjakob 	return r;
28462ac0c33Sjakob }
28562ac0c33Sjakob 
28662ac0c33Sjakob uint16_t *
zparser_conv_short(region_type * region,const char * text)28762ac0c33Sjakob zparser_conv_short(region_type *region, const char *text)
28862ac0c33Sjakob {
28962ac0c33Sjakob 	uint16_t *r = NULL;
29062ac0c33Sjakob 	uint16_t value;
29162ac0c33Sjakob 	char *end;
29262ac0c33Sjakob 
29362ac0c33Sjakob 	value = htons((uint16_t) strtol(text, &end, 10));
29462ac0c33Sjakob 	if (*end != '\0') {
29562ac0c33Sjakob 		zc_error_prev_line("integer value is expected");
29662ac0c33Sjakob 	} else {
29762ac0c33Sjakob 		r = alloc_rdata_init(region, &value, sizeof(value));
29862ac0c33Sjakob 	}
29962ac0c33Sjakob 	return r;
30062ac0c33Sjakob }
30162ac0c33Sjakob 
30262ac0c33Sjakob uint16_t *
zparser_conv_byte(region_type * region,const char * text)30362ac0c33Sjakob zparser_conv_byte(region_type *region, const char *text)
30462ac0c33Sjakob {
30562ac0c33Sjakob 	uint16_t *r = NULL;
30662ac0c33Sjakob 	uint8_t value;
30762ac0c33Sjakob 	char *end;
30862ac0c33Sjakob 
30962ac0c33Sjakob 	value = (uint8_t) strtol(text, &end, 10);
31062ac0c33Sjakob 	if (*end != '\0') {
31162ac0c33Sjakob 		zc_error_prev_line("integer value is expected");
31262ac0c33Sjakob 	} else {
31362ac0c33Sjakob 		r = alloc_rdata_init(region, &value, sizeof(value));
31462ac0c33Sjakob 	}
31562ac0c33Sjakob 	return r;
31662ac0c33Sjakob }
31762ac0c33Sjakob 
31862ac0c33Sjakob uint16_t *
zparser_conv_algorithm(region_type * region,const char * text)31962ac0c33Sjakob zparser_conv_algorithm(region_type *region, const char *text)
32062ac0c33Sjakob {
32162ac0c33Sjakob 	const lookup_table_type *alg;
32262ac0c33Sjakob 	uint8_t id;
32362ac0c33Sjakob 
32462ac0c33Sjakob 	alg = lookup_by_name(dns_algorithms, text);
32562ac0c33Sjakob 	if (alg) {
32662ac0c33Sjakob 		id = (uint8_t) alg->id;
32762ac0c33Sjakob 	} else {
32862ac0c33Sjakob 		char *end;
32962ac0c33Sjakob 		id = (uint8_t) strtol(text, &end, 10);
33062ac0c33Sjakob 		if (*end != '\0') {
33162ac0c33Sjakob 			zc_error_prev_line("algorithm is expected");
33262ac0c33Sjakob 			return NULL;
33362ac0c33Sjakob 		}
33462ac0c33Sjakob 	}
33562ac0c33Sjakob 
33662ac0c33Sjakob 	return alloc_rdata_init(region, &id, sizeof(id));
33762ac0c33Sjakob }
33862ac0c33Sjakob 
33962ac0c33Sjakob uint16_t *
zparser_conv_certificate_type(region_type * region,const char * text)34062ac0c33Sjakob zparser_conv_certificate_type(region_type *region, const char *text)
34162ac0c33Sjakob {
3422fd875a4Ssthen 	/* convert an algorithm string to integer */
34362ac0c33Sjakob 	const lookup_table_type *type;
34462ac0c33Sjakob 	uint16_t id;
34562ac0c33Sjakob 
34662ac0c33Sjakob 	type = lookup_by_name(dns_certificate_types, text);
34762ac0c33Sjakob 	if (type) {
34862ac0c33Sjakob 		id = htons((uint16_t) type->id);
34962ac0c33Sjakob 	} else {
35062ac0c33Sjakob 		char *end;
35162ac0c33Sjakob 		id = htons((uint16_t) strtol(text, &end, 10));
35262ac0c33Sjakob 		if (*end != '\0') {
35362ac0c33Sjakob 			zc_error_prev_line("certificate type is expected");
35462ac0c33Sjakob 			return NULL;
35562ac0c33Sjakob 		}
35662ac0c33Sjakob 	}
35762ac0c33Sjakob 
35862ac0c33Sjakob 	return alloc_rdata_init(region, &id, sizeof(id));
35962ac0c33Sjakob }
36062ac0c33Sjakob 
36162ac0c33Sjakob uint16_t *
zparser_conv_a(region_type * region,const char * text)36262ac0c33Sjakob zparser_conv_a(region_type *region, const char *text)
36362ac0c33Sjakob {
36462ac0c33Sjakob 	in_addr_t address;
36562ac0c33Sjakob 	uint16_t *r = NULL;
36662ac0c33Sjakob 
36762ac0c33Sjakob 	if (inet_pton(AF_INET, text, &address) != 1) {
36862ac0c33Sjakob 		zc_error_prev_line("invalid IPv4 address '%s'", text);
36962ac0c33Sjakob 	} else {
37062ac0c33Sjakob 		r = alloc_rdata_init(region, &address, sizeof(address));
37162ac0c33Sjakob 	}
37262ac0c33Sjakob 	return r;
37362ac0c33Sjakob }
37462ac0c33Sjakob 
37562ac0c33Sjakob uint16_t *
zparser_conv_aaaa(region_type * region,const char * text)37662ac0c33Sjakob zparser_conv_aaaa(region_type *region, const char *text)
37762ac0c33Sjakob {
37862ac0c33Sjakob 	uint8_t address[IP6ADDRLEN];
37962ac0c33Sjakob 	uint16_t *r = NULL;
38062ac0c33Sjakob 
38162ac0c33Sjakob 	if (inet_pton(AF_INET6, text, address) != 1) {
38262ac0c33Sjakob 		zc_error_prev_line("invalid IPv6 address '%s'", text);
38362ac0c33Sjakob 	} else {
38462ac0c33Sjakob 		r = alloc_rdata_init(region, address, sizeof(address));
38562ac0c33Sjakob 	}
38662ac0c33Sjakob 	return r;
38762ac0c33Sjakob }
38862ac0c33Sjakob 
389dd5b221eSsthen 
39062ac0c33Sjakob uint16_t *
zparser_conv_ilnp64(region_type * region,const char * text)39175343be4Ssthen zparser_conv_ilnp64(region_type *region, const char *text)
39275343be4Ssthen {
39375343be4Ssthen 	uint16_t *r = NULL;
39475343be4Ssthen 	int ngroups, num;
39575343be4Ssthen 	unsigned long hex;
39675343be4Ssthen 	const char *ch;
39775343be4Ssthen 	char digits[ILNP_MAXDIGITS+1];
39875343be4Ssthen 	unsigned int ui[ILNP_NUMGROUPS];
39975343be4Ssthen 	uint16_t a[ILNP_NUMGROUPS];
40075343be4Ssthen 
40175343be4Ssthen 	ngroups = 1; /* Always at least one group */
40275343be4Ssthen 	num = 0;
40375343be4Ssthen 	for (ch = text; *ch != '\0'; ch++) {
40475343be4Ssthen 		if (*ch == ':') {
40575343be4Ssthen 			if (num <= 0) {
40675343be4Ssthen 				zc_error_prev_line("ilnp64: empty group of "
40775343be4Ssthen 					"digits is not allowed");
40875343be4Ssthen 				return NULL;
40975343be4Ssthen 			}
41075343be4Ssthen 			digits[num] = '\0';
41175343be4Ssthen 			hex = (unsigned long) strtol(digits, NULL, 16);
41275343be4Ssthen 			num = 0;
41375343be4Ssthen 			ui[ngroups - 1] = hex;
41475343be4Ssthen 			if (ngroups >= ILNP_NUMGROUPS) {
41575343be4Ssthen 				zc_error_prev_line("ilnp64: more than %d groups "
41675343be4Ssthen 					"of digits", ILNP_NUMGROUPS);
41775343be4Ssthen 				return NULL;
41875343be4Ssthen 			}
41975343be4Ssthen 			ngroups++;
42075343be4Ssthen 		} else {
42175343be4Ssthen 			/* Our grammar is stricter than the one accepted by
42275343be4Ssthen 			 * strtol. */
423c1404d4fSbrad 			if (!isxdigit((unsigned char)*ch)) {
42475343be4Ssthen 				zc_error_prev_line("ilnp64: invalid "
425c1404d4fSbrad 					"(non-hexadecimal) character %c", *ch);
42675343be4Ssthen 				return NULL;
42775343be4Ssthen 			}
42875343be4Ssthen 			if (num >= ILNP_MAXDIGITS) {
42975343be4Ssthen 				zc_error_prev_line("ilnp64: more than %d digits "
43075343be4Ssthen 					"in a group", ILNP_MAXDIGITS);
43175343be4Ssthen 				return NULL;
43275343be4Ssthen 			}
43375343be4Ssthen 			digits[num++] = *ch;
43475343be4Ssthen 		}
43575343be4Ssthen 	}
43675343be4Ssthen 	if (num <= 0) {
43775343be4Ssthen 		zc_error_prev_line("ilnp64: empty group of digits is not "
43875343be4Ssthen 			"allowed");
43975343be4Ssthen 		return NULL;
44075343be4Ssthen 	}
44175343be4Ssthen 	digits[num] = '\0';
44275343be4Ssthen 	hex = (unsigned long) strtol(digits, NULL, 16);
44375343be4Ssthen 	ui[ngroups - 1] = hex;
44475343be4Ssthen 	if (ngroups < 4) {
44575343be4Ssthen 		zc_error_prev_line("ilnp64: less than %d groups of digits",
44675343be4Ssthen 			ILNP_NUMGROUPS);
44775343be4Ssthen 		return NULL;
44875343be4Ssthen 	}
44975343be4Ssthen 
45075343be4Ssthen 	a[0] = htons(ui[0]);
45175343be4Ssthen 	a[1] = htons(ui[1]);
45275343be4Ssthen 	a[2] = htons(ui[2]);
45375343be4Ssthen 	a[3] = htons(ui[3]);
45475343be4Ssthen 	r = alloc_rdata_init(region, a, sizeof(a));
45575343be4Ssthen 	return r;
45675343be4Ssthen }
45775343be4Ssthen 
4589c620270Ssthen static uint16_t *
zparser_conv_eui48(region_type * region,const char * text)4599c620270Ssthen zparser_conv_eui48(region_type *region, const char *text)
4609c620270Ssthen {
4619c620270Ssthen 	uint8_t nums[6];
4629c620270Ssthen 	uint16_t *r = NULL;
4639c620270Ssthen 	unsigned int a, b, c, d, e, f;
4649c620270Ssthen 	int l;
4659c620270Ssthen 
4669c620270Ssthen 	if (sscanf(text, "%2x-%2x-%2x-%2x-%2x-%2x%n",
4679c620270Ssthen 		&a, &b, &c, &d, &e, &f, &l) != 6 ||
4689c620270Ssthen 		l != (int)strlen(text)){
4699c620270Ssthen 		zc_error_prev_line("eui48: invalid rr");
4709c620270Ssthen 		return NULL;
4719c620270Ssthen 	}
4729c620270Ssthen 	nums[0] = (uint8_t)a;
4739c620270Ssthen 	nums[1] = (uint8_t)b;
4749c620270Ssthen 	nums[2] = (uint8_t)c;
4759c620270Ssthen 	nums[3] = (uint8_t)d;
4769c620270Ssthen 	nums[4] = (uint8_t)e;
4779c620270Ssthen 	nums[5] = (uint8_t)f;
4789c620270Ssthen 	r = alloc_rdata_init(region, nums, sizeof(nums));
4799c620270Ssthen 	return r;
4809c620270Ssthen }
4819c620270Ssthen 
4829c620270Ssthen static uint16_t *
zparser_conv_eui64(region_type * region,const char * text)4839c620270Ssthen zparser_conv_eui64(region_type *region, const char *text)
4849c620270Ssthen {
4859c620270Ssthen 	uint8_t nums[8];
4869c620270Ssthen 	uint16_t *r = NULL;
4879c620270Ssthen 	unsigned int a, b, c, d, e, f, g, h;
4889c620270Ssthen 	int l;
4899c620270Ssthen 	if (sscanf(text, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n",
4909c620270Ssthen 		&a, &b, &c, &d, &e, &f, &g, &h, &l) != 8 ||
4919c620270Ssthen 		l != (int)strlen(text)) {
4929c620270Ssthen 		zc_error_prev_line("eui64: invalid rr");
4939c620270Ssthen 		return NULL;
4949c620270Ssthen 	}
4959c620270Ssthen 	nums[0] = (uint8_t)a;
4969c620270Ssthen 	nums[1] = (uint8_t)b;
4979c620270Ssthen 	nums[2] = (uint8_t)c;
4989c620270Ssthen 	nums[3] = (uint8_t)d;
4999c620270Ssthen 	nums[4] = (uint8_t)e;
5009c620270Ssthen 	nums[5] = (uint8_t)f;
5019c620270Ssthen 	nums[6] = (uint8_t)g;
5029c620270Ssthen 	nums[7] = (uint8_t)h;
5039c620270Ssthen 	r = alloc_rdata_init(region, nums, sizeof(nums));
5049c620270Ssthen 	return r;
5059c620270Ssthen }
5069c620270Ssthen 
5079c620270Ssthen uint16_t *
zparser_conv_eui(region_type * region,const char * text,size_t len)5089c620270Ssthen zparser_conv_eui(region_type *region, const char *text, size_t len)
5099c620270Ssthen {
5109c620270Ssthen 	uint16_t *r = NULL;
5119c620270Ssthen 	int nnum, num;
5129c620270Ssthen 	const char* ch;
5139c620270Ssthen 
5149c620270Ssthen 	nnum = len/8;
5159c620270Ssthen 	num = 1;
5169c620270Ssthen 	for (ch = text; *ch != '\0'; ch++) {
5179c620270Ssthen 		if (*ch == '-') {
5189c620270Ssthen 			num++;
519c1404d4fSbrad 		} else if (!isxdigit((unsigned char)*ch)) {
5209c620270Ssthen 			zc_error_prev_line("eui%u: invalid (non-hexadecimal) "
521c1404d4fSbrad 				"character %c", (unsigned) len, *ch);
5229c620270Ssthen 			return NULL;
5239c620270Ssthen 		}
5249c620270Ssthen 	}
5259c620270Ssthen 	if (num != nnum) {
5269c620270Ssthen 		zc_error_prev_line("eui%u: wrong number of hex numbers",
5279c620270Ssthen 			(unsigned) len);
5289c620270Ssthen 		return NULL;
5299c620270Ssthen 	}
5309c620270Ssthen 
5319c620270Ssthen 	switch (len) {
5329c620270Ssthen 		case 48:
5339c620270Ssthen 			r = zparser_conv_eui48(region, text);
5349c620270Ssthen 			break;
5359c620270Ssthen 		case 64:
5369c620270Ssthen 			r = zparser_conv_eui64(region, text);
5379c620270Ssthen 		break;
5389c620270Ssthen 		default:
5399c620270Ssthen 			zc_error_prev_line("eui%u: invalid length",
5409c620270Ssthen 				(unsigned) len);
5419c620270Ssthen 			return NULL;
5429c620270Ssthen 			break;
5439c620270Ssthen 	}
5449c620270Ssthen 	return r;
5459c620270Ssthen }
5469c620270Ssthen 
54775343be4Ssthen uint16_t *
zparser_conv_text(region_type * region,const char * text,size_t len)54862ac0c33Sjakob zparser_conv_text(region_type *region, const char *text, size_t len)
54962ac0c33Sjakob {
55062ac0c33Sjakob 	uint16_t *r = NULL;
5510b3518aaSsthen 	uint8_t *p;
55262ac0c33Sjakob 
55362ac0c33Sjakob 	if (len > 255) {
55462ac0c33Sjakob 		zc_error_prev_line("text string is longer than 255 characters,"
55562ac0c33Sjakob 				   " try splitting it into multiple parts");
55672f0a8e9Ssthen 		len = 255;
55772f0a8e9Ssthen 	}
55862ac0c33Sjakob 	r = alloc_rdata(region, len + 1);
55962ac0c33Sjakob 	p = (uint8_t *) (r + 1);
56062ac0c33Sjakob 	*p = len;
56162ac0c33Sjakob 	memcpy(p + 1, text, len);
56262ac0c33Sjakob 	return r;
56362ac0c33Sjakob }
56462ac0c33Sjakob 
565a302926fSbrad /* for CAA Value [RFC 6844] */
566a302926fSbrad uint16_t *
zparser_conv_long_text(region_type * region,const char * text,size_t len)567a302926fSbrad zparser_conv_long_text(region_type *region, const char *text, size_t len)
568a302926fSbrad {
569a302926fSbrad 	uint16_t *r = NULL;
570a302926fSbrad 	if (len > MAX_RDLENGTH) {
571a302926fSbrad 		zc_error_prev_line("text string is longer than max rdlen");
572a302926fSbrad 		return NULL;
573a302926fSbrad 	}
574a302926fSbrad 	r = alloc_rdata_init(region, text, len);
575a302926fSbrad 	return r;
576a302926fSbrad }
577a302926fSbrad 
578a302926fSbrad /* for CAA Tag [RFC 6844] */
579a302926fSbrad uint16_t *
zparser_conv_tag(region_type * region,const char * text,size_t len)580a302926fSbrad zparser_conv_tag(region_type *region, const char *text, size_t len)
581a302926fSbrad {
582a302926fSbrad 	uint16_t *r = NULL;
583a302926fSbrad 	uint8_t *p;
584a302926fSbrad 	const char* ptr;
585a302926fSbrad 
586a302926fSbrad 	if (len < 1) {
587a302926fSbrad 		zc_error_prev_line("invalid tag: zero length");
588a302926fSbrad 		return NULL;
589a302926fSbrad 	}
590a302926fSbrad 	if (len > 15) {
591a302926fSbrad 		zc_error_prev_line("invalid tag %s: longer than 15 characters (%u)",
592a302926fSbrad 			text, (unsigned) len);
593a302926fSbrad 		return NULL;
594a302926fSbrad 	}
595a302926fSbrad 	for (ptr = text; *ptr; ptr++) {
59682cafdebSmillert 		if (!isdigit((unsigned char)*ptr) && !islower((unsigned char)*ptr)) {
597a302926fSbrad 			zc_error_prev_line("invalid tag %s: contains invalid char %c",
598a302926fSbrad 				text, *ptr);
599a302926fSbrad 			return NULL;
600a302926fSbrad 		}
601a302926fSbrad 	}
602a302926fSbrad 	r = alloc_rdata(region, len + 1);
603a302926fSbrad 	p = (uint8_t *) (r + 1);
604a302926fSbrad 	*p = len;
605a302926fSbrad 	memmove(p + 1, text, len);
606a302926fSbrad 	return r;
607a302926fSbrad }
608a302926fSbrad 
60962ac0c33Sjakob uint16_t *
zparser_conv_dns_name(region_type * region,const uint8_t * name,size_t len)61062ac0c33Sjakob zparser_conv_dns_name(region_type *region, const uint8_t* name, size_t len)
61162ac0c33Sjakob {
61262ac0c33Sjakob 	uint16_t* r = NULL;
61362ac0c33Sjakob 	uint8_t* p = NULL;
61462ac0c33Sjakob 	r = alloc_rdata(region, len);
61562ac0c33Sjakob 	p = (uint8_t *) (r + 1);
61662ac0c33Sjakob 	memcpy(p, name, len);
61762ac0c33Sjakob 
61862ac0c33Sjakob 	return r;
61962ac0c33Sjakob }
62062ac0c33Sjakob 
62162ac0c33Sjakob uint16_t *
zparser_conv_b32(region_type * region,const char * b32)62262ac0c33Sjakob zparser_conv_b32(region_type *region, const char *b32)
62362ac0c33Sjakob {
62462ac0c33Sjakob 	uint8_t buffer[B64BUFSIZE];
62562ac0c33Sjakob 	uint16_t *r = NULL;
62662ac0c33Sjakob 	int i;
62762ac0c33Sjakob 
62862ac0c33Sjakob 	if(strcmp(b32, "-") == 0) {
62962ac0c33Sjakob 		return alloc_rdata_init(region, "", 1);
63062ac0c33Sjakob 	}
63162ac0c33Sjakob 	i = b32_pton(b32, buffer+1, B64BUFSIZE-1);
63262ac0c33Sjakob 	if (i == -1 || i > 255) {
63362ac0c33Sjakob 		zc_error_prev_line("invalid base32 data");
63462ac0c33Sjakob 	} else {
63562ac0c33Sjakob 		buffer[0] = i; /* store length byte */
63662ac0c33Sjakob 		r = alloc_rdata_init(region, buffer, i+1);
63762ac0c33Sjakob 	}
63862ac0c33Sjakob 	return r;
63962ac0c33Sjakob }
64062ac0c33Sjakob 
64162ac0c33Sjakob uint16_t *
zparser_conv_b64(region_type * region,const char * b64)64262ac0c33Sjakob zparser_conv_b64(region_type *region, const char *b64)
64362ac0c33Sjakob {
64462ac0c33Sjakob 	uint8_t buffer[B64BUFSIZE];
64562ac0c33Sjakob 	uint16_t *r = NULL;
64662ac0c33Sjakob 	int i;
64762ac0c33Sjakob 
648fb800cb5Sflorian 	if(strcmp(b64, "0") == 0) {
649fb800cb5Sflorian 		/* single 0 represents empty buffer */
650fb800cb5Sflorian 		return alloc_rdata(region, 0);
651fb800cb5Sflorian 	}
65272628ec9Ssthen 	i = __b64_pton(b64, buffer, B64BUFSIZE);
65362ac0c33Sjakob 	if (i == -1) {
65462ac0c33Sjakob 		zc_error_prev_line("invalid base64 data");
65562ac0c33Sjakob 	} else {
65662ac0c33Sjakob 		r = alloc_rdata_init(region, buffer, i);
65762ac0c33Sjakob 	}
65862ac0c33Sjakob 	return r;
65962ac0c33Sjakob }
66062ac0c33Sjakob 
66162ac0c33Sjakob uint16_t *
zparser_conv_rrtype(region_type * region,const char * text)66262ac0c33Sjakob zparser_conv_rrtype(region_type *region, const char *text)
66362ac0c33Sjakob {
66462ac0c33Sjakob 	uint16_t *r = NULL;
66562ac0c33Sjakob 	uint16_t type = rrtype_from_string(text);
66662ac0c33Sjakob 
66762ac0c33Sjakob 	if (type == 0) {
66862ac0c33Sjakob 		zc_error_prev_line("unrecognized RR type '%s'", text);
66962ac0c33Sjakob 	} else {
67062ac0c33Sjakob 		type = htons(type);
67162ac0c33Sjakob 		r = alloc_rdata_init(region, &type, sizeof(type));
67262ac0c33Sjakob 	}
67362ac0c33Sjakob 	return r;
67462ac0c33Sjakob }
67562ac0c33Sjakob 
67662ac0c33Sjakob uint16_t *
zparser_conv_nxt(region_type * region,uint8_t nxtbits[])67762ac0c33Sjakob zparser_conv_nxt(region_type *region, uint8_t nxtbits[])
67862ac0c33Sjakob {
67962ac0c33Sjakob 	/* nxtbits[] consists of 16 bytes with some zero's in it
68062ac0c33Sjakob 	 * copy every byte with zero to r and write the length in
68162ac0c33Sjakob 	 * the first byte
68262ac0c33Sjakob 	 */
68362ac0c33Sjakob 	uint16_t i;
68462ac0c33Sjakob 	uint16_t last = 0;
68562ac0c33Sjakob 
68662ac0c33Sjakob 	for (i = 0; i < 16; i++) {
68762ac0c33Sjakob 		if (nxtbits[i] != 0)
68862ac0c33Sjakob 			last = i + 1;
68962ac0c33Sjakob 	}
69062ac0c33Sjakob 
69162ac0c33Sjakob 	return alloc_rdata_init(region, nxtbits, last);
69262ac0c33Sjakob }
69362ac0c33Sjakob 
69462ac0c33Sjakob 
69562ac0c33Sjakob /* we potentially have 256 windows, each one is numbered. empty ones
69662ac0c33Sjakob  * should be discarded
69762ac0c33Sjakob  */
69862ac0c33Sjakob uint16_t *
zparser_conv_nsec(region_type * region,uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE])69962ac0c33Sjakob zparser_conv_nsec(region_type *region,
70062ac0c33Sjakob 		  uint8_t nsecbits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE])
70162ac0c33Sjakob {
70262ac0c33Sjakob 	/* nsecbits contains up to 64K of bits which represent the
70362ac0c33Sjakob 	 * types available for a name. Walk the bits according to
70462ac0c33Sjakob 	 * nsec++ draft from jakob
70562ac0c33Sjakob 	 */
70662ac0c33Sjakob 	uint16_t *r;
70762ac0c33Sjakob 	uint8_t *ptr;
70862ac0c33Sjakob 	size_t i,j;
70962ac0c33Sjakob 	uint16_t window_count = 0;
71062ac0c33Sjakob 	uint16_t total_size = 0;
71162ac0c33Sjakob 	uint16_t window_max = 0;
71262ac0c33Sjakob 
71362ac0c33Sjakob 	/* The used windows.  */
71462ac0c33Sjakob 	int used[NSEC_WINDOW_COUNT];
71562ac0c33Sjakob 	/* The last byte used in each the window.  */
71662ac0c33Sjakob 	int size[NSEC_WINDOW_COUNT];
71762ac0c33Sjakob 
71862ac0c33Sjakob 	window_max = 1 + (nsec_highest_rcode / 256);
71962ac0c33Sjakob 
72062ac0c33Sjakob 	/* used[i] is the i-th window included in the nsec
72162ac0c33Sjakob 	 * size[used[0]] is the size of window 0
72262ac0c33Sjakob 	 */
72362ac0c33Sjakob 
72462ac0c33Sjakob 	/* walk through the 256 windows */
72562ac0c33Sjakob 	for (i = 0; i < window_max; ++i) {
72662ac0c33Sjakob 		int empty_window = 1;
72762ac0c33Sjakob 		/* check each of the 32 bytes */
72862ac0c33Sjakob 		for (j = 0; j < NSEC_WINDOW_BITS_SIZE; ++j) {
72962ac0c33Sjakob 			if (nsecbits[i][j] != 0) {
73062ac0c33Sjakob 				size[i] = j + 1;
73162ac0c33Sjakob 				empty_window = 0;
73262ac0c33Sjakob 			}
73362ac0c33Sjakob 		}
73462ac0c33Sjakob 		if (!empty_window) {
73562ac0c33Sjakob 			used[window_count] = i;
73662ac0c33Sjakob 			window_count++;
73762ac0c33Sjakob 		}
73862ac0c33Sjakob 	}
73962ac0c33Sjakob 
74062ac0c33Sjakob 	for (i = 0; i < window_count; ++i) {
74162ac0c33Sjakob 		total_size += sizeof(uint16_t) + size[used[i]];
74262ac0c33Sjakob 	}
74362ac0c33Sjakob 
74462ac0c33Sjakob 	r = alloc_rdata(region, total_size);
74562ac0c33Sjakob 	ptr = (uint8_t *) (r + 1);
74662ac0c33Sjakob 
74762ac0c33Sjakob 	/* now walk used and copy it */
74862ac0c33Sjakob 	for (i = 0; i < window_count; ++i) {
74962ac0c33Sjakob 		ptr[0] = used[i];
75062ac0c33Sjakob 		ptr[1] = size[used[i]];
75162ac0c33Sjakob 		memcpy(ptr + 2, &nsecbits[used[i]], size[used[i]]);
75262ac0c33Sjakob 		ptr += size[used[i]] + 2;
75362ac0c33Sjakob 	}
75462ac0c33Sjakob 
75562ac0c33Sjakob 	return r;
75662ac0c33Sjakob }
75762ac0c33Sjakob 
758063644e9Sflorian static uint16_t
svcbparam_lookup_key(const char * key,size_t key_len)759063644e9Sflorian svcbparam_lookup_key(const char *key, size_t key_len)
760063644e9Sflorian {
761063644e9Sflorian 	char buf[64];
762063644e9Sflorian 	char *endptr;
763063644e9Sflorian 	unsigned long int key_value;
764063644e9Sflorian 
765063644e9Sflorian 	if (key_len >= 4  && key_len <= 8 && !strncmp(key, "key", 3)) {
766063644e9Sflorian 		memcpy(buf, key + 3, key_len - 3);
767063644e9Sflorian 		buf[key_len - 3] = 0;
768063644e9Sflorian 		key_value = strtoul(buf, &endptr, 10);
769063644e9Sflorian 		if (endptr > buf	/* digits seen */
770063644e9Sflorian 		&& *endptr == 0		/* no non-digit chars after digits */
771063644e9Sflorian 		&&  key_value <= 65535)	/* no overflow */
772063644e9Sflorian 			return key_value;
773063644e9Sflorian 
774063644e9Sflorian 	} else switch (key_len) {
775063644e9Sflorian 	case sizeof("mandatory")-1:
776063644e9Sflorian 		if (!strncmp(key, "mandatory", sizeof("mandatory")-1))
777063644e9Sflorian 			return SVCB_KEY_MANDATORY;
778063644e9Sflorian 		if (!strncmp(key, "echconfig", sizeof("echconfig")-1))
7794564029fSflorian 			return SVCB_KEY_ECH; /* allow "echconfig" as well as "ech" */
780063644e9Sflorian 		break;
781063644e9Sflorian 
782063644e9Sflorian 	case sizeof("alpn")-1:
783063644e9Sflorian 		if (!strncmp(key, "alpn", sizeof("alpn")-1))
784063644e9Sflorian 			return SVCB_KEY_ALPN;
785063644e9Sflorian 		if (!strncmp(key, "port", sizeof("port")-1))
786063644e9Sflorian 			return SVCB_KEY_PORT;
787063644e9Sflorian 		break;
788063644e9Sflorian 
789063644e9Sflorian 	case sizeof("no-default-alpn")-1:
790063644e9Sflorian 		if (!strncmp( key  , "no-default-alpn"
791063644e9Sflorian 		            , sizeof("no-default-alpn")-1))
792063644e9Sflorian 			return SVCB_KEY_NO_DEFAULT_ALPN;
793063644e9Sflorian 		break;
794063644e9Sflorian 
795063644e9Sflorian 	case sizeof("ipv4hint")-1:
796063644e9Sflorian 		if (!strncmp(key, "ipv4hint", sizeof("ipv4hint")-1))
797063644e9Sflorian 			return SVCB_KEY_IPV4HINT;
798063644e9Sflorian 		if (!strncmp(key, "ipv6hint", sizeof("ipv6hint")-1))
799063644e9Sflorian 			return SVCB_KEY_IPV6HINT;
800063644e9Sflorian 		break;
801*de04d855Ssthen 	case sizeof("dohpath")-1:
802*de04d855Ssthen 		if (!strncmp(key, "dohpath", sizeof("dohpath")-1))
803*de04d855Ssthen 			return SVCB_KEY_DOHPATH;
804*de04d855Ssthen 		break;
805063644e9Sflorian 	case sizeof("ech")-1:
806063644e9Sflorian 		if (!strncmp(key, "ech", sizeof("ech")-1))
807063644e9Sflorian 			return SVCB_KEY_ECH;
808063644e9Sflorian 		break;
809063644e9Sflorian 	default:
810063644e9Sflorian 		break;
811063644e9Sflorian 	}
812063644e9Sflorian 	if (key_len > sizeof(buf) - 1)
813063644e9Sflorian 		zc_error_prev_line("Unknown SvcParamKey");
814063644e9Sflorian 	else {
815063644e9Sflorian 		memcpy(buf, key, key_len);
816063644e9Sflorian 		buf[key_len] = 0;
817063644e9Sflorian 		zc_error_prev_line("Unknown SvcParamKey: %s", buf);
818063644e9Sflorian 	}
819063644e9Sflorian 	/* Although the returned value might be used by the caller,
820063644e9Sflorian 	 * the parser has erred, so the zone will not be loaded.
821063644e9Sflorian 	 */
822063644e9Sflorian 	return -1;
823063644e9Sflorian }
824063644e9Sflorian 
825063644e9Sflorian static uint16_t *
zparser_conv_svcbparam_port_value(region_type * region,const char * val)826063644e9Sflorian zparser_conv_svcbparam_port_value(region_type *region, const char *val)
827063644e9Sflorian {
828063644e9Sflorian 	unsigned long int port;
829063644e9Sflorian 	char *endptr;
830063644e9Sflorian 	uint16_t *r;
831063644e9Sflorian 
832063644e9Sflorian 	port = strtoul(val, &endptr, 10);
833063644e9Sflorian 	if (endptr > val	/* digits seen */
834063644e9Sflorian 	&& *endptr == 0		/* no non-digit chars after digits */
835063644e9Sflorian 	&&  port <= 65535) {	/* no overflow */
836063644e9Sflorian 
837063644e9Sflorian 		r = alloc_rdata(region, 3 * sizeof(uint16_t));
838063644e9Sflorian 		r[1] = htons(SVCB_KEY_PORT);
839063644e9Sflorian 		r[2] = htons(sizeof(uint16_t));
840063644e9Sflorian 		r[3] = htons(port);
841063644e9Sflorian 		return r;
842063644e9Sflorian 	}
843063644e9Sflorian 	zc_error_prev_line("Could not parse port SvcParamValue: \"%s\"", val);
844063644e9Sflorian 	return NULL;
845063644e9Sflorian }
846063644e9Sflorian 
847063644e9Sflorian static uint16_t *
zparser_conv_svcbparam_ipv4hint_value(region_type * region,const char * val)848063644e9Sflorian zparser_conv_svcbparam_ipv4hint_value(region_type *region, const char *val)
849063644e9Sflorian {
850063644e9Sflorian 	uint16_t *r;
851063644e9Sflorian 	int count;
852063644e9Sflorian 	char ip_str[INET_ADDRSTRLEN+1];
853063644e9Sflorian 	char *next_ip_str;
854063644e9Sflorian 	uint32_t *ip_wire_dst;
855063644e9Sflorian 	size_t i;
856063644e9Sflorian 
857063644e9Sflorian 	for (i = 0, count = 1; val[i]; i++) {
858063644e9Sflorian 		if (val[i] == ',')
859063644e9Sflorian 			count += 1;
860063644e9Sflorian 		if (count > SVCB_MAX_COMMA_SEPARATED_VALUES) {
861063644e9Sflorian 			zc_error_prev_line("Too many IPV4 addresses in ipv4hint");
862063644e9Sflorian 			return NULL;
863063644e9Sflorian 		}
864063644e9Sflorian 	}
865063644e9Sflorian 
866063644e9Sflorian 	/* count == number of comma's in val + 1, so the actual number of IPv4
867063644e9Sflorian 	 * addresses in val
868063644e9Sflorian 	 */
869063644e9Sflorian 	r = alloc_rdata(region, 2 * sizeof(uint16_t) + IP4ADDRLEN * count);
870063644e9Sflorian 	r[1] = htons(SVCB_KEY_IPV4HINT);
871063644e9Sflorian 	r[2] = htons(IP4ADDRLEN * count);
872063644e9Sflorian 	ip_wire_dst = (void *)&r[3];
873063644e9Sflorian 
874063644e9Sflorian 	while (count) {
875063644e9Sflorian 		if (!(next_ip_str = strchr(val, ','))) {
876063644e9Sflorian 			if (inet_pton(AF_INET, val, ip_wire_dst) != 1)
877063644e9Sflorian 				break;
878063644e9Sflorian 
879063644e9Sflorian 			assert(count == 1);
880063644e9Sflorian 
881063644e9Sflorian 		} else if (next_ip_str - val >= (int)sizeof(ip_str))
882063644e9Sflorian 			break;
883063644e9Sflorian 
884063644e9Sflorian 		else {
885063644e9Sflorian 			memcpy(ip_str, val, next_ip_str - val);
886063644e9Sflorian 			ip_str[next_ip_str - val] = 0;
887063644e9Sflorian 			if (inet_pton(AF_INET, ip_str, ip_wire_dst) != 1) {
888063644e9Sflorian 				val = ip_str; /* to use in error reporting below */
889063644e9Sflorian 				break;
890063644e9Sflorian 			}
891063644e9Sflorian 
892063644e9Sflorian 			val = next_ip_str + 1;
893063644e9Sflorian 		}
894063644e9Sflorian 		ip_wire_dst++;
895063644e9Sflorian 		count--;
896063644e9Sflorian 	}
897063644e9Sflorian 	if (count)
898063644e9Sflorian 		zc_error_prev_line("Could not parse ipv4hint SvcParamValue: %s", val);
899063644e9Sflorian 
900063644e9Sflorian 	return r;
901063644e9Sflorian }
902063644e9Sflorian 
903063644e9Sflorian static uint16_t *
zparser_conv_svcbparam_ipv6hint_value(region_type * region,const char * val)904063644e9Sflorian zparser_conv_svcbparam_ipv6hint_value(region_type *region, const char *val)
905063644e9Sflorian {
906063644e9Sflorian 	uint16_t *r;
907063644e9Sflorian 	int i, count;
908063644e9Sflorian 	char ip6_str[INET6_ADDRSTRLEN+1];
909063644e9Sflorian 	char *next_ip6_str;
910063644e9Sflorian 	uint8_t *ipv6_wire_dst;
911063644e9Sflorian 
912063644e9Sflorian 	for (i = 0, count = 1; val[i]; i++) {
913063644e9Sflorian 		if (val[i] == ',')
914063644e9Sflorian 			count += 1;
915063644e9Sflorian 		if (count > SVCB_MAX_COMMA_SEPARATED_VALUES) {
916063644e9Sflorian 			zc_error_prev_line("Too many IPV6 addresses in ipv6hint");
917063644e9Sflorian 			return NULL;
918063644e9Sflorian 		}
919063644e9Sflorian 	}
920063644e9Sflorian 
921063644e9Sflorian 	/* count == number of comma's in val + 1
922063644e9Sflorian 	 * so actually the number of IPv6 addresses in val
923063644e9Sflorian 	 */
924063644e9Sflorian 	r = alloc_rdata(region, 2 * sizeof(uint16_t) + IP6ADDRLEN * count);
925063644e9Sflorian 	r[1] = htons(SVCB_KEY_IPV6HINT);
926063644e9Sflorian 	r[2] = htons(IP6ADDRLEN * count);
927063644e9Sflorian 	ipv6_wire_dst = (void *)&r[3];
928063644e9Sflorian 
929063644e9Sflorian 	while (count) {
930063644e9Sflorian 		if (!(next_ip6_str = strchr(val, ','))) {
931063644e9Sflorian 			if ((inet_pton(AF_INET6, val, ipv6_wire_dst) != 1))
932063644e9Sflorian 				break;
933063644e9Sflorian 
934063644e9Sflorian 			assert(count == 1);
935063644e9Sflorian 
936063644e9Sflorian 		} else if (next_ip6_str - val >= (int)sizeof(ip6_str))
937063644e9Sflorian 			break;
938063644e9Sflorian 
939063644e9Sflorian 		else {
940063644e9Sflorian 			memcpy(ip6_str, val, next_ip6_str - val);
941063644e9Sflorian 			ip6_str[next_ip6_str - val] = 0;
942063644e9Sflorian 			if (inet_pton(AF_INET6, ip6_str, ipv6_wire_dst) != 1) {
943063644e9Sflorian 				val = ip6_str; /* for error reporting below */
944063644e9Sflorian 				break;
945063644e9Sflorian 			}
946063644e9Sflorian 
947063644e9Sflorian 			val = next_ip6_str + 1; /* skip the comma */
948063644e9Sflorian 		}
949063644e9Sflorian 		ipv6_wire_dst += IP6ADDRLEN;
950063644e9Sflorian 		count--;
951063644e9Sflorian 	}
952063644e9Sflorian 	if (count)
953063644e9Sflorian 		zc_error_prev_line("Could not parse ipv6hint SvcParamValue: %s", val);
954063644e9Sflorian 
955063644e9Sflorian 	return r;
956063644e9Sflorian }
957063644e9Sflorian 
958063644e9Sflorian static int
network_uint16_cmp(const void * a,const void * b)959063644e9Sflorian network_uint16_cmp(const void *a, const void *b)
960063644e9Sflorian {
961063644e9Sflorian 	return ((int)read_uint16(a)) - ((int)read_uint16(b));
962063644e9Sflorian }
963063644e9Sflorian 
964063644e9Sflorian static uint16_t *
zparser_conv_svcbparam_mandatory_value(region_type * region,const char * val,size_t val_len)965063644e9Sflorian zparser_conv_svcbparam_mandatory_value(region_type *region,
966063644e9Sflorian 		const char *val, size_t val_len)
967063644e9Sflorian {
968063644e9Sflorian 	uint16_t *r;
969063644e9Sflorian 	size_t i, count;
970063644e9Sflorian 	char* next_key;
971063644e9Sflorian 	uint16_t* key_dst;
972063644e9Sflorian 
973063644e9Sflorian 	for (i = 0, count = 1; val[i]; i++) {
974063644e9Sflorian 		if (val[i] == ',')
975063644e9Sflorian 			count += 1;
976063644e9Sflorian 		if (count > SVCB_MAX_COMMA_SEPARATED_VALUES) {
977063644e9Sflorian 			zc_error_prev_line("Too many keys in mandatory");
978063644e9Sflorian 			return NULL;
979063644e9Sflorian 		}
980063644e9Sflorian 	}
981063644e9Sflorian 
982063644e9Sflorian 	r = alloc_rdata(region, (2 + count) * sizeof(uint16_t));
983063644e9Sflorian 	r[1] = htons(SVCB_KEY_MANDATORY);
984063644e9Sflorian 	r[2] = htons(sizeof(uint16_t) * count);
985063644e9Sflorian 	key_dst = (void *)&r[3];
986063644e9Sflorian 
987063644e9Sflorian 	for(;;) {
988063644e9Sflorian 		if (!(next_key = strchr(val, ','))) {
989063644e9Sflorian 			*key_dst = htons(svcbparam_lookup_key(val, val_len));
990063644e9Sflorian 			break;
991063644e9Sflorian 		} else {
992063644e9Sflorian 			*key_dst = htons(svcbparam_lookup_key(val, next_key - val));
993063644e9Sflorian 		}
994063644e9Sflorian 
995063644e9Sflorian 		val_len -= next_key - val + 1;
996063644e9Sflorian 		val = next_key + 1; /* skip the comma */
997063644e9Sflorian 		key_dst += 1;
998063644e9Sflorian 	}
999063644e9Sflorian 
1000063644e9Sflorian 	/* In draft-ietf-dnsop-svcb-https-04 Section 7:
1001063644e9Sflorian 	 *
1002063644e9Sflorian 	 *     In wire format, the keys are represented by their numeric
1003063644e9Sflorian 	 *     values in network byte order, concatenated in ascending order.
1004063644e9Sflorian 	 */
1005063644e9Sflorian 	qsort((void *)&r[3], count, sizeof(uint16_t), network_uint16_cmp);
1006063644e9Sflorian 
1007063644e9Sflorian 	return r;
1008063644e9Sflorian }
1009063644e9Sflorian 
1010063644e9Sflorian static uint16_t *
zparser_conv_svcbparam_ech_value(region_type * region,const char * b64)1011063644e9Sflorian zparser_conv_svcbparam_ech_value(region_type *region, const char *b64)
1012063644e9Sflorian {
1013063644e9Sflorian 	uint8_t buffer[B64BUFSIZE];
1014063644e9Sflorian 	uint16_t *r = NULL;
1015063644e9Sflorian 	int wire_len;
1016063644e9Sflorian 
1017063644e9Sflorian 	if(strcmp(b64, "0") == 0) {
1018063644e9Sflorian 		/* single 0 represents empty buffer */
1019063644e9Sflorian 		return alloc_rdata(region, 0);
1020063644e9Sflorian 	}
1021063644e9Sflorian 	wire_len = __b64_pton(b64, buffer, B64BUFSIZE);
1022063644e9Sflorian 	if (wire_len == -1) {
1023063644e9Sflorian 		zc_error_prev_line("invalid base64 data in ech");
1024063644e9Sflorian 	} else {
1025063644e9Sflorian 		r = alloc_rdata(region, 2 * sizeof(uint16_t) + wire_len);
1026063644e9Sflorian 		r[1] = htons(SVCB_KEY_ECH);
1027063644e9Sflorian 		r[2] = htons(wire_len);
1028063644e9Sflorian 		memcpy(&r[3], buffer, wire_len);
1029063644e9Sflorian 	}
1030063644e9Sflorian 
1031063644e9Sflorian 	return r;
1032063644e9Sflorian }
1033063644e9Sflorian 
parse_alpn_next_unescaped_comma(const char * val)1034063644e9Sflorian static const char* parse_alpn_next_unescaped_comma(const char *val)
1035063644e9Sflorian {
1036063644e9Sflorian 	while (*val) {
1037063644e9Sflorian 		/* Only return when the comma is not escaped*/
1038063644e9Sflorian 		if (*val == '\\'){
1039063644e9Sflorian 			++val;
1040063644e9Sflorian 			if (!*val)
1041063644e9Sflorian 				break;
1042063644e9Sflorian 		} else if (*val == ',')
1043063644e9Sflorian 				return val;
1044063644e9Sflorian 
1045063644e9Sflorian 		val++;
1046063644e9Sflorian 	}
1047063644e9Sflorian 	return NULL;
1048063644e9Sflorian }
1049063644e9Sflorian 
1050063644e9Sflorian static size_t
parse_alpn_copy_unescaped(uint8_t * dst,const char * src,size_t len)1051063644e9Sflorian parse_alpn_copy_unescaped(uint8_t *dst, const char *src, size_t len)
1052063644e9Sflorian {
1053063644e9Sflorian 	uint8_t *orig_dst = dst;
1054063644e9Sflorian 
1055063644e9Sflorian 	while (len) {
1056063644e9Sflorian 		if (*src == '\\') {
1057063644e9Sflorian 			src++;
1058063644e9Sflorian 			len--;
1059063644e9Sflorian 			if (!len)
1060063644e9Sflorian 				break;
1061063644e9Sflorian 		}
1062063644e9Sflorian 		*dst++ = *src++;
1063063644e9Sflorian 		len--;
1064063644e9Sflorian 	}
1065063644e9Sflorian 	return (size_t)(dst - orig_dst);
1066063644e9Sflorian }
1067063644e9Sflorian 
1068063644e9Sflorian static uint16_t *
zparser_conv_svcbparam_alpn_value(region_type * region,const char * val,size_t val_len)1069063644e9Sflorian zparser_conv_svcbparam_alpn_value(region_type *region,
1070063644e9Sflorian 		const char *val, size_t val_len)
1071063644e9Sflorian {
1072063644e9Sflorian 	uint8_t     unescaped_dst[65536];
1073063644e9Sflorian 	uint8_t    *dst = unescaped_dst;
1074063644e9Sflorian 	const char *next_str;
1075063644e9Sflorian 	size_t      str_len;
1076063644e9Sflorian 	size_t      dst_len;
1077063644e9Sflorian 	uint16_t   *r = NULL;
1078063644e9Sflorian 
1079063644e9Sflorian 	if (val_len > sizeof(unescaped_dst)) {
1080063644e9Sflorian 		zc_error_prev_line("invalid alpn");
1081063644e9Sflorian 		return r;
1082063644e9Sflorian 	}
1083063644e9Sflorian 	while (val_len) {
1084063644e9Sflorian 		size_t dst_len;
1085063644e9Sflorian 
1086063644e9Sflorian 		str_len = (next_str = parse_alpn_next_unescaped_comma(val))
1087063644e9Sflorian 		        ? (size_t)(next_str - val) : val_len;
1088063644e9Sflorian 
1089063644e9Sflorian 		if (str_len > 255) {
1090063644e9Sflorian 			zc_error_prev_line("alpn strings need to be"
1091063644e9Sflorian 					   " smaller than 255 chars");
1092063644e9Sflorian 			return r;
1093063644e9Sflorian 		}
1094063644e9Sflorian 		dst_len = parse_alpn_copy_unescaped(dst + 1, val, str_len);
1095063644e9Sflorian 		*dst++ = dst_len;
1096063644e9Sflorian 		 dst  += dst_len;
1097063644e9Sflorian 
1098063644e9Sflorian 		if (!next_str)
1099063644e9Sflorian 			break;
1100063644e9Sflorian 
1101063644e9Sflorian 		/* skip the comma for the next iteration */
1102063644e9Sflorian 		val_len -= next_str - val + 1;
1103063644e9Sflorian 		val = next_str + 1;
1104063644e9Sflorian 	}
1105063644e9Sflorian 	dst_len = dst - unescaped_dst;
1106063644e9Sflorian 	r = alloc_rdata(region, 2 * sizeof(uint16_t) + dst_len);
1107063644e9Sflorian 	r[1] = htons(SVCB_KEY_ALPN);
1108063644e9Sflorian 	r[2] = htons(dst_len);
1109063644e9Sflorian 	memcpy(&r[3], unescaped_dst, dst_len);
1110063644e9Sflorian 	return r;
1111063644e9Sflorian }
1112063644e9Sflorian 
1113063644e9Sflorian static uint16_t *
zparser_conv_svcbparam_key_value(region_type * region,const char * key,size_t key_len,const char * val,size_t val_len)1114063644e9Sflorian zparser_conv_svcbparam_key_value(region_type *region,
1115063644e9Sflorian     const char *key, size_t key_len, const char *val, size_t val_len)
1116063644e9Sflorian {
1117063644e9Sflorian 	uint16_t svcparamkey = svcbparam_lookup_key(key, key_len);
1118063644e9Sflorian 	uint16_t *r;
1119063644e9Sflorian 
1120063644e9Sflorian 	switch (svcparamkey) {
1121063644e9Sflorian 	case SVCB_KEY_PORT:
1122063644e9Sflorian 		return zparser_conv_svcbparam_port_value(region, val);
1123063644e9Sflorian 	case SVCB_KEY_IPV4HINT:
1124063644e9Sflorian 		return zparser_conv_svcbparam_ipv4hint_value(region, val);
1125063644e9Sflorian 	case SVCB_KEY_IPV6HINT:
1126063644e9Sflorian 		return zparser_conv_svcbparam_ipv6hint_value(region, val);
1127063644e9Sflorian 	case SVCB_KEY_MANDATORY:
1128063644e9Sflorian 		return zparser_conv_svcbparam_mandatory_value(region, val, val_len);
1129063644e9Sflorian 	case SVCB_KEY_NO_DEFAULT_ALPN:
1130063644e9Sflorian 		if(zone_is_slave(parser->current_zone->opts))
1131063644e9Sflorian 			zc_warning_prev_line("no-default-alpn should not have a value");
1132063644e9Sflorian 		else
1133063644e9Sflorian 			zc_error_prev_line("no-default-alpn should not have a value");
1134063644e9Sflorian 		break;
1135063644e9Sflorian 	case SVCB_KEY_ECH:
1136063644e9Sflorian 		return zparser_conv_svcbparam_ech_value(region, val);
1137063644e9Sflorian 	case SVCB_KEY_ALPN:
1138063644e9Sflorian 		return zparser_conv_svcbparam_alpn_value(region, val, val_len);
1139*de04d855Ssthen 	case SVCB_KEY_DOHPATH:
1140*de04d855Ssthen 		/* fallthrough */
1141063644e9Sflorian 	default:
1142063644e9Sflorian 		break;
1143063644e9Sflorian 	}
1144063644e9Sflorian 	r = alloc_rdata(region, 2 * sizeof(uint16_t) + val_len);
1145063644e9Sflorian 	r[1] = htons(svcparamkey);
1146063644e9Sflorian 	r[2] = htons(val_len);
1147063644e9Sflorian 	memcpy(r + 3, val, val_len);
1148063644e9Sflorian 	return r;
1149063644e9Sflorian }
1150063644e9Sflorian 
1151063644e9Sflorian uint16_t *
zparser_conv_svcbparam(region_type * region,const char * key,size_t key_len,const char * val,size_t val_len)1152063644e9Sflorian zparser_conv_svcbparam(region_type *region, const char *key, size_t key_len
1153063644e9Sflorian                                           , const char *val, size_t val_len)
1154063644e9Sflorian {
1155063644e9Sflorian 	const char *eq;
1156063644e9Sflorian 	uint16_t *r;
1157063644e9Sflorian 	uint16_t svcparamkey;
1158063644e9Sflorian 
1159063644e9Sflorian 	/* Form <key>="<value>" (or at least with quoted value) */
1160063644e9Sflorian 	if (val && val_len) {
1161063644e9Sflorian 		/* Does key end with '=' */
1162063644e9Sflorian 		if (key_len && key[key_len - 1] == '=')
1163063644e9Sflorian 			return zparser_conv_svcbparam_key_value(
1164063644e9Sflorian 			    region, key, key_len - 1, val, val_len);
1165063644e9Sflorian 
1166063644e9Sflorian 		zc_error_prev_line( "SvcParam syntax error in param: %s\"%s\""
1167063644e9Sflorian 		                  , key, val);
1168063644e9Sflorian 	}
1169063644e9Sflorian 	assert(val == NULL);
1170063644e9Sflorian 	if ((eq = memchr(key, '=', key_len))) {
1171063644e9Sflorian 		size_t new_key_len = eq - key;
1172063644e9Sflorian 
1173063644e9Sflorian 		if (key_len - new_key_len - 1 > 0)
1174063644e9Sflorian 			return zparser_conv_svcbparam_key_value(region,
1175063644e9Sflorian 			    key, new_key_len, eq+1, key_len - new_key_len - 1);
1176063644e9Sflorian 		key_len = new_key_len;
1177063644e9Sflorian 	}
1178063644e9Sflorian 	/* Some SvcParamKeys require values */
1179063644e9Sflorian 	svcparamkey = svcbparam_lookup_key(key, key_len);
1180063644e9Sflorian 	switch (svcparamkey) {
1181063644e9Sflorian 		case SVCB_KEY_MANDATORY:
1182063644e9Sflorian 		case SVCB_KEY_ALPN:
1183063644e9Sflorian 		case SVCB_KEY_PORT:
1184063644e9Sflorian 		case SVCB_KEY_IPV4HINT:
1185063644e9Sflorian 		case SVCB_KEY_IPV6HINT:
1186*de04d855Ssthen 		case SVCB_KEY_DOHPATH:
1187063644e9Sflorian 			if(zone_is_slave(parser->current_zone->opts))
1188063644e9Sflorian 				zc_warning_prev_line("value expected for SvcParam: %s", key);
1189063644e9Sflorian 			else
1190063644e9Sflorian 				zc_error_prev_line("value expected for SvcParam: %s", key);
1191063644e9Sflorian 			break;
1192063644e9Sflorian 		default:
1193063644e9Sflorian 			break;
1194063644e9Sflorian 	}
1195063644e9Sflorian 	/* SvcParam is only a SvcParamKey */
1196063644e9Sflorian 	r = alloc_rdata(region, 2 * sizeof(uint16_t));
1197063644e9Sflorian 	r[1] = htons(svcparamkey);
1198063644e9Sflorian 	r[2] = 0;
1199063644e9Sflorian 	return r;
1200063644e9Sflorian }
1201063644e9Sflorian 
120262ac0c33Sjakob /* Parse an int terminated in the specified range. */
120362ac0c33Sjakob static int
parse_int(const char * str,char ** end,int * result,const char * name,int min,int max)120462ac0c33Sjakob parse_int(const char *str,
120562ac0c33Sjakob 	  char **end,
120662ac0c33Sjakob 	  int *result,
120762ac0c33Sjakob 	  const char *name,
120862ac0c33Sjakob 	  int min,
120962ac0c33Sjakob 	  int max)
121062ac0c33Sjakob {
121162ac0c33Sjakob 	*result = (int) strtol(str, end, 10);
121262ac0c33Sjakob 	if (*result < min || *result > max) {
121362ac0c33Sjakob 		zc_error_prev_line("%s must be within the range [%d .. %d]",
121462ac0c33Sjakob 				   name,
121562ac0c33Sjakob 				   min,
121662ac0c33Sjakob 				   max);
121762ac0c33Sjakob 		return 0;
121862ac0c33Sjakob 	} else {
121962ac0c33Sjakob 		return 1;
122062ac0c33Sjakob 	}
122162ac0c33Sjakob }
122262ac0c33Sjakob 
122362ac0c33Sjakob /* RFC1876 conversion routines */
122462ac0c33Sjakob static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
122562ac0c33Sjakob 				1000000,10000000,100000000,1000000000};
122662ac0c33Sjakob 
122762ac0c33Sjakob /*
122862ac0c33Sjakob  * Converts ascii size/precision X * 10**Y(cm) to 0xXY.
122962ac0c33Sjakob  * Sets the given pointer to the last used character.
123062ac0c33Sjakob  *
123162ac0c33Sjakob  */
123262ac0c33Sjakob static uint8_t
precsize_aton(char * cp,char ** endptr)123362ac0c33Sjakob precsize_aton (char *cp, char **endptr)
123462ac0c33Sjakob {
123562ac0c33Sjakob 	unsigned int mval = 0, cmval = 0;
123662ac0c33Sjakob 	uint8_t retval = 0;
123762ac0c33Sjakob 	int exponent;
123862ac0c33Sjakob 	int mantissa;
123962ac0c33Sjakob 
124082cafdebSmillert 	while (isdigit((unsigned char)*cp))
124162ac0c33Sjakob 		mval = mval * 10 + hexdigit_to_int(*cp++);
124262ac0c33Sjakob 
124362ac0c33Sjakob 	if (*cp == '.') {	/* centimeters */
124462ac0c33Sjakob 		cp++;
124582cafdebSmillert 		if (isdigit((unsigned char)*cp)) {
124662ac0c33Sjakob 			cmval = hexdigit_to_int(*cp++) * 10;
124782cafdebSmillert 			if (isdigit((unsigned char)*cp)) {
124862ac0c33Sjakob 				cmval += hexdigit_to_int(*cp++);
124962ac0c33Sjakob 			}
125062ac0c33Sjakob 		}
125162ac0c33Sjakob 	}
125262ac0c33Sjakob 
125362ac0c33Sjakob 	if(mval >= poweroften[7]) {
1254bfd0b123Sflorian 		assert(poweroften[7] != 0);
125562ac0c33Sjakob 		/* integer overflow possible for *100 */
125662ac0c33Sjakob 		mantissa = mval / poweroften[7];
125762ac0c33Sjakob 		exponent = 9; /* max */
125862ac0c33Sjakob 	}
125962ac0c33Sjakob 	else {
126062ac0c33Sjakob 		cmval = (mval * 100) + cmval;
126162ac0c33Sjakob 
126262ac0c33Sjakob 		for (exponent = 0; exponent < 9; exponent++)
126362ac0c33Sjakob 			if (cmval < poweroften[exponent+1])
126462ac0c33Sjakob 				break;
126562ac0c33Sjakob 
1266bfd0b123Sflorian 		assert(poweroften[exponent] != 0);
126762ac0c33Sjakob 		mantissa = cmval / poweroften[exponent];
126862ac0c33Sjakob 	}
126962ac0c33Sjakob 	if (mantissa > 9)
127062ac0c33Sjakob 		mantissa = 9;
127162ac0c33Sjakob 
127262ac0c33Sjakob 	retval = (mantissa << 4) | exponent;
127362ac0c33Sjakob 
127462ac0c33Sjakob 	if (*cp == 'm') cp++;
127562ac0c33Sjakob 
127662ac0c33Sjakob 	*endptr = cp;
127762ac0c33Sjakob 
127862ac0c33Sjakob 	return (retval);
127962ac0c33Sjakob }
128062ac0c33Sjakob 
128162ac0c33Sjakob /*
128262ac0c33Sjakob  * Parses a specific part of rdata.
128362ac0c33Sjakob  *
128462ac0c33Sjakob  * Returns:
128562ac0c33Sjakob  *
128662ac0c33Sjakob  *	number of elements parsed
128762ac0c33Sjakob  *	zero on error
128862ac0c33Sjakob  *
128962ac0c33Sjakob  */
129062ac0c33Sjakob uint16_t *
zparser_conv_loc(region_type * region,char * str)129162ac0c33Sjakob zparser_conv_loc(region_type *region, char *str)
129262ac0c33Sjakob {
129362ac0c33Sjakob 	uint16_t *r;
129462ac0c33Sjakob 	uint32_t *p;
129562ac0c33Sjakob 	int i;
129662ac0c33Sjakob 	int deg, min, secs;	/* Secs is stored times 1000.  */
129762ac0c33Sjakob 	uint32_t lat = 0, lon = 0, alt = 0;
129862ac0c33Sjakob 	/* encoded defaults: version=0 sz=1m hp=10000m vp=10m */
129962ac0c33Sjakob 	uint8_t vszhpvp[4] = {0, 0x12, 0x16, 0x13};
130062ac0c33Sjakob 	char *start;
130162ac0c33Sjakob 	double d;
130262ac0c33Sjakob 
130362ac0c33Sjakob 	for(;;) {
130462ac0c33Sjakob 		deg = min = secs = 0;
130562ac0c33Sjakob 
130662ac0c33Sjakob 		/* Degrees */
130762ac0c33Sjakob 		if (*str == '\0') {
130862ac0c33Sjakob 			zc_error_prev_line("unexpected end of LOC data");
130962ac0c33Sjakob 			return NULL;
131062ac0c33Sjakob 		}
131162ac0c33Sjakob 
131262ac0c33Sjakob 		if (!parse_int(str, &str, &deg, "degrees", 0, 180))
131362ac0c33Sjakob 			return NULL;
131482cafdebSmillert 		if (!isspace((unsigned char)*str)) {
131562ac0c33Sjakob 			zc_error_prev_line("space expected after degrees");
131662ac0c33Sjakob 			return NULL;
131762ac0c33Sjakob 		}
131862ac0c33Sjakob 		++str;
131962ac0c33Sjakob 
132062ac0c33Sjakob 		/* Minutes? */
132182cafdebSmillert 		if (isdigit((unsigned char)*str)) {
132262ac0c33Sjakob 			if (!parse_int(str, &str, &min, "minutes", 0, 60))
132362ac0c33Sjakob 				return NULL;
132482cafdebSmillert 			if (!isspace((unsigned char)*str)) {
132562ac0c33Sjakob 				zc_error_prev_line("space expected after minutes");
132662ac0c33Sjakob 				return NULL;
132762ac0c33Sjakob 			}
132862ac0c33Sjakob 			++str;
132962ac0c33Sjakob 		}
133062ac0c33Sjakob 
133162ac0c33Sjakob 		/* Seconds? */
133282cafdebSmillert 		if (isdigit((unsigned char)*str)) {
133362ac0c33Sjakob 			start = str;
133462ac0c33Sjakob 			if (!parse_int(str, &str, &i, "seconds", 0, 60)) {
133562ac0c33Sjakob 				return NULL;
133662ac0c33Sjakob 			}
133762ac0c33Sjakob 
133862ac0c33Sjakob 			if (*str == '.' && !parse_int(str + 1, &str, &i, "seconds fraction", 0, 999)) {
133962ac0c33Sjakob 				return NULL;
134062ac0c33Sjakob 			}
134162ac0c33Sjakob 
134282cafdebSmillert 			if (!isspace((unsigned char)*str)) {
134362ac0c33Sjakob 				zc_error_prev_line("space expected after seconds");
134462ac0c33Sjakob 				return NULL;
134562ac0c33Sjakob 			}
134672f0a8e9Ssthen 			/* No need for precision specifiers, it's a double */
134762ac0c33Sjakob 			if (sscanf(start, "%lf", &d) != 1) {
134862ac0c33Sjakob 				zc_error_prev_line("error parsing seconds");
134962ac0c33Sjakob 			}
135062ac0c33Sjakob 
135162ac0c33Sjakob 			if (d < 0.0 || d > 60.0) {
135262ac0c33Sjakob 				zc_error_prev_line("seconds not in range 0.0 .. 60.0");
135362ac0c33Sjakob 			}
135462ac0c33Sjakob 
135562ac0c33Sjakob 			secs = (int) (d * 1000.0 + 0.5);
135662ac0c33Sjakob 			++str;
135762ac0c33Sjakob 		}
135862ac0c33Sjakob 
135962ac0c33Sjakob 		switch(*str) {
136062ac0c33Sjakob 		case 'N':
136162ac0c33Sjakob 		case 'n':
136262ac0c33Sjakob 			lat = ((uint32_t)1<<31) + (deg * 3600000 + min * 60000 + secs);
136362ac0c33Sjakob 			break;
136462ac0c33Sjakob 		case 'E':
136562ac0c33Sjakob 		case 'e':
136662ac0c33Sjakob 			lon = ((uint32_t)1<<31) + (deg * 3600000 + min * 60000 + secs);
136762ac0c33Sjakob 			break;
136862ac0c33Sjakob 		case 'S':
136962ac0c33Sjakob 		case 's':
137062ac0c33Sjakob 			lat = ((uint32_t)1<<31) - (deg * 3600000 + min * 60000 + secs);
137162ac0c33Sjakob 			break;
137262ac0c33Sjakob 		case 'W':
137362ac0c33Sjakob 		case 'w':
137462ac0c33Sjakob 			lon = ((uint32_t)1<<31) - (deg * 3600000 + min * 60000 + secs);
137562ac0c33Sjakob 			break;
137662ac0c33Sjakob 		default:
137762ac0c33Sjakob 			zc_error_prev_line("invalid latitude/longtitude: '%c'", *str);
137862ac0c33Sjakob 			return NULL;
137962ac0c33Sjakob 		}
138062ac0c33Sjakob 		++str;
138162ac0c33Sjakob 
138262ac0c33Sjakob 		if (lat != 0 && lon != 0)
138362ac0c33Sjakob 			break;
138462ac0c33Sjakob 
138582cafdebSmillert 		if (!isspace((unsigned char)*str)) {
138662ac0c33Sjakob 			zc_error_prev_line("space expected after latitude/longitude");
138762ac0c33Sjakob 			return NULL;
138862ac0c33Sjakob 		}
138962ac0c33Sjakob 		++str;
139062ac0c33Sjakob 	}
139162ac0c33Sjakob 
139262ac0c33Sjakob 	/* Altitude */
139362ac0c33Sjakob 	if (*str == '\0') {
139462ac0c33Sjakob 		zc_error_prev_line("unexpected end of LOC data");
139562ac0c33Sjakob 		return NULL;
139662ac0c33Sjakob 	}
139762ac0c33Sjakob 
139882cafdebSmillert 	if (!isspace((unsigned char)*str)) {
139962ac0c33Sjakob 		zc_error_prev_line("space expected before altitude");
140062ac0c33Sjakob 		return NULL;
140162ac0c33Sjakob 	}
140262ac0c33Sjakob 	++str;
140362ac0c33Sjakob 
140462ac0c33Sjakob 	start = str;
140562ac0c33Sjakob 
140662ac0c33Sjakob 	/* Sign */
140762ac0c33Sjakob 	if (*str == '+' || *str == '-') {
140862ac0c33Sjakob 		++str;
140962ac0c33Sjakob 	}
141062ac0c33Sjakob 
141162ac0c33Sjakob 	/* Meters of altitude... */
14126e9bf1eeSflorian 	if(strtol(str, &str, 10) == LONG_MAX) {
14136e9bf1eeSflorian 		zc_error_prev_line("altitude too large, number overflow");
14146e9bf1eeSflorian 		return NULL;
14156e9bf1eeSflorian 	}
141662ac0c33Sjakob 	switch(*str) {
141762ac0c33Sjakob 	case ' ':
141862ac0c33Sjakob 	case '\0':
141962ac0c33Sjakob 	case 'm':
142062ac0c33Sjakob 		break;
142162ac0c33Sjakob 	case '.':
142262ac0c33Sjakob 		if (!parse_int(str + 1, &str, &i, "altitude fraction", 0, 99)) {
142362ac0c33Sjakob 			return NULL;
142462ac0c33Sjakob 		}
142582cafdebSmillert 		if (!isspace((unsigned char)*str) && *str != '\0' && *str != 'm') {
142662ac0c33Sjakob 			zc_error_prev_line("altitude fraction must be a number");
142762ac0c33Sjakob 			return NULL;
142862ac0c33Sjakob 		}
142962ac0c33Sjakob 		break;
143062ac0c33Sjakob 	default:
143162ac0c33Sjakob 		zc_error_prev_line("altitude must be expressed in meters");
143262ac0c33Sjakob 		return NULL;
143362ac0c33Sjakob 	}
143482cafdebSmillert 	if (!isspace((unsigned char)*str) && *str != '\0')
143562ac0c33Sjakob 		++str;
143662ac0c33Sjakob 
143762ac0c33Sjakob 	if (sscanf(start, "%lf", &d) != 1) {
143862ac0c33Sjakob 		zc_error_prev_line("error parsing altitude");
143962ac0c33Sjakob 	}
144062ac0c33Sjakob 
144162ac0c33Sjakob 	alt = (uint32_t) (10000000.0 + d * 100 + 0.5);
144262ac0c33Sjakob 
144382cafdebSmillert 	if (!isspace((unsigned char)*str) && *str != '\0') {
144462ac0c33Sjakob 		zc_error_prev_line("unexpected character after altitude");
144562ac0c33Sjakob 		return NULL;
144662ac0c33Sjakob 	}
144762ac0c33Sjakob 
144862ac0c33Sjakob 	/* Now parse size, horizontal precision and vertical precision if any */
144982cafdebSmillert 	for(i = 1; isspace((unsigned char)*str) && i <= 3; i++) {
145062ac0c33Sjakob 		vszhpvp[i] = precsize_aton(str + 1, &str);
145162ac0c33Sjakob 
145282cafdebSmillert 		if (!isspace((unsigned char)*str) && *str != '\0') {
145362ac0c33Sjakob 			zc_error_prev_line("invalid size or precision");
145462ac0c33Sjakob 			return NULL;
145562ac0c33Sjakob 		}
145662ac0c33Sjakob 	}
145762ac0c33Sjakob 
145862ac0c33Sjakob 	/* Allocate required space... */
145962ac0c33Sjakob 	r = alloc_rdata(region, 16);
146062ac0c33Sjakob 	p = (uint32_t *) (r + 1);
146162ac0c33Sjakob 
146262ac0c33Sjakob 	memmove(p, vszhpvp, 4);
146362ac0c33Sjakob 	write_uint32(p + 1, lat);
146462ac0c33Sjakob 	write_uint32(p + 2, lon);
146562ac0c33Sjakob 	write_uint32(p + 3, alt);
146662ac0c33Sjakob 
146762ac0c33Sjakob 	return r;
146862ac0c33Sjakob }
146962ac0c33Sjakob 
147062ac0c33Sjakob /*
147162ac0c33Sjakob  * Convert an APL RR RDATA element.
147262ac0c33Sjakob  */
147362ac0c33Sjakob uint16_t *
zparser_conv_apl_rdata(region_type * region,char * str)147462ac0c33Sjakob zparser_conv_apl_rdata(region_type *region, char *str)
147562ac0c33Sjakob {
147662ac0c33Sjakob 	int negated = 0;
147762ac0c33Sjakob 	uint16_t address_family;
147862ac0c33Sjakob 	uint8_t prefix;
147962ac0c33Sjakob 	uint8_t maximum_prefix;
148062ac0c33Sjakob 	uint8_t length;
148162ac0c33Sjakob 	uint8_t address[IP6ADDRLEN];
148262ac0c33Sjakob 	char *colon = strchr(str, ':');
148362ac0c33Sjakob 	char *slash = strchr(str, '/');
148462ac0c33Sjakob 	int af;
148562ac0c33Sjakob 	int rc;
148662ac0c33Sjakob 	uint16_t rdlength;
148762ac0c33Sjakob 	uint16_t *r;
148862ac0c33Sjakob 	uint8_t *t;
148962ac0c33Sjakob 	char *end;
149062ac0c33Sjakob 	long p;
149162ac0c33Sjakob 
149262ac0c33Sjakob 	if (!colon) {
149362ac0c33Sjakob 		zc_error("address family separator is missing");
149462ac0c33Sjakob 		return NULL;
149562ac0c33Sjakob 	}
149662ac0c33Sjakob 	if (!slash) {
149762ac0c33Sjakob 		zc_error("prefix separator is missing");
149862ac0c33Sjakob 		return NULL;
149962ac0c33Sjakob 	}
150062ac0c33Sjakob 
150162ac0c33Sjakob 	*colon = '\0';
150262ac0c33Sjakob 	*slash = '\0';
150362ac0c33Sjakob 
150462ac0c33Sjakob 	if (*str == '!') {
150562ac0c33Sjakob 		negated = 1;
150662ac0c33Sjakob 		++str;
150762ac0c33Sjakob 	}
150862ac0c33Sjakob 
150962ac0c33Sjakob 	if (strcmp(str, "1") == 0) {
151062ac0c33Sjakob 		address_family = htons(1);
151162ac0c33Sjakob 		af = AF_INET;
151262ac0c33Sjakob 		length = sizeof(in_addr_t);
151362ac0c33Sjakob 		maximum_prefix = length * 8;
151462ac0c33Sjakob 	} else if (strcmp(str, "2") == 0) {
151562ac0c33Sjakob 		address_family = htons(2);
151662ac0c33Sjakob 		af = AF_INET6;
151762ac0c33Sjakob 		length = IP6ADDRLEN;
151862ac0c33Sjakob 		maximum_prefix = length * 8;
151962ac0c33Sjakob 	} else {
152062ac0c33Sjakob 		zc_error("invalid address family '%s'", str);
152162ac0c33Sjakob 		return NULL;
152262ac0c33Sjakob 	}
152362ac0c33Sjakob 
152462ac0c33Sjakob 	rc = inet_pton(af, colon + 1, address);
152562ac0c33Sjakob 	if (rc == 0) {
152662ac0c33Sjakob 		zc_error("invalid address '%s'", colon + 1);
152762ac0c33Sjakob 		return NULL;
152862ac0c33Sjakob 	} else if (rc == -1) {
152962ac0c33Sjakob 		zc_error("inet_pton failed: %s", strerror(errno));
153062ac0c33Sjakob 		return NULL;
153162ac0c33Sjakob 	}
153262ac0c33Sjakob 
153362ac0c33Sjakob 	/* Strip trailing zero octets.	*/
153462ac0c33Sjakob 	while (length > 0 && address[length - 1] == 0)
153562ac0c33Sjakob 		--length;
153662ac0c33Sjakob 
153762ac0c33Sjakob 
153862ac0c33Sjakob 	p = strtol(slash + 1, &end, 10);
153962ac0c33Sjakob 	if (p < 0 || p > maximum_prefix) {
154062ac0c33Sjakob 		zc_error("prefix not in the range 0 .. %d", maximum_prefix);
154162ac0c33Sjakob 		return NULL;
154262ac0c33Sjakob 	} else if (*end != '\0') {
154362ac0c33Sjakob 		zc_error("invalid prefix '%s'", slash + 1);
154462ac0c33Sjakob 		return NULL;
154562ac0c33Sjakob 	}
154662ac0c33Sjakob 	prefix = (uint8_t) p;
154762ac0c33Sjakob 
154862ac0c33Sjakob 	rdlength = (sizeof(address_family) + sizeof(prefix) + sizeof(length)
154962ac0c33Sjakob 		    + length);
155062ac0c33Sjakob 	r = alloc_rdata(region, rdlength);
155162ac0c33Sjakob 	t = (uint8_t *) (r + 1);
155262ac0c33Sjakob 
155362ac0c33Sjakob 	memcpy(t, &address_family, sizeof(address_family));
155462ac0c33Sjakob 	t += sizeof(address_family);
155562ac0c33Sjakob 	memcpy(t, &prefix, sizeof(prefix));
155662ac0c33Sjakob 	t += sizeof(prefix);
155762ac0c33Sjakob 	memcpy(t, &length, sizeof(length));
155862ac0c33Sjakob 	if (negated) {
155962ac0c33Sjakob 		*t |= APL_NEGATION_MASK;
156062ac0c33Sjakob 	}
156162ac0c33Sjakob 	t += sizeof(length);
156262ac0c33Sjakob 	memcpy(t, address, length);
156362ac0c33Sjakob 
156462ac0c33Sjakob 	return r;
156562ac0c33Sjakob }
156662ac0c33Sjakob 
156762ac0c33Sjakob /*
156862ac0c33Sjakob  * Below some function that also convert but not to wireformat
156962ac0c33Sjakob  * but to "normal" (int,long,char) types
157062ac0c33Sjakob  */
157162ac0c33Sjakob 
157262ac0c33Sjakob uint32_t
zparser_ttl2int(const char * ttlstr,int * error)157362ac0c33Sjakob zparser_ttl2int(const char *ttlstr, int* error)
157462ac0c33Sjakob {
157562ac0c33Sjakob 	/* convert a ttl value to a integer
157662ac0c33Sjakob 	 * return the ttl in a int
157762ac0c33Sjakob 	 * -1 on error
157862ac0c33Sjakob 	 */
157962ac0c33Sjakob 
158062ac0c33Sjakob 	uint32_t ttl;
158162ac0c33Sjakob 	const char *t;
158262ac0c33Sjakob 
158362ac0c33Sjakob 	ttl = strtottl(ttlstr, &t);
158462ac0c33Sjakob 	if (*t != 0) {
158562ac0c33Sjakob 		zc_error_prev_line("invalid TTL value: %s",ttlstr);
158662ac0c33Sjakob 		*error = 1;
158762ac0c33Sjakob 	}
158862ac0c33Sjakob 
158962ac0c33Sjakob 	return ttl;
159062ac0c33Sjakob }
159162ac0c33Sjakob 
159262ac0c33Sjakob 
159362ac0c33Sjakob void
zadd_rdata_wireformat(uint16_t * data)159462ac0c33Sjakob zadd_rdata_wireformat(uint16_t *data)
159562ac0c33Sjakob {
1596f72b2965Sjakob 	if (parser->current_rr.rdata_count >= MAXRDATALEN) {
159762ac0c33Sjakob 		zc_error_prev_line("too many rdata elements");
159862ac0c33Sjakob 	} else {
159962ac0c33Sjakob 		parser->current_rr.rdatas[parser->current_rr.rdata_count].data
160062ac0c33Sjakob 			= data;
160162ac0c33Sjakob 		++parser->current_rr.rdata_count;
160262ac0c33Sjakob 	}
160362ac0c33Sjakob }
160462ac0c33Sjakob 
1605f72b2965Sjakob /**
1606f72b2965Sjakob  * Used for TXT RR's to grow with undefined number of strings.
1607f72b2965Sjakob  */
1608f72b2965Sjakob void
zadd_rdata_txt_wireformat(uint16_t * data,int first)1609f72b2965Sjakob zadd_rdata_txt_wireformat(uint16_t *data, int first)
1610f72b2965Sjakob {
1611f72b2965Sjakob 	rdata_atom_type *rd;
16128d8f1862Ssthen 	if (parser->current_rr.rdata_count >= MAXRDATALEN) {
16138d8f1862Ssthen 		zc_error_prev_line("too many rdata txt elements");
16148d8f1862Ssthen 		return;
16158d8f1862Ssthen 	}
1616f72b2965Sjakob 
1617f72b2965Sjakob 	/* First STR in str_seq, allocate 65K in first unused rdata
1618f72b2965Sjakob 	 * else find last used rdata */
1619f72b2965Sjakob 	if (first) {
1620f72b2965Sjakob 		rd = &parser->current_rr.rdatas[parser->current_rr.rdata_count];
1621f72b2965Sjakob 		if ((rd->data = (uint16_t *) region_alloc(parser->rr_region,
1622f72b2965Sjakob 			sizeof(uint16_t) + 65535 * sizeof(uint8_t))) == NULL) {
1623f72b2965Sjakob 			zc_error_prev_line("Could not allocate memory for TXT RR");
1624f72b2965Sjakob 			return;
1625f72b2965Sjakob 		}
1626f72b2965Sjakob 		parser->current_rr.rdata_count++;
1627f72b2965Sjakob 		rd->data[0] = 0;
1628f72b2965Sjakob 	}
1629f72b2965Sjakob 	else
1630f72b2965Sjakob 		rd = &parser->current_rr.rdatas[parser->current_rr.rdata_count-1];
1631f72b2965Sjakob 
1632f72b2965Sjakob 	if ((size_t)rd->data[0] + (size_t)data[0] > 65535) {
1633f72b2965Sjakob 		zc_error_prev_line("too large rdata element");
1634f72b2965Sjakob 		return;
1635f72b2965Sjakob 	}
1636f72b2965Sjakob 
1637f72b2965Sjakob 	memcpy((uint8_t *)rd->data + 2 + rd->data[0], data + 1, data[0]);
1638f72b2965Sjakob 	rd->data[0] += data[0];
1639f72b2965Sjakob }
1640f72b2965Sjakob 
1641f72b2965Sjakob /**
1642f72b2965Sjakob  * Clean up after last call of zadd_rdata_txt_wireformat
1643f72b2965Sjakob  */
1644f72b2965Sjakob void
zadd_rdata_txt_clean_wireformat()1645f72b2965Sjakob zadd_rdata_txt_clean_wireformat()
1646f72b2965Sjakob {
1647f72b2965Sjakob 	uint16_t *tmp_data;
1648f72b2965Sjakob 	rdata_atom_type *rd = &parser->current_rr.rdatas[parser->current_rr.rdata_count-1];
16498d8f1862Ssthen 	if(!rd || !rd->data)
16508d8f1862Ssthen 		return; /* previous syntax failure */
1651f72b2965Sjakob 	if ((tmp_data = (uint16_t *) region_alloc(parser->region,
16528d8f1862Ssthen 		((size_t)rd->data[0]) + ((size_t)2))) != NULL) {
1653f72b2965Sjakob 		memcpy(tmp_data, rd->data, rd->data[0] + 2);
1654dd5b221eSsthen 		/* rd->data of u16+65535 freed when rr_region is freed */
1655f72b2965Sjakob 		rd->data = tmp_data;
1656f72b2965Sjakob 	}
1657f72b2965Sjakob 	else {
1658f72b2965Sjakob 		/* We could not get memory in non-volatile region */
1659f72b2965Sjakob 		zc_error_prev_line("could not allocate memory for rdata");
1660f72b2965Sjakob 		return;
1661f72b2965Sjakob 	}
1662f72b2965Sjakob }
1663f72b2965Sjakob 
1664063644e9Sflorian static int
svcparam_key_cmp(const void * a,const void * b)1665063644e9Sflorian svcparam_key_cmp(const void *a, const void *b)
1666063644e9Sflorian {
1667063644e9Sflorian 	return ((int)read_uint16(rdata_atom_data(*(rdata_atom_type *)a)))
1668063644e9Sflorian 	     - ((int)read_uint16(rdata_atom_data(*(rdata_atom_type *)b)));
1669063644e9Sflorian }
1670063644e9Sflorian 
1671063644e9Sflorian void
zadd_rdata_svcb_check_wireformat()1672063644e9Sflorian zadd_rdata_svcb_check_wireformat()
1673063644e9Sflorian {
1674063644e9Sflorian 	size_t i;
1675063644e9Sflorian 	uint8_t paramkeys[65536];
1676063644e9Sflorian 	int prev_key = - 1;
1677063644e9Sflorian 	int key = 0;
1678063644e9Sflorian 	size_t size;
1679063644e9Sflorian 	uint16_t *mandatory_values;
1680063644e9Sflorian 
1681063644e9Sflorian 	if (parser->current_rr.rdata_count <= 2) {
1682063644e9Sflorian 		if (!parser->error_occurred)
1683063644e9Sflorian 			zc_error_prev_line("invalid SVCB or HTTPS rdata");
1684063644e9Sflorian 		return;
1685063644e9Sflorian 	} else for (i = 2; i < parser->current_rr.rdata_count; i++) {
1686063644e9Sflorian 		if (parser->current_rr.rdatas[i].data == NULL
1687063644e9Sflorian 		||  rdata_atom_data(parser->current_rr.rdatas[i]) == NULL
1688063644e9Sflorian 		||  rdata_atom_size(parser->current_rr.rdatas[i]) < 4) {
1689063644e9Sflorian 			if (!parser->error_occurred)
1690063644e9Sflorian 				zc_error_prev_line("invalid SVCB or HTTPS rdata");
1691063644e9Sflorian 			return;
1692063644e9Sflorian 		}
1693063644e9Sflorian 	}
1694063644e9Sflorian 	/* After this point, all rdatas do have data larger than 4 bytes.
1695063644e9Sflorian 	 * So we may assume a uint16_t SVCB key followed by uint16_t length
1696063644e9Sflorian 	 * in each rdata in the remainder of this function.
1697063644e9Sflorian 	 */
1698063644e9Sflorian 	memset(paramkeys, 0, sizeof(paramkeys));
1699063644e9Sflorian 	/*
1700063644e9Sflorian 	 * In draft-ietf-dnsop-svcb-https-04 Section 7:
1701063644e9Sflorian 	 * In wire format, the keys are represented by their numeric values in
1702063644e9Sflorian 	 * network byte order, concatenated in ascending order.
1703063644e9Sflorian 	 *
1704063644e9Sflorian 	 * svcparam_key_cmp assumes the rdatas to have a SVCB key, which is
1705063644e9Sflorian 	 * safe because we checked.
1706063644e9Sflorian 	 *
1707063644e9Sflorian 	 */
1708063644e9Sflorian 	qsort( (void *)&parser->current_rr.rdatas[2]
1709063644e9Sflorian 	     , parser->current_rr.rdata_count - 2
1710063644e9Sflorian 	     , sizeof(rdata_atom_type)
1711063644e9Sflorian 	     , svcparam_key_cmp
1712063644e9Sflorian 	     );
1713063644e9Sflorian 
1714063644e9Sflorian 	for (i = 2; i < parser->current_rr.rdata_count; i++) {
1715063644e9Sflorian 		assert(parser->current_rr.rdatas[i].data);
1716063644e9Sflorian 		assert(rdata_atom_data(parser->current_rr.rdatas[i]));
1717063644e9Sflorian 		assert(rdata_atom_size(parser->current_rr.rdatas[i]) >= sizeof(uint16_t));
1718063644e9Sflorian 
1719063644e9Sflorian 		key = read_uint16(rdata_atom_data(parser->current_rr.rdatas[i]));
1720063644e9Sflorian 
1721063644e9Sflorian 		/* In draft-ietf-dnsop-svcb-https-04 Section 7:
1722063644e9Sflorian 		 *
1723063644e9Sflorian 		 *     Keys (...) MUST NOT appear more than once.
1724063644e9Sflorian 		 *
1725063644e9Sflorian 		 * If they key has already been seen, we have a duplicate
1726063644e9Sflorian 		 */
1727063644e9Sflorian 		if (!paramkeys[key])
1728063644e9Sflorian 			/* keep track of keys that are present */
1729063644e9Sflorian 			paramkeys[key] = 1;
1730063644e9Sflorian 
1731063644e9Sflorian 		else if (key < SVCPARAMKEY_COUNT) {
1732063644e9Sflorian 			if(zone_is_slave(parser->current_zone->opts))
1733063644e9Sflorian 				zc_warning_prev_line(
1734063644e9Sflorian 					"Duplicate key found: %s",
1735063644e9Sflorian 					svcparamkey_strs[key]);
1736063644e9Sflorian 			else {
1737063644e9Sflorian 				zc_error_prev_line(
1738063644e9Sflorian 					"Duplicate key found: %s",
1739063644e9Sflorian 					svcparamkey_strs[key]);
1740063644e9Sflorian 			}
1741063644e9Sflorian 		} else if(zone_is_slave(parser->current_zone->opts))
1742063644e9Sflorian 			zc_warning_prev_line(
1743063644e9Sflorian 					"Duplicate key found: key%d", key);
1744063644e9Sflorian 		else
1745063644e9Sflorian 			zc_error_prev_line(
1746063644e9Sflorian 					"Duplicate key found: key%d", key);
1747063644e9Sflorian 	}
1748063644e9Sflorian 	/* Checks when a mandatory key is present */
1749063644e9Sflorian 	if (!paramkeys[SVCB_KEY_MANDATORY])
1750063644e9Sflorian 		return;
1751063644e9Sflorian 
1752063644e9Sflorian 	size = rdata_atom_size(parser->current_rr.rdatas[2]);
1753063644e9Sflorian 	assert(size >= 4);
1754063644e9Sflorian 	mandatory_values = (void*)rdata_atom_data(parser->current_rr.rdatas[2]);
1755063644e9Sflorian 	mandatory_values += 2; /* skip the key type and length */
1756063644e9Sflorian 
1757063644e9Sflorian 	if (size % 2)
1758063644e9Sflorian 		zc_error_prev_line("mandatory rdata must be a multiple of shorts");
1759063644e9Sflorian 
1760063644e9Sflorian 	else for (i = 0; i < (size - 4)/2; i++) {
1761063644e9Sflorian 		key = ntohs(mandatory_values[i]);
1762063644e9Sflorian 
1763063644e9Sflorian 		if (paramkeys[key])
1764063644e9Sflorian 			; /* pass */
1765063644e9Sflorian 
1766063644e9Sflorian 		else if (key < SVCPARAMKEY_COUNT) {
1767063644e9Sflorian 			if(zone_is_slave(parser->current_zone->opts))
1768063644e9Sflorian 				zc_warning_prev_line("mandatory SvcParamKey: %s is missing "
1769063644e9Sflorian 						     "the record", svcparamkey_strs[key]);
1770063644e9Sflorian 			else
1771063644e9Sflorian 				zc_error_prev_line("mandatory SvcParamKey: %s is missing "
1772063644e9Sflorian 						   "the record", svcparamkey_strs[key]);
1773063644e9Sflorian 		} else {
1774063644e9Sflorian 			if(zone_is_slave(parser->current_zone->opts))
1775063644e9Sflorian 				zc_warning_prev_line("mandatory SvcParamKey: key%d is missing "
1776063644e9Sflorian 						     "the record", key);
1777063644e9Sflorian 			else
1778063644e9Sflorian 				zc_error_prev_line("mandatory SvcParamKey: key%d is missing "
1779063644e9Sflorian 						   "the record", key);
1780063644e9Sflorian 		}
1781063644e9Sflorian 
1782063644e9Sflorian 		/* In draft-ietf-dnsop-svcb-https-04 Section 8
1783063644e9Sflorian 		 * automatically mandatory MUST NOT appear in its own value-list
1784063644e9Sflorian 		 */
1785063644e9Sflorian 		if (key == SVCB_KEY_MANDATORY) {
1786063644e9Sflorian 			if(zone_is_slave(parser->current_zone->opts))
1787063644e9Sflorian 				zc_warning_prev_line("mandatory MUST not be included"
1788063644e9Sflorian 						     " as mandatory parameter");
1789063644e9Sflorian 			else
1790063644e9Sflorian 				zc_error_prev_line("mandatory MUST not be included"
1791063644e9Sflorian 						   " as mandatory parameter");
1792063644e9Sflorian 		}
1793063644e9Sflorian 		if (key == prev_key) {
1794063644e9Sflorian 			if(zone_is_slave(parser->current_zone->opts))
1795063644e9Sflorian 				zc_warning_prev_line("Keys inSvcParam mandatory "
1796063644e9Sflorian 				                   "MUST NOT appear more than once.");
1797063644e9Sflorian 			else
1798063644e9Sflorian 				zc_error_prev_line("Keys in SvcParam mandatory "
1799063644e9Sflorian 				                   "MUST NOT appear more than once.");
1800063644e9Sflorian 		}
1801063644e9Sflorian 		prev_key = key;
1802063644e9Sflorian 	}
1803063644e9Sflorian }
1804063644e9Sflorian 
180562ac0c33Sjakob void
zadd_rdata_domain(domain_type * domain)180662ac0c33Sjakob zadd_rdata_domain(domain_type *domain)
180762ac0c33Sjakob {
1808f72b2965Sjakob 	if (parser->current_rr.rdata_count >= MAXRDATALEN) {
180962ac0c33Sjakob 		zc_error_prev_line("too many rdata elements");
181062ac0c33Sjakob 	} else {
181162ac0c33Sjakob 		parser->current_rr.rdatas[parser->current_rr.rdata_count].domain
181262ac0c33Sjakob 			= domain;
1813dd5b221eSsthen 		domain->usage ++; /* new reference to domain */
181462ac0c33Sjakob 		++parser->current_rr.rdata_count;
181562ac0c33Sjakob 	}
181662ac0c33Sjakob }
181762ac0c33Sjakob 
181862ac0c33Sjakob void
parse_unknown_rdata(uint16_t type,uint16_t * wireformat)181962ac0c33Sjakob parse_unknown_rdata(uint16_t type, uint16_t *wireformat)
182062ac0c33Sjakob {
182162ac0c33Sjakob 	buffer_type packet;
182262ac0c33Sjakob 	uint16_t size;
182362ac0c33Sjakob 	ssize_t rdata_count;
182462ac0c33Sjakob 	ssize_t i;
182562ac0c33Sjakob 	rdata_atom_type *rdatas;
182662ac0c33Sjakob 
182762ac0c33Sjakob 	if (wireformat) {
182862ac0c33Sjakob 		size = *wireformat;
182962ac0c33Sjakob 	} else {
183062ac0c33Sjakob 		return;
183162ac0c33Sjakob 	}
183262ac0c33Sjakob 
183362ac0c33Sjakob 	buffer_create_from(&packet, wireformat + 1, *wireformat);
183462ac0c33Sjakob 	rdata_count = rdata_wireformat_to_rdata_atoms(parser->region,
183562ac0c33Sjakob 						      parser->db->domains,
183662ac0c33Sjakob 						      type,
183762ac0c33Sjakob 						      size,
183862ac0c33Sjakob 						      &packet,
183962ac0c33Sjakob 						      &rdatas);
184062ac0c33Sjakob 	if (rdata_count == -1) {
184162ac0c33Sjakob 		zc_error_prev_line("bad unknown RDATA");
184262ac0c33Sjakob 		return;
184362ac0c33Sjakob 	}
184462ac0c33Sjakob 
184562ac0c33Sjakob 	for (i = 0; i < rdata_count; ++i) {
184662ac0c33Sjakob 		if (rdata_atom_is_domain(type, i)) {
184762ac0c33Sjakob 			zadd_rdata_domain(rdatas[i].domain);
184862ac0c33Sjakob 		} else {
184962ac0c33Sjakob 			zadd_rdata_wireformat(rdatas[i].data);
185062ac0c33Sjakob 		}
185162ac0c33Sjakob 	}
1852b90bb40eSsthen 	region_recycle(parser->region, rdatas,
1853b90bb40eSsthen 		rdata_count*sizeof(rdata_atom_type));
185462ac0c33Sjakob }
185562ac0c33Sjakob 
185662ac0c33Sjakob 
185762ac0c33Sjakob /*
185862ac0c33Sjakob  * Compares two rdata arrays.
185962ac0c33Sjakob  *
186062ac0c33Sjakob  * Returns:
186162ac0c33Sjakob  *
186262ac0c33Sjakob  *	zero if they are equal
186362ac0c33Sjakob  *	non-zero if not
186462ac0c33Sjakob  *
186562ac0c33Sjakob  */
186662ac0c33Sjakob static int
zrdatacmp(uint16_t type,rr_type * a,rr_type * b)186762ac0c33Sjakob zrdatacmp(uint16_t type, rr_type *a, rr_type *b)
186862ac0c33Sjakob {
186962ac0c33Sjakob 	int i = 0;
187062ac0c33Sjakob 
187162ac0c33Sjakob 	assert(a);
187262ac0c33Sjakob 	assert(b);
187362ac0c33Sjakob 
187462ac0c33Sjakob 	/* One is shorter than another */
187562ac0c33Sjakob 	if (a->rdata_count != b->rdata_count)
187662ac0c33Sjakob 		return 1;
187762ac0c33Sjakob 
187862ac0c33Sjakob 	/* Compare element by element */
187962ac0c33Sjakob 	for (i = 0; i < a->rdata_count; ++i) {
188062ac0c33Sjakob 		if (rdata_atom_is_domain(type, i)) {
188162ac0c33Sjakob 			if (rdata_atom_domain(a->rdatas[i])
188262ac0c33Sjakob 			    != rdata_atom_domain(b->rdatas[i]))
188362ac0c33Sjakob 			{
188462ac0c33Sjakob 				return 1;
188562ac0c33Sjakob 			}
1886dd5b221eSsthen 		} else if(rdata_atom_is_literal_domain(type, i)) {
1887dd5b221eSsthen 			if (rdata_atom_size(a->rdatas[i])
1888dd5b221eSsthen 			    != rdata_atom_size(b->rdatas[i]))
1889dd5b221eSsthen 				return 1;
1890dd5b221eSsthen 			if (!dname_equal_nocase(rdata_atom_data(a->rdatas[i]),
1891dd5b221eSsthen 				   rdata_atom_data(b->rdatas[i]),
1892dd5b221eSsthen 				   rdata_atom_size(a->rdatas[i])))
1893dd5b221eSsthen 				return 1;
189462ac0c33Sjakob 		} else {
189562ac0c33Sjakob 			if (rdata_atom_size(a->rdatas[i])
189662ac0c33Sjakob 			    != rdata_atom_size(b->rdatas[i]))
189762ac0c33Sjakob 			{
189862ac0c33Sjakob 				return 1;
189962ac0c33Sjakob 			}
190062ac0c33Sjakob 			if (memcmp(rdata_atom_data(a->rdatas[i]),
190162ac0c33Sjakob 				   rdata_atom_data(b->rdatas[i]),
190262ac0c33Sjakob 				   rdata_atom_size(a->rdatas[i])) != 0)
190362ac0c33Sjakob 			{
190462ac0c33Sjakob 				return 1;
190562ac0c33Sjakob 			}
190662ac0c33Sjakob 		}
190762ac0c33Sjakob 	}
190862ac0c33Sjakob 
190962ac0c33Sjakob 	/* Otherwise they are equal */
191062ac0c33Sjakob 	return 0;
191162ac0c33Sjakob }
191262ac0c33Sjakob 
191362ac0c33Sjakob /*
191462ac0c33Sjakob  *
191562ac0c33Sjakob  * Opens a zone file.
191662ac0c33Sjakob  *
191762ac0c33Sjakob  * Returns:
191862ac0c33Sjakob  *
191962ac0c33Sjakob  *	- pointer to the parser structure
192062ac0c33Sjakob  *	- NULL on error and errno set
192162ac0c33Sjakob  *
192262ac0c33Sjakob  */
192362ac0c33Sjakob static int
zone_open(const char * filename,uint32_t ttl,uint16_t klass,const dname_type * origin)192462ac0c33Sjakob zone_open(const char *filename, uint32_t ttl, uint16_t klass,
192562ac0c33Sjakob 	  const dname_type *origin)
192662ac0c33Sjakob {
192762ac0c33Sjakob 	/* Open the zone file... */
192862ac0c33Sjakob 	if (strcmp(filename, "-") == 0) {
192962ac0c33Sjakob 		yyin = stdin;
193062ac0c33Sjakob 		filename = "<stdin>";
19313b24e79eSsthen 		warn_if_directory("zonefile from stdin", yyin, filename);
19323b24e79eSsthen 	} else {
19333b24e79eSsthen 		if (!(yyin = fopen(filename, "r"))) {
193462ac0c33Sjakob 			return 0;
193562ac0c33Sjakob 		}
19363b24e79eSsthen 		warn_if_directory("zonefile", yyin, filename);
19373b24e79eSsthen 	}
193862ac0c33Sjakob 
193962ac0c33Sjakob 	zparser_init(filename, ttl, klass, origin);
194062ac0c33Sjakob 
194162ac0c33Sjakob 	return 1;
194262ac0c33Sjakob }
194362ac0c33Sjakob 
194462ac0c33Sjakob 
194562ac0c33Sjakob void
set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE],uint16_t index)194662ac0c33Sjakob set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT][NSEC_WINDOW_BITS_SIZE],
194762ac0c33Sjakob 	    uint16_t index)
194862ac0c33Sjakob {
194962ac0c33Sjakob 	/*
195062ac0c33Sjakob 	 * The bits are counted from left to right, so bit #0 is the
195162ac0c33Sjakob 	 * left most bit.
195262ac0c33Sjakob 	 */
195362ac0c33Sjakob 	uint8_t window = index / 256;
195462ac0c33Sjakob 	uint8_t bit = index % 256;
195562ac0c33Sjakob 
195662ac0c33Sjakob 	bits[window][bit / 8] |= (1 << (7 - bit % 8));
195762ac0c33Sjakob }
195862ac0c33Sjakob 
195962ac0c33Sjakob 
1960dd5b221eSsthen static int
has_soa(domain_type * domain)1961dd5b221eSsthen has_soa(domain_type* domain)
196262ac0c33Sjakob {
1963dd5b221eSsthen 	rrset_type* p = NULL;
1964dd5b221eSsthen 	if(!domain) return 0;
1965dd5b221eSsthen 	for(p = domain->rrsets; p; p = p->next)
1966dd5b221eSsthen 		if(rrset_rrtype(p) == TYPE_SOA)
1967dd5b221eSsthen 			return 1;
1968dd5b221eSsthen 	return 0;
196962ac0c33Sjakob }
197062ac0c33Sjakob 
197162ac0c33Sjakob int
process_rr(void)197262ac0c33Sjakob process_rr(void)
197362ac0c33Sjakob {
197462ac0c33Sjakob 	zone_type *zone = parser->current_zone;
197562ac0c33Sjakob 	rr_type *rr = &parser->current_rr;
197662ac0c33Sjakob 	rrset_type *rrset;
197762ac0c33Sjakob 	size_t max_rdlength;
197862ac0c33Sjakob 	int i;
197962ac0c33Sjakob 	rrtype_descriptor_type *descriptor
198062ac0c33Sjakob 		= rrtype_descriptor_by_type(rr->type);
198162ac0c33Sjakob 
198262ac0c33Sjakob 	/* We only support IN class */
198362ac0c33Sjakob 	if (rr->klass != CLASS_IN) {
1984dd5b221eSsthen 		if(zone_is_slave(zone->opts))
19855bcb494bSjakob 			zc_warning_prev_line("only class IN is supported");
19865bcb494bSjakob 		else
198762ac0c33Sjakob 			zc_error_prev_line("only class IN is supported");
198862ac0c33Sjakob 		return 0;
198962ac0c33Sjakob 	}
199062ac0c33Sjakob 
199162ac0c33Sjakob 	/* Make sure the maximum RDLENGTH does not exceed 65535 bytes.	*/
199262ac0c33Sjakob 	max_rdlength = rdata_maximum_wireformat_size(
199362ac0c33Sjakob 		descriptor, rr->rdata_count, rr->rdatas);
199462ac0c33Sjakob 
199562ac0c33Sjakob 	if (max_rdlength > MAX_RDLENGTH) {
199662ac0c33Sjakob 		zc_error_prev_line("maximum rdata length exceeds %d octets", MAX_RDLENGTH);
199762ac0c33Sjakob 		return 0;
199862ac0c33Sjakob 	}
1999063644e9Sflorian 
2000063644e9Sflorian 	/* We cannot print invalid owner names,
2001063644e9Sflorian 	 * so error on that before it is used in printing other errors.
2002063644e9Sflorian 	 */
2003063644e9Sflorian 	if (rr->owner == error_domain
2004063644e9Sflorian 	||  domain_dname(rr->owner) == error_dname) {
2005063644e9Sflorian 		zc_error_prev_line("invalid owner name");
2006063644e9Sflorian 		return 0;
2007063644e9Sflorian 	}
2008063644e9Sflorian 
2009dd5b221eSsthen 	/* we have the zone already */
2010dd5b221eSsthen 	assert(zone);
201162ac0c33Sjakob 	if (rr->type == TYPE_SOA) {
2012dd5b221eSsthen 		if (rr->owner != zone->apex) {
2013eab1363eSsthen 			char s[MAXDOMAINLEN*5];
2014eab1363eSsthen 			snprintf(s, sizeof(s), "%s", domain_to_string(zone->apex));
2015dd5b221eSsthen 			zc_error_prev_line(
2016eab1363eSsthen 				"SOA record with invalid domain name, '%s' is not '%s'", domain_to_string(rr->owner), s);
2017dd5b221eSsthen 			return 0;
2018dd5b221eSsthen 		}
2019dd5b221eSsthen 		if(has_soa(rr->owner)) {
2020dd5b221eSsthen 			if(zone_is_slave(zone->opts))
20215bcb494bSjakob 				zc_warning_prev_line("this SOA record was already encountered");
20225bcb494bSjakob 			else
202362ac0c33Sjakob 				zc_error_prev_line("this SOA record was already encountered");
2024dd5b221eSsthen 			return 0;
2025dd5b221eSsthen 		}
202662ac0c33Sjakob 		rr->owner->is_apex = 1;
202762ac0c33Sjakob 	}
202862ac0c33Sjakob 
2029dd5b221eSsthen 	if (!domain_is_subdomain(rr->owner, zone->apex))
203062ac0c33Sjakob 	{
2031eab1363eSsthen 		char s[MAXDOMAINLEN*5];
2032eab1363eSsthen 		snprintf(s, sizeof(s), "%s", domain_to_string(zone->apex));
2033dd5b221eSsthen 		if(zone_is_slave(zone->opts))
2034eab1363eSsthen 			zc_warning_prev_line("out of zone data: %s is outside the zone for fqdn %s", domain_to_string(rr->owner), s);
20355bcb494bSjakob 		else
2036eab1363eSsthen 			zc_error_prev_line("out of zone data: %s is outside the zone for fqdn %s", domain_to_string(rr->owner), s);
203762ac0c33Sjakob 		return 0;
203862ac0c33Sjakob 	}
203962ac0c33Sjakob 
204062ac0c33Sjakob 	/* Do we have this type of rrset already? */
204162ac0c33Sjakob 	rrset = domain_find_rrset(rr->owner, zone, rr->type);
204262ac0c33Sjakob 	if (!rrset) {
204362ac0c33Sjakob 		rrset = (rrset_type *) region_alloc(parser->region,
204462ac0c33Sjakob 						    sizeof(rrset_type));
204562ac0c33Sjakob 		rrset->zone = zone;
204662ac0c33Sjakob 		rrset->rr_count = 1;
2047dd5b221eSsthen 		rrset->rrs = (rr_type *) region_alloc(parser->region,
2048dd5b221eSsthen 						      sizeof(rr_type));
204962ac0c33Sjakob 		rrset->rrs[0] = *rr;
205062ac0c33Sjakob 
205162ac0c33Sjakob 		/* Add it */
205262ac0c33Sjakob 		domain_add_rrset(rr->owner, rrset);
205362ac0c33Sjakob 	} else {
2054dd5b221eSsthen 		rr_type* o;
205562ac0c33Sjakob 		if (rr->type != TYPE_RRSIG && rrset->rrs[0].ttl != rr->ttl) {
205662ac0c33Sjakob 			zc_warning_prev_line(
20573126abd5Ssthen 				"%s TTL %u does not match the TTL %u of the %s RRset",
20583126abd5Ssthen 				domain_to_string(rr->owner), (unsigned)rr->ttl,
20593126abd5Ssthen 				(unsigned)rrset->rrs[0].ttl,
20603126abd5Ssthen 				rrtype_to_string(rr->type));
206162ac0c33Sjakob 		}
206262ac0c33Sjakob 
206362ac0c33Sjakob 		/* Search for possible duplicates... */
206462ac0c33Sjakob 		for (i = 0; i < rrset->rr_count; i++) {
206562ac0c33Sjakob 			if (!zrdatacmp(rr->type, rr, &rrset->rrs[i])) {
206662ac0c33Sjakob 				break;
206762ac0c33Sjakob 			}
206862ac0c33Sjakob 		}
206962ac0c33Sjakob 
207062ac0c33Sjakob 		/* Discard the duplicates... */
207162ac0c33Sjakob 		if (i < rrset->rr_count) {
2072eab1363eSsthen 			/* add rdatas to recycle bin. */
2073eab1363eSsthen 			size_t i;
2074eab1363eSsthen 			for (i = 0; i < rr->rdata_count; i++) {
2075eab1363eSsthen 				if(!rdata_atom_is_domain(rr->type, i))
2076eab1363eSsthen 					region_recycle(parser->region, rr->rdatas[i].data,
2077eab1363eSsthen 						rdata_atom_size(rr->rdatas[i])
2078eab1363eSsthen 						+ sizeof(uint16_t));
2079eab1363eSsthen 			}
2080eab1363eSsthen 			region_recycle(parser->region, rr->rdatas,
2081eab1363eSsthen 				sizeof(rdata_atom_type)*rr->rdata_count);
208262ac0c33Sjakob 			return 0;
208362ac0c33Sjakob 		}
20848d8f1862Ssthen 		if(rrset->rr_count == 65535) {
2085e3d8a0a5Ssthen 			zc_error_prev_line("too many RRs for domain RRset");
20868d8f1862Ssthen 			return 0;
20878d8f1862Ssthen 		}
208862ac0c33Sjakob 
208962ac0c33Sjakob 		/* Add it... */
2090dd5b221eSsthen 		o = rrset->rrs;
20918d8f1862Ssthen 		rrset->rrs = (rr_type *) region_alloc_array(parser->region,
20928d8f1862Ssthen 			(rrset->rr_count + 1), sizeof(rr_type));
2093dd5b221eSsthen 		memcpy(rrset->rrs, o, (rrset->rr_count) * sizeof(rr_type));
2094dd5b221eSsthen 		region_recycle(parser->region, o,
2095dd5b221eSsthen 			(rrset->rr_count) * sizeof(rr_type));
209662ac0c33Sjakob 		rrset->rrs[rrset->rr_count] = *rr;
209762ac0c33Sjakob 		++rrset->rr_count;
209862ac0c33Sjakob 	}
209962ac0c33Sjakob 
210062ac0c33Sjakob 	if(rr->type == TYPE_DNAME && rrset->rr_count > 1) {
2101dd5b221eSsthen 		if(zone_is_slave(zone->opts))
21025bcb494bSjakob 			zc_warning_prev_line("multiple DNAMEs at the same name");
21035bcb494bSjakob 		else
210462ac0c33Sjakob 			zc_error_prev_line("multiple DNAMEs at the same name");
210562ac0c33Sjakob 	}
210662ac0c33Sjakob 	if(rr->type == TYPE_CNAME && rrset->rr_count > 1) {
2107dd5b221eSsthen 		if(zone_is_slave(zone->opts))
21085bcb494bSjakob 			zc_warning_prev_line("multiple CNAMEs at the same name");
21095bcb494bSjakob 		else
211062ac0c33Sjakob 			zc_error_prev_line("multiple CNAMEs at the same name");
211162ac0c33Sjakob 	}
211262ac0c33Sjakob 	if((rr->type == TYPE_DNAME && domain_find_rrset(rr->owner, zone, TYPE_CNAME))
211362ac0c33Sjakob 	 ||(rr->type == TYPE_CNAME && domain_find_rrset(rr->owner, zone, TYPE_DNAME))) {
2114dd5b221eSsthen 		if(zone_is_slave(zone->opts))
21155bcb494bSjakob 			zc_warning_prev_line("DNAME and CNAME at the same name");
21165bcb494bSjakob 		else
211762ac0c33Sjakob 			zc_error_prev_line("DNAME and CNAME at the same name");
211862ac0c33Sjakob 	}
211962ac0c33Sjakob 	if(domain_find_rrset(rr->owner, zone, TYPE_CNAME) &&
212062ac0c33Sjakob 		domain_find_non_cname_rrset(rr->owner, zone)) {
2121dd5b221eSsthen 		if(zone_is_slave(zone->opts))
21225bcb494bSjakob 			zc_warning_prev_line("CNAME and other data at the same name");
21235bcb494bSjakob 		else
212462ac0c33Sjakob 			zc_error_prev_line("CNAME and other data at the same name");
212562ac0c33Sjakob 	}
212662ac0c33Sjakob 
212762ac0c33Sjakob 	/* Check we have SOA */
2128dd5b221eSsthen 	if(rr->owner == zone->apex)
2129dd5b221eSsthen 		apex_rrset_checks(parser->db, rrset, rr->owner);
213062ac0c33Sjakob 
2131dd5b221eSsthen 	if(parser->line % ZONEC_PCT_COUNT == 0 && time(NULL) > startzonec + ZONEC_PCT_TIME) {
2132dd5b221eSsthen 		struct stat buf;
2133dd5b221eSsthen 		startzonec = time(NULL);
2134dd5b221eSsthen 		buf.st_size = 0;
2135dd5b221eSsthen 		fstat(fileno(yyin), &buf);
2136dd5b221eSsthen 		if(buf.st_size == 0) buf.st_size = 1;
2137dd5b221eSsthen 		VERBOSITY(1, (LOG_INFO, "parse %s %d %%",
2138dd5b221eSsthen 			parser->current_zone->opts->name,
2139dd5b221eSsthen 			(int)((uint64_t)ftell(yyin)*(uint64_t)100/(uint64_t)buf.st_size)));
214062ac0c33Sjakob 	}
214162ac0c33Sjakob 	++totalrrs;
214262ac0c33Sjakob 	return 1;
214362ac0c33Sjakob }
214462ac0c33Sjakob 
214562ac0c33Sjakob /*
214662ac0c33Sjakob  * Find rrset type for any zone
214762ac0c33Sjakob  */
214862ac0c33Sjakob static rrset_type*
domain_find_rrset_any(domain_type * domain,uint16_t type)214962ac0c33Sjakob domain_find_rrset_any(domain_type *domain, uint16_t type)
215062ac0c33Sjakob {
215162ac0c33Sjakob 	rrset_type *result = domain->rrsets;
215262ac0c33Sjakob 	while (result) {
215362ac0c33Sjakob 		if (rrset_rrtype(result) == type) {
215462ac0c33Sjakob 			return result;
215562ac0c33Sjakob 		}
215662ac0c33Sjakob 		result = result->next;
215762ac0c33Sjakob 	}
215862ac0c33Sjakob 	return NULL;
215962ac0c33Sjakob }
216062ac0c33Sjakob 
216162ac0c33Sjakob /*
216262ac0c33Sjakob  * Check for DNAME type. Nothing is allowed below it
216362ac0c33Sjakob  */
216462ac0c33Sjakob static void
check_dname(zone_type * zone)2165dd5b221eSsthen check_dname(zone_type* zone)
216662ac0c33Sjakob {
216762ac0c33Sjakob 	domain_type* domain;
2168dd5b221eSsthen 	for(domain = zone->apex; domain && domain_is_subdomain(domain,
2169dd5b221eSsthen 		zone->apex); domain=domain_next(domain))
217062ac0c33Sjakob 	{
217162ac0c33Sjakob 		if(domain->is_existing) {
217262ac0c33Sjakob 			/* there may not be DNAMEs above it */
217362ac0c33Sjakob 			domain_type* parent = domain->parent;
217462ac0c33Sjakob #ifdef NSEC3
217562ac0c33Sjakob 			if(domain_has_only_NSEC3(domain, NULL))
217662ac0c33Sjakob 				continue;
217762ac0c33Sjakob #endif
217862ac0c33Sjakob 			while(parent) {
217962ac0c33Sjakob 				if(domain_find_rrset_any(parent, TYPE_DNAME)) {
218062ac0c33Sjakob 					zc_error("While checking node %s,",
2181dd5b221eSsthen 						domain_to_string(domain));
218262ac0c33Sjakob 					zc_error("DNAME at %s has data below it. "
218362ac0c33Sjakob 						"This is not allowed (rfc 2672).",
2184dd5b221eSsthen 						domain_to_string(parent));
2185dd5b221eSsthen 					return;
218662ac0c33Sjakob 				}
218762ac0c33Sjakob 				parent = parent->parent;
218862ac0c33Sjakob 			}
218962ac0c33Sjakob 		}
219062ac0c33Sjakob 	}
219162ac0c33Sjakob }
219262ac0c33Sjakob 
219362ac0c33Sjakob /*
219462ac0c33Sjakob  * Reads the specified zone into the memory
219562ac0c33Sjakob  * nsd_options can be NULL if no config file is passed.
219662ac0c33Sjakob  */
2197dd5b221eSsthen unsigned int
zonec_read(const char * name,const char * zonefile,zone_type * zone)2198dd5b221eSsthen zonec_read(const char* name, const char* zonefile, zone_type* zone)
219962ac0c33Sjakob {
220062ac0c33Sjakob 	const dname_type *dname;
220162ac0c33Sjakob 
2202dd5b221eSsthen 	totalrrs = 0;
2203dd5b221eSsthen 	startzonec = time(NULL);
2204dd5b221eSsthen 	parser->errors = 0;
2205dd5b221eSsthen 
22065fab9a23Sbrad 	dname = dname_parse(parser->rr_region, name);
220762ac0c33Sjakob 	if (!dname) {
220862ac0c33Sjakob 		zc_error("incorrect zone name '%s'", name);
22096e9bf1eeSflorian 		return 1;
221062ac0c33Sjakob 	}
221162ac0c33Sjakob 
221262ac0c33Sjakob 	/* Open the zone file */
221362ac0c33Sjakob 	if (!zone_open(zonefile, 3600, CLASS_IN, dname)) {
221462ac0c33Sjakob 		zc_error("cannot open '%s': %s", zonefile, strerror(errno));
22156e9bf1eeSflorian 		return 1;
221662ac0c33Sjakob 	}
2217dd5b221eSsthen 	parser->current_zone = zone;
221862ac0c33Sjakob 
221962ac0c33Sjakob 	/* Parse and process all RRs.  */
222062ac0c33Sjakob 	yyparse();
222162ac0c33Sjakob 
2222dd5b221eSsthen 	/* remove origin if it was unused */
22238d8f1862Ssthen 	if(parser->origin != error_domain)
2224dd5b221eSsthen 		domain_table_deldomain(parser->db, parser->origin);
22255fab9a23Sbrad 	/* rr_region has been emptied by now */
22265fab9a23Sbrad 	dname = dname_parse(parser->rr_region, name);
2227dd5b221eSsthen 
222862ac0c33Sjakob 	/* check if zone file contained a correct SOA record */
2229dd5b221eSsthen 	if (!parser->current_zone) {
2230dd5b221eSsthen 		zc_error("zone configured as '%s' has no content.", name);
2231dd5b221eSsthen 	} else if(!parser->current_zone->soa_rrset ||
2232dd5b221eSsthen 		parser->current_zone->soa_rrset->rr_count == 0) {
2233dd5b221eSsthen 		zc_error("zone configured as '%s' has no SOA record.", name);
2234dd5b221eSsthen 	} else if(dname_compare(domain_dname(
2235dd5b221eSsthen 		parser->current_zone->soa_rrset->rrs[0].owner), dname) != 0) {
223662ac0c33Sjakob 		zc_error("zone configured as '%s', but SOA has owner '%s'.",
2237dd5b221eSsthen 			name, domain_to_string(
2238dd5b221eSsthen 			parser->current_zone->soa_rrset->rrs[0].owner));
223962ac0c33Sjakob 	}
2240b90bb40eSsthen 	region_free_all(parser->rr_region);
224162ac0c33Sjakob 
2242ee5153b7Sflorian 	parser_flush();
224362ac0c33Sjakob 	fclose(yyin);
2244dd5b221eSsthen 	if(!zone_is_slave(zone->opts))
2245dd5b221eSsthen 		check_dname(zone);
224662ac0c33Sjakob 
224762ac0c33Sjakob 	parser->filename = NULL;
2248dd5b221eSsthen 	return parser->errors;
224962ac0c33Sjakob }
225062ac0c33Sjakob 
225162ac0c33Sjakob 
225262ac0c33Sjakob /*
2253dd5b221eSsthen  * setup parse
225462ac0c33Sjakob  */
2255dd5b221eSsthen void
zonec_setup_parser(namedb_type * db)2256dd5b221eSsthen zonec_setup_parser(namedb_type* db)
225762ac0c33Sjakob {
2258dd5b221eSsthen 	region_type* rr_region = region_create(xalloc, free);
2259dd5b221eSsthen 	parser = zparser_create(db->region, rr_region, db);
2260dd5b221eSsthen 	assert(parser);
2261dd5b221eSsthen 	/* Unique pointers used to mark errors.	 */
2262dd5b221eSsthen 	error_dname = (dname_type *) region_alloc(db->region, 1);
2263dd5b221eSsthen 	error_domain = (domain_type *) region_alloc(db->region, 1);
2264dd5b221eSsthen 	/* Open the network database */
2265dd5b221eSsthen 	setprotoent(1);
2266dd5b221eSsthen 	setservent(1);
2267dd5b221eSsthen }
2268dd5b221eSsthen 
2269dd5b221eSsthen /** desetup parse */
2270dd5b221eSsthen void
zonec_desetup_parser(void)2271dd5b221eSsthen zonec_desetup_parser(void)
2272dd5b221eSsthen {
2273dd5b221eSsthen 	if(parser) {
2274dd5b221eSsthen 		endservent();
2275dd5b221eSsthen 		endprotoent();
2276dd5b221eSsthen 		region_destroy(parser->rr_region);
2277dd5b221eSsthen 		/* removed when parser->region(=db->region) is destroyed:
2278dd5b221eSsthen 		 * region_recycle(parser->region, (void*)error_dname, 1);
2279dd5b221eSsthen 		 * region_recycle(parser->region, (void*)error_domain, 1); */
2280dd5b221eSsthen 		/* clear memory for exit, but this is not portable to
2281dd5b221eSsthen 		 * other versions of lex. yylex_destroy(); */
2282b90bb40eSsthen #ifdef MEMCLEAN /* OS collects memory pages */
2283b90bb40eSsthen 		yylex_destroy();
2284b90bb40eSsthen #endif
2285dd5b221eSsthen 	}
2286dd5b221eSsthen }
2287dd5b221eSsthen 
2288dd5b221eSsthen static domain_table_type* orig_domains = NULL;
2289dd5b221eSsthen static region_type* orig_region = NULL;
2290dd5b221eSsthen static region_type* orig_dbregion = NULL;
2291dd5b221eSsthen 
2292dd5b221eSsthen /** setup for string parse */
2293dd5b221eSsthen void
zonec_setup_string_parser(region_type * region,domain_table_type * domains)2294dd5b221eSsthen zonec_setup_string_parser(region_type* region, domain_table_type* domains)
2295dd5b221eSsthen {
2296dd5b221eSsthen 	assert(parser); /* global parser must be setup */
2297dd5b221eSsthen 	orig_domains = parser->db->domains;
2298dd5b221eSsthen 	orig_region = parser->region;
2299dd5b221eSsthen 	orig_dbregion = parser->db->region;
2300dd5b221eSsthen 	parser->region = region;
2301dd5b221eSsthen 	parser->db->region = region;
2302dd5b221eSsthen 	parser->db->domains = domains;
2303dd5b221eSsthen 	zparser_init("string", 3600, CLASS_IN, domain_dname(domains->root));
2304dd5b221eSsthen }
2305dd5b221eSsthen 
2306dd5b221eSsthen /** desetup string parse */
2307dd5b221eSsthen void
zonec_desetup_string_parser(void)2308dd5b221eSsthen zonec_desetup_string_parser(void)
2309dd5b221eSsthen {
2310dd5b221eSsthen 	parser->region = orig_region;
2311dd5b221eSsthen 	parser->db->domains = orig_domains;
2312dd5b221eSsthen 	parser->db->region = orig_dbregion;
2313dd5b221eSsthen }
2314dd5b221eSsthen 
2315dd5b221eSsthen /** parse a string into temporary storage */
2316dd5b221eSsthen int
zonec_parse_string(region_type * region,domain_table_type * domains,zone_type * zone,char * str,domain_type ** parsed,int * num_rrs)2317dd5b221eSsthen zonec_parse_string(region_type* region, domain_table_type* domains,
2318dd5b221eSsthen 	zone_type* zone, char* str, domain_type** parsed, int* num_rrs)
2319dd5b221eSsthen {
2320dd5b221eSsthen 	int errors;
2321dd5b221eSsthen 	zonec_setup_string_parser(region, domains);
2322dd5b221eSsthen 	parser->current_zone = zone;
2323dd5b221eSsthen 	parser->errors = 0;
232462ac0c33Sjakob 	totalrrs = 0;
2325dd5b221eSsthen 	startzonec = time(NULL)+100000; /* disable */
2326dd5b221eSsthen 	parser_push_stringbuf(str);
2327dd5b221eSsthen 	yyparse();
2328dd5b221eSsthen 	parser_pop_stringbuf();
2329dd5b221eSsthen 	errors = parser->errors;
2330dd5b221eSsthen 	*num_rrs = totalrrs;
2331dd5b221eSsthen 	if(*num_rrs == 0)
2332dd5b221eSsthen 		*parsed = NULL;
2333dd5b221eSsthen 	else	*parsed = parser->prev_dname;
2334dd5b221eSsthen 	/* remove origin if it was not used during the parse */
23358d8f1862Ssthen 	if(parser->origin != error_domain)
2336dd5b221eSsthen 		domain_table_deldomain(parser->db, parser->origin);
2337b90bb40eSsthen 	region_free_all(parser->rr_region);
2338dd5b221eSsthen 	zonec_desetup_string_parser();
2339ee5153b7Sflorian 	parser_flush();
2340dd5b221eSsthen 	return errors;
234162ac0c33Sjakob }
2342eab1363eSsthen 
2343eab1363eSsthen /** check SSHFP type for failures and emit warnings */
check_sshfp(void)2344eab1363eSsthen void check_sshfp(void)
2345eab1363eSsthen {
2346eab1363eSsthen 	uint8_t hash;
2347eab1363eSsthen 	uint16_t size;
2348eab1363eSsthen 	if(parser->current_rr.rdata_count < 3)
2349eab1363eSsthen 		return; /* cannot check it, too few rdata elements */
2350eab1363eSsthen 	if(!parser->current_rr.rdatas[0].data ||
2351eab1363eSsthen 		!parser->current_rr.rdatas[1].data ||
2352eab1363eSsthen 		!parser->current_rr.rdatas[2].data ||
2353eab1363eSsthen 		!parser->current_rr.owner)
2354eab1363eSsthen 		return; /* cannot check, NULLs (due to earlier errors) */
2355eab1363eSsthen 	if(rdata_atom_size(parser->current_rr.rdatas[1]) != 1)
2356eab1363eSsthen 		return; /* wrong size of the hash type rdata element */
2357eab1363eSsthen 	hash = rdata_atom_data(parser->current_rr.rdatas[1])[0];
2358eab1363eSsthen 	size = rdata_atom_size(parser->current_rr.rdatas[2]);
2359eab1363eSsthen 	if(hash == 1 && size != 20) {
2360eab1363eSsthen 		zc_warning_prev_line("SSHFP %s of type SHA1 has hash of "
2361eab1363eSsthen 			"wrong length, %d bytes, should be 20",
2362eab1363eSsthen 			domain_to_string(parser->current_rr.owner),
2363eab1363eSsthen 			(int)size);
2364eab1363eSsthen 	} else if(hash == 2 && size != 32) {
2365eab1363eSsthen 		zc_warning_prev_line("SSHFP %s of type SHA256 has hash of "
2366eab1363eSsthen 			"wrong length, %d bytes, should be 32",
2367eab1363eSsthen 			domain_to_string(parser->current_rr.owner),
2368eab1363eSsthen 			(int)size);
2369eab1363eSsthen 	}
2370eab1363eSsthen }
23714564029fSflorian 
23724564029fSflorian void
apex_rrset_checks(namedb_type * db,rrset_type * rrset,domain_type * domain)23734564029fSflorian apex_rrset_checks(namedb_type* db, rrset_type* rrset, domain_type* domain)
23744564029fSflorian {
23754564029fSflorian 	uint32_t soa_minimum;
23764564029fSflorian 	unsigned i;
23774564029fSflorian 	zone_type* zone = rrset->zone;
23784564029fSflorian 	assert(domain == zone->apex);
23794564029fSflorian 	(void)domain;
23804564029fSflorian 	if (rrset_rrtype(rrset) == TYPE_SOA) {
23814564029fSflorian 		zone->soa_rrset = rrset;
23824564029fSflorian 
23834564029fSflorian 		/* BUG #103 add another soa with a tweaked ttl */
23844564029fSflorian 		if(zone->soa_nx_rrset == 0) {
23854564029fSflorian 			zone->soa_nx_rrset = region_alloc(db->region,
23864564029fSflorian 				sizeof(rrset_type));
23874564029fSflorian 			zone->soa_nx_rrset->rr_count = 1;
23884564029fSflorian 			zone->soa_nx_rrset->next = 0;
23894564029fSflorian 			zone->soa_nx_rrset->zone = zone;
23904564029fSflorian 			zone->soa_nx_rrset->rrs = region_alloc(db->region,
23914564029fSflorian 				sizeof(rr_type));
23924564029fSflorian 		}
23934564029fSflorian 		memcpy(zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type));
23944564029fSflorian 
23954564029fSflorian 		/* check the ttl and MINIMUM value and set accordingly */
23964564029fSflorian 		memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]),
23974564029fSflorian 				rdata_atom_size(rrset->rrs->rdatas[6]));
23984564029fSflorian 		if (rrset->rrs->ttl > ntohl(soa_minimum)) {
23994564029fSflorian 			zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum);
24004564029fSflorian 		}
24014564029fSflorian 	} else if (rrset_rrtype(rrset) == TYPE_NS) {
24024564029fSflorian 		zone->ns_rrset = rrset;
24034564029fSflorian 	} else if (rrset_rrtype(rrset) == TYPE_RRSIG) {
24044564029fSflorian 		for (i = 0; i < rrset->rr_count; ++i) {
24054564029fSflorian 			if(rr_rrsig_type_covered(&rrset->rrs[i])==TYPE_DNSKEY){
24064564029fSflorian 				zone->is_secure = 1;
24074564029fSflorian 				break;
24084564029fSflorian 			}
24094564029fSflorian 		}
24104564029fSflorian 	}
24114564029fSflorian }
2412