| File: | src/usr.sbin/nsd/zonec.c |
| Warning: | line 1249, column 19 Division by zero |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * zonec.c -- zone compiler. | |||
| 3 | * | |||
| 4 | * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. | |||
| 5 | * | |||
| 6 | * See LICENSE for the license. | |||
| 7 | * | |||
| 8 | */ | |||
| 9 | ||||
| 10 | #include "config.h" | |||
| 11 | ||||
| 12 | #include <assert.h> | |||
| 13 | #include <fcntl.h> | |||
| 14 | #include <ctype.h> | |||
| 15 | #include <errno(*__errno()).h> | |||
| 16 | #include <limits.h> | |||
| 17 | #include <stdio.h> | |||
| 18 | #include <string.h> | |||
| 19 | #ifdef HAVE_STRINGS_H1 | |||
| 20 | #include <strings.h> | |||
| 21 | #endif | |||
| 22 | #include <unistd.h> | |||
| 23 | #include <stdlib.h> | |||
| 24 | #include <time.h> | |||
| 25 | #ifdef HAVE_SYS_STAT_H1 | |||
| 26 | #include <sys/stat.h> | |||
| 27 | #endif | |||
| 28 | ||||
| 29 | #include <netinet/in.h> | |||
| 30 | ||||
| 31 | #ifdef HAVE_NETDB_H1 | |||
| 32 | #include <netdb.h> | |||
| 33 | #endif | |||
| 34 | ||||
| 35 | #include "zonec.h" | |||
| 36 | ||||
| 37 | #include "dname.h" | |||
| 38 | #include "dns.h" | |||
| 39 | #include "namedb.h" | |||
| 40 | #include "rdata.h" | |||
| 41 | #include "region-allocator.h" | |||
| 42 | #include "util.h" | |||
| 43 | #include "zparser.h" | |||
| 44 | #include "options.h" | |||
| 45 | #include "nsec3.h" | |||
| 46 | ||||
| 47 | #define ILNP_MAXDIGITS4 4 | |||
| 48 | #define ILNP_NUMGROUPS4 4 | |||
| 49 | #define SVCB_MAX_COMMA_SEPARATED_VALUES1000 1000 | |||
| 50 | ||||
| 51 | ||||
| 52 | const dname_type *error_dname; | |||
| 53 | domain_type *error_domain; | |||
| 54 | ||||
| 55 | static time_t startzonec = 0; | |||
| 56 | static long int totalrrs = 0; | |||
| 57 | ||||
| 58 | extern uint8_t nsecbits[NSEC_WINDOW_COUNT256][NSEC_WINDOW_BITS_SIZE(256 / 8)]; | |||
| 59 | extern uint16_t nsec_highest_rcode; | |||
| 60 | ||||
| 61 | ||||
| 62 | /* | |||
| 63 | * Allocate SIZE+sizeof(uint16_t) bytes and store SIZE in the first | |||
| 64 | * element. Return a pointer to the allocation. | |||
| 65 | */ | |||
| 66 | static uint16_t * | |||
| 67 | alloc_rdata(region_type *region, size_t size) | |||
| 68 | { | |||
| 69 | uint16_t *result = region_alloc(region, sizeof(uint16_t) + size); | |||
| 70 | *result = size; | |||
| 71 | return result; | |||
| 72 | } | |||
| 73 | ||||
| 74 | uint16_t * | |||
| 75 | alloc_rdata_init(region_type *region, const void *data, size_t size) | |||
| 76 | { | |||
| 77 | uint16_t *result = region_alloc(region, sizeof(uint16_t) + size); | |||
| 78 | *result = size; | |||
| 79 | memcpy(result + 1, data, size); | |||
| 80 | return result; | |||
| 81 | } | |||
| 82 | ||||
| 83 | /* | |||
| 84 | * These are parser function for generic zone file stuff. | |||
| 85 | */ | |||
| 86 | uint16_t * | |||
| 87 | zparser_conv_hex(region_type *region, const char *hex, size_t len) | |||
| 88 | { | |||
| 89 | /* convert a hex value to wireformat */ | |||
| 90 | uint16_t *r = NULL((void*)0); | |||
| 91 | uint8_t *t; | |||
| 92 | int i; | |||
| 93 | ||||
| 94 | if(len == 1 && hex[0] == '0') { | |||
| 95 | /* single 0 represents empty buffer */ | |||
| 96 | return alloc_rdata(region, 0); | |||
| 97 | } | |||
| 98 | if (len % 2 != 0) { | |||
| 99 | zc_error_prev_line("number of hex digits must be a multiple of 2"); | |||
| 100 | } else if (len > MAX_RDLENGTH65535 * 2) { | |||
| 101 | zc_error_prev_line("hex data exceeds maximum rdata length (%d)", | |||
| 102 | MAX_RDLENGTH65535); | |||
| 103 | } else { | |||
| 104 | /* the length part */ | |||
| 105 | r = alloc_rdata(region, len/2); | |||
| 106 | t = (uint8_t *)(r + 1); | |||
| 107 | ||||
| 108 | /* Now process octet by octet... */ | |||
| 109 | while (*hex) { | |||
| 110 | *t = 0; | |||
| 111 | for (i = 16; i >= 1; i -= 15) { | |||
| 112 | if (isxdigit((unsigned char)*hex)) { | |||
| 113 | *t += hexdigit_to_int(*hex) * i; | |||
| 114 | } else { | |||
| 115 | zc_error_prev_line( | |||
| 116 | "illegal hex character '%c'", | |||
| 117 | (int) *hex); | |||
| 118 | return NULL((void*)0); | |||
| 119 | } | |||
| 120 | ++hex; | |||
| 121 | } | |||
| 122 | ++t; | |||
| 123 | } | |||
| 124 | } | |||
| 125 | return r; | |||
| 126 | } | |||
| 127 | ||||
| 128 | /* convert hex, precede by a 1-byte length */ | |||
| 129 | uint16_t * | |||
| 130 | zparser_conv_hex_length(region_type *region, const char *hex, size_t len) | |||
| 131 | { | |||
| 132 | uint16_t *r = NULL((void*)0); | |||
| 133 | uint8_t *t; | |||
| 134 | int i; | |||
| 135 | if (len % 2 != 0) { | |||
| 136 | zc_error_prev_line("number of hex digits must be a multiple of 2"); | |||
| 137 | } else if (len > 255 * 2) { | |||
| 138 | zc_error_prev_line("hex data exceeds 255 bytes"); | |||
| 139 | } else { | |||
| 140 | uint8_t *l; | |||
| 141 | ||||
| 142 | /* the length part */ | |||
| 143 | r = alloc_rdata(region, len/2+1); | |||
| 144 | t = (uint8_t *)(r + 1); | |||
| 145 | ||||
| 146 | l = t++; | |||
| 147 | *l = '\0'; | |||
| 148 | ||||
| 149 | /* Now process octet by octet... */ | |||
| 150 | while (*hex) { | |||
| 151 | *t = 0; | |||
| 152 | for (i = 16; i >= 1; i -= 15) { | |||
| 153 | if (isxdigit((unsigned char)*hex)) { | |||
| 154 | *t += hexdigit_to_int(*hex) * i; | |||
| 155 | } else { | |||
| 156 | zc_error_prev_line( | |||
| 157 | "illegal hex character '%c'", | |||
| 158 | (int) *hex); | |||
| 159 | return NULL((void*)0); | |||
| 160 | } | |||
| 161 | ++hex; | |||
| 162 | } | |||
| 163 | ++t; | |||
| 164 | ++*l; | |||
| 165 | } | |||
| 166 | } | |||
| 167 | return r; | |||
| 168 | } | |||
| 169 | ||||
| 170 | uint16_t * | |||
| 171 | zparser_conv_time(region_type *region, const char *time) | |||
| 172 | { | |||
| 173 | /* convert a time YYHM to wireformat */ | |||
| 174 | uint16_t *r = NULL((void*)0); | |||
| 175 | struct tm tm; | |||
| 176 | ||||
| 177 | /* Try to scan the time... */ | |||
| 178 | if (!strptime(time, "%Y%m%d%H%M%S", &tm)) { | |||
| 179 | zc_error_prev_line("date and time is expected"); | |||
| 180 | } else { | |||
| 181 | uint32_t l = htonl(mktime_from_utc(&tm))(__uint32_t)(__builtin_constant_p(mktime_from_utc(&tm)) ? (__uint32_t)(((__uint32_t)(mktime_from_utc(&tm)) & 0xff ) << 24 | ((__uint32_t)(mktime_from_utc(&tm)) & 0xff00) << 8 | ((__uint32_t)(mktime_from_utc(&tm)) & 0xff0000) >> 8 | ((__uint32_t)(mktime_from_utc(& tm)) & 0xff000000) >> 24) : __swap32md(mktime_from_utc (&tm))); | |||
| 182 | r = alloc_rdata_init(region, &l, sizeof(l)); | |||
| 183 | } | |||
| 184 | return r; | |||
| 185 | } | |||
| 186 | ||||
| 187 | uint16_t * | |||
| 188 | zparser_conv_services(region_type *region, const char *protostr, | |||
| 189 | char *servicestr) | |||
| 190 | { | |||
| 191 | /* | |||
| 192 | * Convert a protocol and a list of service port numbers | |||
| 193 | * (separated by spaces) in the rdata to wireformat | |||
| 194 | */ | |||
| 195 | uint16_t *r = NULL((void*)0); | |||
| 196 | uint8_t *p; | |||
| 197 | uint8_t bitmap[65536/8]; | |||
| 198 | char sep[] = " "; | |||
| 199 | char *word; | |||
| 200 | int max_port = -8; | |||
| 201 | /* convert a protocol in the rdata to wireformat */ | |||
| 202 | struct protoent *proto; | |||
| 203 | ||||
| 204 | memset(bitmap, 0, sizeof(bitmap)); | |||
| 205 | ||||
| 206 | proto = getprotobyname(protostr); | |||
| 207 | if (!proto) { | |||
| 208 | proto = getprotobynumber(atoi(protostr)); | |||
| 209 | } | |||
| 210 | if (!proto) { | |||
| 211 | zc_error_prev_line("unknown protocol '%s'", protostr); | |||
| 212 | return NULL((void*)0); | |||
| 213 | } | |||
| 214 | ||||
| 215 | for (word = strtok(servicestr, sep); word; word = strtok(NULL((void*)0), sep)) { | |||
| 216 | struct servent *service; | |||
| 217 | int port; | |||
| 218 | ||||
| 219 | service = getservbyname(word, proto->p_name); | |||
| 220 | if (service) { | |||
| 221 | /* Note: ntohs not ntohl! Strange but true. */ | |||
| 222 | port = ntohs((uint16_t) service->s_port)(__uint16_t)(__builtin_constant_p((uint16_t) service->s_port ) ? (__uint16_t)(((__uint16_t)((uint16_t) service->s_port) & 0xffU) << 8 | ((__uint16_t)((uint16_t) service-> s_port) & 0xff00U) >> 8) : __swap16md((uint16_t) service ->s_port)); | |||
| 223 | } else { | |||
| 224 | char *end; | |||
| 225 | port = strtol(word, &end, 10); | |||
| 226 | if (*end != '\0') { | |||
| 227 | zc_error_prev_line("unknown service '%s' for protocol '%s'", | |||
| 228 | word, protostr); | |||
| 229 | continue; | |||
| 230 | } | |||
| 231 | } | |||
| 232 | ||||
| 233 | if (port < 0 || port > 65535) { | |||
| 234 | zc_error_prev_line("bad port number %d", port); | |||
| 235 | } else { | |||
| 236 | set_bit(bitmap, port); | |||
| 237 | if (port > max_port) | |||
| 238 | max_port = port; | |||
| 239 | } | |||
| 240 | } | |||
| 241 | ||||
| 242 | r = alloc_rdata(region, sizeof(uint8_t) + max_port / 8 + 1); | |||
| 243 | p = (uint8_t *) (r + 1); | |||
| 244 | *p = proto->p_proto; | |||
| 245 | memcpy(p + 1, bitmap, *r-1); | |||
| 246 | ||||
| 247 | return r; | |||
| 248 | } | |||
| 249 | ||||
| 250 | uint16_t * | |||
| 251 | zparser_conv_serial(region_type *region, const char *serialstr) | |||
| 252 | { | |||
| 253 | uint16_t *r = NULL((void*)0); | |||
| 254 | uint32_t serial; | |||
| 255 | const char *t; | |||
| 256 | ||||
| 257 | serial = strtoserial(serialstr, &t); | |||
| 258 | if (*t != '\0') { | |||
| 259 | zc_error_prev_line("serial is expected or serial too big"); | |||
| 260 | } else { | |||
| 261 | serial = htonl(serial)(__uint32_t)(__builtin_constant_p(serial) ? (__uint32_t)(((__uint32_t )(serial) & 0xff) << 24 | ((__uint32_t)(serial) & 0xff00) << 8 | ((__uint32_t)(serial) & 0xff0000) >> 8 | ((__uint32_t)(serial) & 0xff000000) >> 24) : __swap32md (serial)); | |||
| 262 | r = alloc_rdata_init(region, &serial, sizeof(serial)); | |||
| 263 | } | |||
| 264 | return r; | |||
| 265 | } | |||
| 266 | ||||
| 267 | uint16_t * | |||
| 268 | zparser_conv_period(region_type *region, const char *periodstr) | |||
| 269 | { | |||
| 270 | /* convert a time period (think TTL's) to wireformat) */ | |||
| 271 | uint16_t *r = NULL((void*)0); | |||
| 272 | uint32_t period; | |||
| 273 | const char *end; | |||
| 274 | ||||
| 275 | /* Allocate required space... */ | |||
| 276 | period = strtottl(periodstr, &end); | |||
| 277 | if (*end != '\0') { | |||
| 278 | zc_error_prev_line("time period is expected"); | |||
| 279 | } else { | |||
| 280 | period = htonl(period)(__uint32_t)(__builtin_constant_p(period) ? (__uint32_t)(((__uint32_t )(period) & 0xff) << 24 | ((__uint32_t)(period) & 0xff00) << 8 | ((__uint32_t)(period) & 0xff0000) >> 8 | ((__uint32_t)(period) & 0xff000000) >> 24) : __swap32md (period)); | |||
| 281 | r = alloc_rdata_init(region, &period, sizeof(period)); | |||
| 282 | } | |||
| 283 | return r; | |||
| 284 | } | |||
| 285 | ||||
| 286 | uint16_t * | |||
| 287 | zparser_conv_short(region_type *region, const char *text) | |||
| 288 | { | |||
| 289 | uint16_t *r = NULL((void*)0); | |||
| 290 | uint16_t value; | |||
| 291 | char *end; | |||
| 292 | ||||
| 293 | value = htons((uint16_t) strtol(text, &end, 10))(__uint16_t)(__builtin_constant_p((uint16_t) strtol(text, & end, 10)) ? (__uint16_t)(((__uint16_t)((uint16_t) strtol(text , &end, 10)) & 0xffU) << 8 | ((__uint16_t)((uint16_t ) strtol(text, &end, 10)) & 0xff00U) >> 8) : __swap16md ((uint16_t) strtol(text, &end, 10))); | |||
| 294 | if (*end != '\0') { | |||
| 295 | zc_error_prev_line("integer value is expected"); | |||
| 296 | } else { | |||
| 297 | r = alloc_rdata_init(region, &value, sizeof(value)); | |||
| 298 | } | |||
| 299 | return r; | |||
| 300 | } | |||
| 301 | ||||
| 302 | uint16_t * | |||
| 303 | zparser_conv_byte(region_type *region, const char *text) | |||
| 304 | { | |||
| 305 | uint16_t *r = NULL((void*)0); | |||
| 306 | uint8_t value; | |||
| 307 | char *end; | |||
| 308 | ||||
| 309 | value = (uint8_t) strtol(text, &end, 10); | |||
| 310 | if (*end != '\0') { | |||
| 311 | zc_error_prev_line("integer value is expected"); | |||
| 312 | } else { | |||
| 313 | r = alloc_rdata_init(region, &value, sizeof(value)); | |||
| 314 | } | |||
| 315 | return r; | |||
| 316 | } | |||
| 317 | ||||
| 318 | uint16_t * | |||
| 319 | zparser_conv_algorithm(region_type *region, const char *text) | |||
| 320 | { | |||
| 321 | const lookup_table_type *alg; | |||
| 322 | uint8_t id; | |||
| 323 | ||||
| 324 | alg = lookup_by_name(dns_algorithms, text); | |||
| 325 | if (alg) { | |||
| 326 | id = (uint8_t) alg->id; | |||
| 327 | } else { | |||
| 328 | char *end; | |||
| 329 | id = (uint8_t) strtol(text, &end, 10); | |||
| 330 | if (*end != '\0') { | |||
| 331 | zc_error_prev_line("algorithm is expected"); | |||
| 332 | return NULL((void*)0); | |||
| 333 | } | |||
| 334 | } | |||
| 335 | ||||
| 336 | return alloc_rdata_init(region, &id, sizeof(id)); | |||
| 337 | } | |||
| 338 | ||||
| 339 | uint16_t * | |||
| 340 | zparser_conv_certificate_type(region_type *region, const char *text) | |||
| 341 | { | |||
| 342 | /* convert an algorithm string to integer */ | |||
| 343 | const lookup_table_type *type; | |||
| 344 | uint16_t id; | |||
| 345 | ||||
| 346 | type = lookup_by_name(dns_certificate_types, text); | |||
| 347 | if (type) { | |||
| 348 | id = htons((uint16_t) type->id)(__uint16_t)(__builtin_constant_p((uint16_t) type->id) ? ( __uint16_t)(((__uint16_t)((uint16_t) type->id) & 0xffU ) << 8 | ((__uint16_t)((uint16_t) type->id) & 0xff00U ) >> 8) : __swap16md((uint16_t) type->id)); | |||
| 349 | } else { | |||
| 350 | char *end; | |||
| 351 | id = htons((uint16_t) strtol(text, &end, 10))(__uint16_t)(__builtin_constant_p((uint16_t) strtol(text, & end, 10)) ? (__uint16_t)(((__uint16_t)((uint16_t) strtol(text , &end, 10)) & 0xffU) << 8 | ((__uint16_t)((uint16_t ) strtol(text, &end, 10)) & 0xff00U) >> 8) : __swap16md ((uint16_t) strtol(text, &end, 10))); | |||
| 352 | if (*end != '\0') { | |||
| 353 | zc_error_prev_line("certificate type is expected"); | |||
| 354 | return NULL((void*)0); | |||
| 355 | } | |||
| 356 | } | |||
| 357 | ||||
| 358 | return alloc_rdata_init(region, &id, sizeof(id)); | |||
| 359 | } | |||
| 360 | ||||
| 361 | uint16_t * | |||
| 362 | zparser_conv_a(region_type *region, const char *text) | |||
| 363 | { | |||
| 364 | in_addr_t address; | |||
| 365 | uint16_t *r = NULL((void*)0); | |||
| 366 | ||||
| 367 | if (inet_pton(AF_INET2, text, &address) != 1) { | |||
| 368 | zc_error_prev_line("invalid IPv4 address '%s'", text); | |||
| 369 | } else { | |||
| 370 | r = alloc_rdata_init(region, &address, sizeof(address)); | |||
| 371 | } | |||
| 372 | return r; | |||
| 373 | } | |||
| 374 | ||||
| 375 | uint16_t * | |||
| 376 | zparser_conv_aaaa(region_type *region, const char *text) | |||
| 377 | { | |||
| 378 | uint8_t address[IP6ADDRLEN(128/8)]; | |||
| 379 | uint16_t *r = NULL((void*)0); | |||
| 380 | ||||
| 381 | if (inet_pton(AF_INET624, text, address) != 1) { | |||
| 382 | zc_error_prev_line("invalid IPv6 address '%s'", text); | |||
| 383 | } else { | |||
| 384 | r = alloc_rdata_init(region, address, sizeof(address)); | |||
| 385 | } | |||
| 386 | return r; | |||
| 387 | } | |||
| 388 | ||||
| 389 | ||||
| 390 | uint16_t * | |||
| 391 | zparser_conv_ilnp64(region_type *region, const char *text) | |||
| 392 | { | |||
| 393 | uint16_t *r = NULL((void*)0); | |||
| 394 | int ngroups, num; | |||
| 395 | unsigned long hex; | |||
| 396 | const char *ch; | |||
| 397 | char digits[ILNP_MAXDIGITS4+1]; | |||
| 398 | unsigned int ui[ILNP_NUMGROUPS4]; | |||
| 399 | uint16_t a[ILNP_NUMGROUPS4]; | |||
| 400 | ||||
| 401 | ngroups = 1; /* Always at least one group */ | |||
| 402 | num = 0; | |||
| 403 | for (ch = text; *ch != '\0'; ch++) { | |||
| 404 | if (*ch == ':') { | |||
| 405 | if (num <= 0) { | |||
| 406 | zc_error_prev_line("ilnp64: empty group of " | |||
| 407 | "digits is not allowed"); | |||
| 408 | return NULL((void*)0); | |||
| 409 | } | |||
| 410 | digits[num] = '\0'; | |||
| 411 | hex = (unsigned long) strtol(digits, NULL((void*)0), 16); | |||
| 412 | num = 0; | |||
| 413 | ui[ngroups - 1] = hex; | |||
| 414 | if (ngroups >= ILNP_NUMGROUPS4) { | |||
| 415 | zc_error_prev_line("ilnp64: more than %d groups " | |||
| 416 | "of digits", ILNP_NUMGROUPS4); | |||
| 417 | return NULL((void*)0); | |||
| 418 | } | |||
| 419 | ngroups++; | |||
| 420 | } else { | |||
| 421 | /* Our grammar is stricter than the one accepted by | |||
| 422 | * strtol. */ | |||
| 423 | if (!isxdigit((unsigned char)*ch)) { | |||
| 424 | zc_error_prev_line("ilnp64: invalid " | |||
| 425 | "(non-hexadecimal) character %c", *ch); | |||
| 426 | return NULL((void*)0); | |||
| 427 | } | |||
| 428 | if (num >= ILNP_MAXDIGITS4) { | |||
| 429 | zc_error_prev_line("ilnp64: more than %d digits " | |||
| 430 | "in a group", ILNP_MAXDIGITS4); | |||
| 431 | return NULL((void*)0); | |||
| 432 | } | |||
| 433 | digits[num++] = *ch; | |||
| 434 | } | |||
| 435 | } | |||
| 436 | if (num <= 0) { | |||
| 437 | zc_error_prev_line("ilnp64: empty group of digits is not " | |||
| 438 | "allowed"); | |||
| 439 | return NULL((void*)0); | |||
| 440 | } | |||
| 441 | digits[num] = '\0'; | |||
| 442 | hex = (unsigned long) strtol(digits, NULL((void*)0), 16); | |||
| 443 | ui[ngroups - 1] = hex; | |||
| 444 | if (ngroups < 4) { | |||
| 445 | zc_error_prev_line("ilnp64: less than %d groups of digits", | |||
| 446 | ILNP_NUMGROUPS4); | |||
| 447 | return NULL((void*)0); | |||
| 448 | } | |||
| 449 | ||||
| 450 | a[0] = htons(ui[0])(__uint16_t)(__builtin_constant_p(ui[0]) ? (__uint16_t)(((__uint16_t )(ui[0]) & 0xffU) << 8 | ((__uint16_t)(ui[0]) & 0xff00U) >> 8) : __swap16md(ui[0])); | |||
| 451 | a[1] = htons(ui[1])(__uint16_t)(__builtin_constant_p(ui[1]) ? (__uint16_t)(((__uint16_t )(ui[1]) & 0xffU) << 8 | ((__uint16_t)(ui[1]) & 0xff00U) >> 8) : __swap16md(ui[1])); | |||
| 452 | a[2] = htons(ui[2])(__uint16_t)(__builtin_constant_p(ui[2]) ? (__uint16_t)(((__uint16_t )(ui[2]) & 0xffU) << 8 | ((__uint16_t)(ui[2]) & 0xff00U) >> 8) : __swap16md(ui[2])); | |||
| 453 | a[3] = htons(ui[3])(__uint16_t)(__builtin_constant_p(ui[3]) ? (__uint16_t)(((__uint16_t )(ui[3]) & 0xffU) << 8 | ((__uint16_t)(ui[3]) & 0xff00U) >> 8) : __swap16md(ui[3])); | |||
| 454 | r = alloc_rdata_init(region, a, sizeof(a)); | |||
| 455 | return r; | |||
| 456 | } | |||
| 457 | ||||
| 458 | static uint16_t * | |||
| 459 | zparser_conv_eui48(region_type *region, const char *text) | |||
| 460 | { | |||
| 461 | uint8_t nums[6]; | |||
| 462 | uint16_t *r = NULL((void*)0); | |||
| 463 | unsigned int a, b, c, d, e, f; | |||
| 464 | int l; | |||
| 465 | ||||
| 466 | if (sscanf(text, "%2x-%2x-%2x-%2x-%2x-%2x%n", | |||
| 467 | &a, &b, &c, &d, &e, &f, &l) != 6 || | |||
| 468 | l != (int)strlen(text)){ | |||
| 469 | zc_error_prev_line("eui48: invalid rr"); | |||
| 470 | return NULL((void*)0); | |||
| 471 | } | |||
| 472 | nums[0] = (uint8_t)a; | |||
| 473 | nums[1] = (uint8_t)b; | |||
| 474 | nums[2] = (uint8_t)c; | |||
| 475 | nums[3] = (uint8_t)d; | |||
| 476 | nums[4] = (uint8_t)e; | |||
| 477 | nums[5] = (uint8_t)f; | |||
| 478 | r = alloc_rdata_init(region, nums, sizeof(nums)); | |||
| 479 | return r; | |||
| 480 | } | |||
| 481 | ||||
| 482 | static uint16_t * | |||
| 483 | zparser_conv_eui64(region_type *region, const char *text) | |||
| 484 | { | |||
| 485 | uint8_t nums[8]; | |||
| 486 | uint16_t *r = NULL((void*)0); | |||
| 487 | unsigned int a, b, c, d, e, f, g, h; | |||
| 488 | int l; | |||
| 489 | if (sscanf(text, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n", | |||
| 490 | &a, &b, &c, &d, &e, &f, &g, &h, &l) != 8 || | |||
| 491 | l != (int)strlen(text)) { | |||
| 492 | zc_error_prev_line("eui64: invalid rr"); | |||
| 493 | return NULL((void*)0); | |||
| 494 | } | |||
| 495 | nums[0] = (uint8_t)a; | |||
| 496 | nums[1] = (uint8_t)b; | |||
| 497 | nums[2] = (uint8_t)c; | |||
| 498 | nums[3] = (uint8_t)d; | |||
| 499 | nums[4] = (uint8_t)e; | |||
| 500 | nums[5] = (uint8_t)f; | |||
| 501 | nums[6] = (uint8_t)g; | |||
| 502 | nums[7] = (uint8_t)h; | |||
| 503 | r = alloc_rdata_init(region, nums, sizeof(nums)); | |||
| 504 | return r; | |||
| 505 | } | |||
| 506 | ||||
| 507 | uint16_t * | |||
| 508 | zparser_conv_eui(region_type *region, const char *text, size_t len) | |||
| 509 | { | |||
| 510 | uint16_t *r = NULL((void*)0); | |||
| 511 | int nnum, num; | |||
| 512 | const char* ch; | |||
| 513 | ||||
| 514 | nnum = len/8; | |||
| 515 | num = 1; | |||
| 516 | for (ch = text; *ch != '\0'; ch++) { | |||
| 517 | if (*ch == '-') { | |||
| 518 | num++; | |||
| 519 | } else if (!isxdigit((unsigned char)*ch)) { | |||
| 520 | zc_error_prev_line("eui%u: invalid (non-hexadecimal) " | |||
| 521 | "character %c", (unsigned) len, *ch); | |||
| 522 | return NULL((void*)0); | |||
| 523 | } | |||
| 524 | } | |||
| 525 | if (num != nnum) { | |||
| 526 | zc_error_prev_line("eui%u: wrong number of hex numbers", | |||
| 527 | (unsigned) len); | |||
| 528 | return NULL((void*)0); | |||
| 529 | } | |||
| 530 | ||||
| 531 | switch (len) { | |||
| 532 | case 48: | |||
| 533 | r = zparser_conv_eui48(region, text); | |||
| 534 | break; | |||
| 535 | case 64: | |||
| 536 | r = zparser_conv_eui64(region, text); | |||
| 537 | break; | |||
| 538 | default: | |||
| 539 | zc_error_prev_line("eui%u: invalid length", | |||
| 540 | (unsigned) len); | |||
| 541 | return NULL((void*)0); | |||
| 542 | break; | |||
| 543 | } | |||
| 544 | return r; | |||
| 545 | } | |||
| 546 | ||||
| 547 | uint16_t * | |||
| 548 | zparser_conv_text(region_type *region, const char *text, size_t len) | |||
| 549 | { | |||
| 550 | uint16_t *r = NULL((void*)0); | |||
| 551 | uint8_t *p; | |||
| 552 | ||||
| 553 | if (len > 255) { | |||
| 554 | zc_error_prev_line("text string is longer than 255 characters," | |||
| 555 | " try splitting it into multiple parts"); | |||
| 556 | len = 255; | |||
| 557 | } | |||
| 558 | r = alloc_rdata(region, len + 1); | |||
| 559 | p = (uint8_t *) (r + 1); | |||
| 560 | *p = len; | |||
| 561 | memcpy(p + 1, text, len); | |||
| 562 | return r; | |||
| 563 | } | |||
| 564 | ||||
| 565 | /* for CAA Value [RFC 6844] */ | |||
| 566 | uint16_t * | |||
| 567 | zparser_conv_long_text(region_type *region, const char *text, size_t len) | |||
| 568 | { | |||
| 569 | uint16_t *r = NULL((void*)0); | |||
| 570 | if (len > MAX_RDLENGTH65535) { | |||
| 571 | zc_error_prev_line("text string is longer than max rdlen"); | |||
| 572 | return NULL((void*)0); | |||
| 573 | } | |||
| 574 | r = alloc_rdata_init(region, text, len); | |||
| 575 | return r; | |||
| 576 | } | |||
| 577 | ||||
| 578 | /* for CAA Tag [RFC 6844] */ | |||
| 579 | uint16_t * | |||
| 580 | zparser_conv_tag(region_type *region, const char *text, size_t len) | |||
| 581 | { | |||
| 582 | uint16_t *r = NULL((void*)0); | |||
| 583 | uint8_t *p; | |||
| 584 | const char* ptr; | |||
| 585 | ||||
| 586 | if (len < 1) { | |||
| 587 | zc_error_prev_line("invalid tag: zero length"); | |||
| 588 | return NULL((void*)0); | |||
| 589 | } | |||
| 590 | if (len > 15) { | |||
| 591 | zc_error_prev_line("invalid tag %s: longer than 15 characters (%u)", | |||
| 592 | text, (unsigned) len); | |||
| 593 | return NULL((void*)0); | |||
| 594 | } | |||
| 595 | for (ptr = text; *ptr; ptr++) { | |||
| 596 | if (!isdigit((unsigned char)*ptr) && !islower((unsigned char)*ptr)) { | |||
| 597 | zc_error_prev_line("invalid tag %s: contains invalid char %c", | |||
| 598 | text, *ptr); | |||
| 599 | return NULL((void*)0); | |||
| 600 | } | |||
| 601 | } | |||
| 602 | r = alloc_rdata(region, len + 1); | |||
| 603 | p = (uint8_t *) (r + 1); | |||
| 604 | *p = len; | |||
| 605 | memmove(p + 1, text, len); | |||
| 606 | return r; | |||
| 607 | } | |||
| 608 | ||||
| 609 | uint16_t * | |||
| 610 | zparser_conv_dns_name(region_type *region, const uint8_t* name, size_t len) | |||
| 611 | { | |||
| 612 | uint16_t* r = NULL((void*)0); | |||
| 613 | uint8_t* p = NULL((void*)0); | |||
| 614 | r = alloc_rdata(region, len); | |||
| 615 | p = (uint8_t *) (r + 1); | |||
| 616 | memcpy(p, name, len); | |||
| 617 | ||||
| 618 | return r; | |||
| 619 | } | |||
| 620 | ||||
| 621 | uint16_t * | |||
| 622 | zparser_conv_b32(region_type *region, const char *b32) | |||
| 623 | { | |||
| 624 | uint8_t buffer[B64BUFSIZE65535]; | |||
| 625 | uint16_t *r = NULL((void*)0); | |||
| 626 | int i; | |||
| 627 | ||||
| 628 | if(strcmp(b32, "-") == 0) { | |||
| 629 | return alloc_rdata_init(region, "", 1); | |||
| 630 | } | |||
| 631 | i = b32_pton(b32, buffer+1, B64BUFSIZE65535-1); | |||
| 632 | if (i == -1 || i > 255) { | |||
| 633 | zc_error_prev_line("invalid base32 data"); | |||
| 634 | } else { | |||
| 635 | buffer[0] = i; /* store length byte */ | |||
| 636 | r = alloc_rdata_init(region, buffer, i+1); | |||
| 637 | } | |||
| 638 | return r; | |||
| 639 | } | |||
| 640 | ||||
| 641 | uint16_t * | |||
| 642 | zparser_conv_b64(region_type *region, const char *b64) | |||
| 643 | { | |||
| 644 | uint8_t buffer[B64BUFSIZE65535]; | |||
| 645 | uint16_t *r = NULL((void*)0); | |||
| 646 | int i; | |||
| 647 | ||||
| 648 | if(strcmp(b64, "0") == 0) { | |||
| 649 | /* single 0 represents empty buffer */ | |||
| 650 | return alloc_rdata(region, 0); | |||
| 651 | } | |||
| 652 | i = __b64_pton(b64, buffer, B64BUFSIZE65535); | |||
| 653 | if (i == -1) { | |||
| 654 | zc_error_prev_line("invalid base64 data"); | |||
| 655 | } else { | |||
| 656 | r = alloc_rdata_init(region, buffer, i); | |||
| 657 | } | |||
| 658 | return r; | |||
| 659 | } | |||
| 660 | ||||
| 661 | uint16_t * | |||
| 662 | zparser_conv_rrtype(region_type *region, const char *text) | |||
| 663 | { | |||
| 664 | uint16_t *r = NULL((void*)0); | |||
| 665 | uint16_t type = rrtype_from_string(text); | |||
| 666 | ||||
| 667 | if (type == 0) { | |||
| 668 | zc_error_prev_line("unrecognized RR type '%s'", text); | |||
| 669 | } else { | |||
| 670 | type = htons(type)(__uint16_t)(__builtin_constant_p(type) ? (__uint16_t)(((__uint16_t )(type) & 0xffU) << 8 | ((__uint16_t)(type) & 0xff00U ) >> 8) : __swap16md(type)); | |||
| 671 | r = alloc_rdata_init(region, &type, sizeof(type)); | |||
| 672 | } | |||
| 673 | return r; | |||
| 674 | } | |||
| 675 | ||||
| 676 | uint16_t * | |||
| 677 | zparser_conv_nxt(region_type *region, uint8_t nxtbits[]) | |||
| 678 | { | |||
| 679 | /* nxtbits[] consists of 16 bytes with some zero's in it | |||
| 680 | * copy every byte with zero to r and write the length in | |||
| 681 | * the first byte | |||
| 682 | */ | |||
| 683 | uint16_t i; | |||
| 684 | uint16_t last = 0; | |||
| 685 | ||||
| 686 | for (i = 0; i < 16; i++) { | |||
| 687 | if (nxtbits[i] != 0) | |||
| 688 | last = i + 1; | |||
| 689 | } | |||
| 690 | ||||
| 691 | return alloc_rdata_init(region, nxtbits, last); | |||
| 692 | } | |||
| 693 | ||||
| 694 | ||||
| 695 | /* we potentially have 256 windows, each one is numbered. empty ones | |||
| 696 | * should be discarded | |||
| 697 | */ | |||
| 698 | uint16_t * | |||
| 699 | zparser_conv_nsec(region_type *region, | |||
| 700 | uint8_t nsecbits[NSEC_WINDOW_COUNT256][NSEC_WINDOW_BITS_SIZE(256 / 8)]) | |||
| 701 | { | |||
| 702 | /* nsecbits contains up to 64K of bits which represent the | |||
| 703 | * types available for a name. Walk the bits according to | |||
| 704 | * nsec++ draft from jakob | |||
| 705 | */ | |||
| 706 | uint16_t *r; | |||
| 707 | uint8_t *ptr; | |||
| 708 | size_t i,j; | |||
| 709 | uint16_t window_count = 0; | |||
| 710 | uint16_t total_size = 0; | |||
| 711 | uint16_t window_max = 0; | |||
| 712 | ||||
| 713 | /* The used windows. */ | |||
| 714 | int used[NSEC_WINDOW_COUNT256]; | |||
| 715 | /* The last byte used in each the window. */ | |||
| 716 | int size[NSEC_WINDOW_COUNT256]; | |||
| 717 | ||||
| 718 | window_max = 1 + (nsec_highest_rcode / 256); | |||
| 719 | ||||
| 720 | /* used[i] is the i-th window included in the nsec | |||
| 721 | * size[used[0]] is the size of window 0 | |||
| 722 | */ | |||
| 723 | ||||
| 724 | /* walk through the 256 windows */ | |||
| 725 | for (i = 0; i < window_max; ++i) { | |||
| 726 | int empty_window = 1; | |||
| 727 | /* check each of the 32 bytes */ | |||
| 728 | for (j = 0; j < NSEC_WINDOW_BITS_SIZE(256 / 8); ++j) { | |||
| 729 | if (nsecbits[i][j] != 0) { | |||
| 730 | size[i] = j + 1; | |||
| 731 | empty_window = 0; | |||
| 732 | } | |||
| 733 | } | |||
| 734 | if (!empty_window) { | |||
| 735 | used[window_count] = i; | |||
| 736 | window_count++; | |||
| 737 | } | |||
| 738 | } | |||
| 739 | ||||
| 740 | for (i = 0; i < window_count; ++i) { | |||
| 741 | total_size += sizeof(uint16_t) + size[used[i]]; | |||
| 742 | } | |||
| 743 | ||||
| 744 | r = alloc_rdata(region, total_size); | |||
| 745 | ptr = (uint8_t *) (r + 1); | |||
| 746 | ||||
| 747 | /* now walk used and copy it */ | |||
| 748 | for (i = 0; i < window_count; ++i) { | |||
| 749 | ptr[0] = used[i]; | |||
| 750 | ptr[1] = size[used[i]]; | |||
| 751 | memcpy(ptr + 2, &nsecbits[used[i]], size[used[i]]); | |||
| 752 | ptr += size[used[i]] + 2; | |||
| 753 | } | |||
| 754 | ||||
| 755 | return r; | |||
| 756 | } | |||
| 757 | ||||
| 758 | static uint16_t | |||
| 759 | svcbparam_lookup_key(const char *key, size_t key_len) | |||
| 760 | { | |||
| 761 | char buf[64]; | |||
| 762 | char *endptr; | |||
| 763 | unsigned long int key_value; | |||
| 764 | ||||
| 765 | if (key_len >= 4 && key_len <= 8 && !strncmp(key, "key", 3)) { | |||
| 766 | memcpy(buf, key + 3, key_len - 3); | |||
| 767 | buf[key_len - 3] = 0; | |||
| 768 | key_value = strtoul(buf, &endptr, 10); | |||
| 769 | if (endptr > buf /* digits seen */ | |||
| 770 | && *endptr == 0 /* no non-digit chars after digits */ | |||
| 771 | && key_value <= 65535) /* no overflow */ | |||
| 772 | return key_value; | |||
| 773 | ||||
| 774 | } else switch (key_len) { | |||
| 775 | case sizeof("mandatory")-1: | |||
| 776 | if (!strncmp(key, "mandatory", sizeof("mandatory")-1)) | |||
| 777 | return SVCB_KEY_MANDATORY0; | |||
| 778 | if (!strncmp(key, "echconfig", sizeof("echconfig")-1)) | |||
| 779 | return SVCB_KEY_ECH5; /* allow "echconfig as well as "ech" */ | |||
| 780 | break; | |||
| 781 | ||||
| 782 | case sizeof("alpn")-1: | |||
| 783 | if (!strncmp(key, "alpn", sizeof("alpn")-1)) | |||
| 784 | return SVCB_KEY_ALPN1; | |||
| 785 | if (!strncmp(key, "port", sizeof("port")-1)) | |||
| 786 | return SVCB_KEY_PORT3; | |||
| 787 | break; | |||
| 788 | ||||
| 789 | case sizeof("no-default-alpn")-1: | |||
| 790 | if (!strncmp( key , "no-default-alpn" | |||
| 791 | , sizeof("no-default-alpn")-1)) | |||
| 792 | return SVCB_KEY_NO_DEFAULT_ALPN2; | |||
| 793 | break; | |||
| 794 | ||||
| 795 | case sizeof("ipv4hint")-1: | |||
| 796 | if (!strncmp(key, "ipv4hint", sizeof("ipv4hint")-1)) | |||
| 797 | return SVCB_KEY_IPV4HINT4; | |||
| 798 | if (!strncmp(key, "ipv6hint", sizeof("ipv6hint")-1)) | |||
| 799 | return SVCB_KEY_IPV6HINT6; | |||
| 800 | break; | |||
| 801 | case sizeof("ech")-1: | |||
| 802 | if (!strncmp(key, "ech", sizeof("ech")-1)) | |||
| 803 | return SVCB_KEY_ECH5; | |||
| 804 | break; | |||
| 805 | default: | |||
| 806 | break; | |||
| 807 | } | |||
| 808 | if (key_len > sizeof(buf) - 1) | |||
| 809 | zc_error_prev_line("Unknown SvcParamKey"); | |||
| 810 | else { | |||
| 811 | memcpy(buf, key, key_len); | |||
| 812 | buf[key_len] = 0; | |||
| 813 | zc_error_prev_line("Unknown SvcParamKey: %s", buf); | |||
| 814 | } | |||
| 815 | /* Although the returned value might be used by the caller, | |||
| 816 | * the parser has erred, so the zone will not be loaded. | |||
| 817 | */ | |||
| 818 | return -1; | |||
| 819 | } | |||
| 820 | ||||
| 821 | static uint16_t * | |||
| 822 | zparser_conv_svcbparam_port_value(region_type *region, const char *val) | |||
| 823 | { | |||
| 824 | unsigned long int port; | |||
| 825 | char *endptr; | |||
| 826 | uint16_t *r; | |||
| 827 | ||||
| 828 | port = strtoul(val, &endptr, 10); | |||
| 829 | if (endptr > val /* digits seen */ | |||
| 830 | && *endptr == 0 /* no non-digit chars after digits */ | |||
| 831 | && port <= 65535) { /* no overflow */ | |||
| 832 | ||||
| 833 | r = alloc_rdata(region, 3 * sizeof(uint16_t)); | |||
| 834 | r[1] = htons(SVCB_KEY_PORT)(__uint16_t)(__builtin_constant_p(3) ? (__uint16_t)(((__uint16_t )(3) & 0xffU) << 8 | ((__uint16_t)(3) & 0xff00U ) >> 8) : __swap16md(3)); | |||
| 835 | r[2] = htons(sizeof(uint16_t))(__uint16_t)(__builtin_constant_p(sizeof(uint16_t)) ? (__uint16_t )(((__uint16_t)(sizeof(uint16_t)) & 0xffU) << 8 | ( (__uint16_t)(sizeof(uint16_t)) & 0xff00U) >> 8) : __swap16md (sizeof(uint16_t))); | |||
| 836 | r[3] = htons(port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t )(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U ) >> 8) : __swap16md(port)); | |||
| 837 | return r; | |||
| 838 | } | |||
| 839 | zc_error_prev_line("Could not parse port SvcParamValue: \"%s\"", val); | |||
| 840 | return NULL((void*)0); | |||
| 841 | } | |||
| 842 | ||||
| 843 | static uint16_t * | |||
| 844 | zparser_conv_svcbparam_ipv4hint_value(region_type *region, const char *val) | |||
| 845 | { | |||
| 846 | uint16_t *r; | |||
| 847 | int count; | |||
| 848 | char ip_str[INET_ADDRSTRLEN16+1]; | |||
| 849 | char *next_ip_str; | |||
| 850 | uint32_t *ip_wire_dst; | |||
| 851 | size_t i; | |||
| 852 | ||||
| 853 | for (i = 0, count = 1; val[i]; i++) { | |||
| 854 | if (val[i] == ',') | |||
| 855 | count += 1; | |||
| 856 | if (count > SVCB_MAX_COMMA_SEPARATED_VALUES1000) { | |||
| 857 | zc_error_prev_line("Too many IPV4 addresses in ipv4hint"); | |||
| 858 | return NULL((void*)0); | |||
| 859 | } | |||
| 860 | } | |||
| 861 | ||||
| 862 | /* count == number of comma's in val + 1, so the actual number of IPv4 | |||
| 863 | * addresses in val | |||
| 864 | */ | |||
| 865 | r = alloc_rdata(region, 2 * sizeof(uint16_t) + IP4ADDRLEN(32/8) * count); | |||
| 866 | r[1] = htons(SVCB_KEY_IPV4HINT)(__uint16_t)(__builtin_constant_p(4) ? (__uint16_t)(((__uint16_t )(4) & 0xffU) << 8 | ((__uint16_t)(4) & 0xff00U ) >> 8) : __swap16md(4)); | |||
| 867 | r[2] = htons(IP4ADDRLEN * count)(__uint16_t)(__builtin_constant_p((32/8) * count) ? (__uint16_t )(((__uint16_t)((32/8) * count) & 0xffU) << 8 | ((__uint16_t )((32/8) * count) & 0xff00U) >> 8) : __swap16md((32 /8) * count)); | |||
| 868 | ip_wire_dst = (void *)&r[3]; | |||
| 869 | ||||
| 870 | while (count) { | |||
| 871 | if (!(next_ip_str = strchr(val, ','))) { | |||
| 872 | if (inet_pton(AF_INET2, val, ip_wire_dst) != 1) | |||
| 873 | break; | |||
| 874 | ||||
| 875 | assert(count == 1)((void)0); | |||
| 876 | ||||
| 877 | } else if (next_ip_str - val >= (int)sizeof(ip_str)) | |||
| 878 | break; | |||
| 879 | ||||
| 880 | else { | |||
| 881 | memcpy(ip_str, val, next_ip_str - val); | |||
| 882 | ip_str[next_ip_str - val] = 0; | |||
| 883 | if (inet_pton(AF_INET2, ip_str, ip_wire_dst) != 1) { | |||
| 884 | val = ip_str; /* to use in error reporting below */ | |||
| 885 | break; | |||
| 886 | } | |||
| 887 | ||||
| 888 | val = next_ip_str + 1; | |||
| 889 | } | |||
| 890 | ip_wire_dst++; | |||
| 891 | count--; | |||
| 892 | } | |||
| 893 | if (count) | |||
| 894 | zc_error_prev_line("Could not parse ipv4hint SvcParamValue: %s", val); | |||
| 895 | ||||
| 896 | return r; | |||
| 897 | } | |||
| 898 | ||||
| 899 | static uint16_t * | |||
| 900 | zparser_conv_svcbparam_ipv6hint_value(region_type *region, const char *val) | |||
| 901 | { | |||
| 902 | uint16_t *r; | |||
| 903 | int i, count; | |||
| 904 | char ip6_str[INET6_ADDRSTRLEN46+1]; | |||
| 905 | char *next_ip6_str; | |||
| 906 | uint8_t *ipv6_wire_dst; | |||
| 907 | ||||
| 908 | for (i = 0, count = 1; val[i]; i++) { | |||
| 909 | if (val[i] == ',') | |||
| 910 | count += 1; | |||
| 911 | if (count > SVCB_MAX_COMMA_SEPARATED_VALUES1000) { | |||
| 912 | zc_error_prev_line("Too many IPV6 addresses in ipv6hint"); | |||
| 913 | return NULL((void*)0); | |||
| 914 | } | |||
| 915 | } | |||
| 916 | ||||
| 917 | /* count == number of comma's in val + 1 | |||
| 918 | * so actually the number of IPv6 addresses in val | |||
| 919 | */ | |||
| 920 | r = alloc_rdata(region, 2 * sizeof(uint16_t) + IP6ADDRLEN(128/8) * count); | |||
| 921 | r[1] = htons(SVCB_KEY_IPV6HINT)(__uint16_t)(__builtin_constant_p(6) ? (__uint16_t)(((__uint16_t )(6) & 0xffU) << 8 | ((__uint16_t)(6) & 0xff00U ) >> 8) : __swap16md(6)); | |||
| 922 | r[2] = htons(IP6ADDRLEN * count)(__uint16_t)(__builtin_constant_p((128/8) * count) ? (__uint16_t )(((__uint16_t)((128/8) * count) & 0xffU) << 8 | (( __uint16_t)((128/8) * count) & 0xff00U) >> 8) : __swap16md ((128/8) * count)); | |||
| 923 | ipv6_wire_dst = (void *)&r[3]; | |||
| 924 | ||||
| 925 | while (count) { | |||
| 926 | if (!(next_ip6_str = strchr(val, ','))) { | |||
| 927 | if ((inet_pton(AF_INET624, val, ipv6_wire_dst) != 1)) | |||
| 928 | break; | |||
| 929 | ||||
| 930 | assert(count == 1)((void)0); | |||
| 931 | ||||
| 932 | } else if (next_ip6_str - val >= (int)sizeof(ip6_str)) | |||
| 933 | break; | |||
| 934 | ||||
| 935 | else { | |||
| 936 | memcpy(ip6_str, val, next_ip6_str - val); | |||
| 937 | ip6_str[next_ip6_str - val] = 0; | |||
| 938 | if (inet_pton(AF_INET624, ip6_str, ipv6_wire_dst) != 1) { | |||
| 939 | val = ip6_str; /* for error reporting below */ | |||
| 940 | break; | |||
| 941 | } | |||
| 942 | ||||
| 943 | val = next_ip6_str + 1; /* skip the comma */ | |||
| 944 | } | |||
| 945 | ipv6_wire_dst += IP6ADDRLEN(128/8); | |||
| 946 | count--; | |||
| 947 | } | |||
| 948 | if (count) | |||
| 949 | zc_error_prev_line("Could not parse ipv6hint SvcParamValue: %s", val); | |||
| 950 | ||||
| 951 | return r; | |||
| 952 | } | |||
| 953 | ||||
| 954 | static int | |||
| 955 | network_uint16_cmp(const void *a, const void *b) | |||
| 956 | { | |||
| 957 | return ((int)read_uint16(a)) - ((int)read_uint16(b)); | |||
| 958 | } | |||
| 959 | ||||
| 960 | static uint16_t * | |||
| 961 | zparser_conv_svcbparam_mandatory_value(region_type *region, | |||
| 962 | const char *val, size_t val_len) | |||
| 963 | { | |||
| 964 | uint16_t *r; | |||
| 965 | size_t i, count; | |||
| 966 | char* next_key; | |||
| 967 | uint16_t* key_dst; | |||
| 968 | ||||
| 969 | for (i = 0, count = 1; val[i]; i++) { | |||
| 970 | if (val[i] == ',') | |||
| 971 | count += 1; | |||
| 972 | if (count > SVCB_MAX_COMMA_SEPARATED_VALUES1000) { | |||
| 973 | zc_error_prev_line("Too many keys in mandatory"); | |||
| 974 | return NULL((void*)0); | |||
| 975 | } | |||
| 976 | } | |||
| 977 | ||||
| 978 | r = alloc_rdata(region, (2 + count) * sizeof(uint16_t)); | |||
| 979 | r[1] = htons(SVCB_KEY_MANDATORY)(__uint16_t)(__builtin_constant_p(0) ? (__uint16_t)(((__uint16_t )(0) & 0xffU) << 8 | ((__uint16_t)(0) & 0xff00U ) >> 8) : __swap16md(0)); | |||
| 980 | r[2] = htons(sizeof(uint16_t) * count)(__uint16_t)(__builtin_constant_p(sizeof(uint16_t) * count) ? (__uint16_t)(((__uint16_t)(sizeof(uint16_t) * count) & 0xffU ) << 8 | ((__uint16_t)(sizeof(uint16_t) * count) & 0xff00U ) >> 8) : __swap16md(sizeof(uint16_t) * count)); | |||
| 981 | key_dst = (void *)&r[3]; | |||
| 982 | ||||
| 983 | for(;;) { | |||
| 984 | if (!(next_key = strchr(val, ','))) { | |||
| 985 | *key_dst = htons(svcbparam_lookup_key(val, val_len))(__uint16_t)(__builtin_constant_p(svcbparam_lookup_key(val, val_len )) ? (__uint16_t)(((__uint16_t)(svcbparam_lookup_key(val, val_len )) & 0xffU) << 8 | ((__uint16_t)(svcbparam_lookup_key (val, val_len)) & 0xff00U) >> 8) : __swap16md(svcbparam_lookup_key (val, val_len))); | |||
| 986 | break; | |||
| 987 | } else { | |||
| 988 | *key_dst = htons(svcbparam_lookup_key(val, next_key - val))(__uint16_t)(__builtin_constant_p(svcbparam_lookup_key(val, next_key - val)) ? (__uint16_t)(((__uint16_t)(svcbparam_lookup_key(val , next_key - val)) & 0xffU) << 8 | ((__uint16_t)(svcbparam_lookup_key (val, next_key - val)) & 0xff00U) >> 8) : __swap16md (svcbparam_lookup_key(val, next_key - val))); | |||
| 989 | } | |||
| 990 | ||||
| 991 | val_len -= next_key - val + 1; | |||
| 992 | val = next_key + 1; /* skip the comma */ | |||
| 993 | key_dst += 1; | |||
| 994 | } | |||
| 995 | ||||
| 996 | /* In draft-ietf-dnsop-svcb-https-04 Section 7: | |||
| 997 | * | |||
| 998 | * In wire format, the keys are represented by their numeric | |||
| 999 | * values in network byte order, concatenated in ascending order. | |||
| 1000 | */ | |||
| 1001 | qsort((void *)&r[3], count, sizeof(uint16_t), network_uint16_cmp); | |||
| 1002 | ||||
| 1003 | return r; | |||
| 1004 | } | |||
| 1005 | ||||
| 1006 | static uint16_t * | |||
| 1007 | zparser_conv_svcbparam_ech_value(region_type *region, const char *b64) | |||
| 1008 | { | |||
| 1009 | uint8_t buffer[B64BUFSIZE65535]; | |||
| 1010 | uint16_t *r = NULL((void*)0); | |||
| 1011 | int wire_len; | |||
| 1012 | ||||
| 1013 | if(strcmp(b64, "0") == 0) { | |||
| 1014 | /* single 0 represents empty buffer */ | |||
| 1015 | return alloc_rdata(region, 0); | |||
| 1016 | } | |||
| 1017 | wire_len = __b64_pton(b64, buffer, B64BUFSIZE65535); | |||
| 1018 | if (wire_len == -1) { | |||
| 1019 | zc_error_prev_line("invalid base64 data in ech"); | |||
| 1020 | } else { | |||
| 1021 | r = alloc_rdata(region, 2 * sizeof(uint16_t) + wire_len); | |||
| 1022 | r[1] = htons(SVCB_KEY_ECH)(__uint16_t)(__builtin_constant_p(5) ? (__uint16_t)(((__uint16_t )(5) & 0xffU) << 8 | ((__uint16_t)(5) & 0xff00U ) >> 8) : __swap16md(5)); | |||
| 1023 | r[2] = htons(wire_len)(__uint16_t)(__builtin_constant_p(wire_len) ? (__uint16_t)((( __uint16_t)(wire_len) & 0xffU) << 8 | ((__uint16_t) (wire_len) & 0xff00U) >> 8) : __swap16md(wire_len)); | |||
| 1024 | memcpy(&r[3], buffer, wire_len); | |||
| 1025 | } | |||
| 1026 | ||||
| 1027 | return r; | |||
| 1028 | } | |||
| 1029 | ||||
| 1030 | static const char* parse_alpn_next_unescaped_comma(const char *val) | |||
| 1031 | { | |||
| 1032 | while (*val) { | |||
| 1033 | /* Only return when the comma is not escaped*/ | |||
| 1034 | if (*val == '\\'){ | |||
| 1035 | ++val; | |||
| 1036 | if (!*val) | |||
| 1037 | break; | |||
| 1038 | } else if (*val == ',') | |||
| 1039 | return val; | |||
| 1040 | ||||
| 1041 | val++; | |||
| 1042 | } | |||
| 1043 | return NULL((void*)0); | |||
| 1044 | } | |||
| 1045 | ||||
| 1046 | static size_t | |||
| 1047 | parse_alpn_copy_unescaped(uint8_t *dst, const char *src, size_t len) | |||
| 1048 | { | |||
| 1049 | uint8_t *orig_dst = dst; | |||
| 1050 | ||||
| 1051 | while (len) { | |||
| 1052 | if (*src == '\\') { | |||
| 1053 | src++; | |||
| 1054 | len--; | |||
| 1055 | if (!len) | |||
| 1056 | break; | |||
| 1057 | } | |||
| 1058 | *dst++ = *src++; | |||
| 1059 | len--; | |||
| 1060 | } | |||
| 1061 | return (size_t)(dst - orig_dst); | |||
| 1062 | } | |||
| 1063 | ||||
| 1064 | static uint16_t * | |||
| 1065 | zparser_conv_svcbparam_alpn_value(region_type *region, | |||
| 1066 | const char *val, size_t val_len) | |||
| 1067 | { | |||
| 1068 | uint8_t unescaped_dst[65536]; | |||
| 1069 | uint8_t *dst = unescaped_dst; | |||
| 1070 | const char *next_str; | |||
| 1071 | size_t str_len; | |||
| 1072 | size_t dst_len; | |||
| 1073 | uint16_t *r = NULL((void*)0); | |||
| 1074 | ||||
| 1075 | if (val_len > sizeof(unescaped_dst)) { | |||
| 1076 | zc_error_prev_line("invalid alpn"); | |||
| 1077 | return r; | |||
| 1078 | } | |||
| 1079 | while (val_len) { | |||
| 1080 | size_t dst_len; | |||
| 1081 | ||||
| 1082 | str_len = (next_str = parse_alpn_next_unescaped_comma(val)) | |||
| 1083 | ? (size_t)(next_str - val) : val_len; | |||
| 1084 | ||||
| 1085 | if (str_len > 255) { | |||
| 1086 | zc_error_prev_line("alpn strings need to be" | |||
| 1087 | " smaller than 255 chars"); | |||
| 1088 | return r; | |||
| 1089 | } | |||
| 1090 | dst_len = parse_alpn_copy_unescaped(dst + 1, val, str_len); | |||
| 1091 | *dst++ = dst_len; | |||
| 1092 | dst += dst_len; | |||
| 1093 | ||||
| 1094 | if (!next_str) | |||
| 1095 | break; | |||
| 1096 | ||||
| 1097 | /* skip the comma for the next iteration */ | |||
| 1098 | val_len -= next_str - val + 1; | |||
| 1099 | val = next_str + 1; | |||
| 1100 | } | |||
| 1101 | dst_len = dst - unescaped_dst; | |||
| 1102 | r = alloc_rdata(region, 2 * sizeof(uint16_t) + dst_len); | |||
| 1103 | r[1] = htons(SVCB_KEY_ALPN)(__uint16_t)(__builtin_constant_p(1) ? (__uint16_t)(((__uint16_t )(1) & 0xffU) << 8 | ((__uint16_t)(1) & 0xff00U ) >> 8) : __swap16md(1)); | |||
| 1104 | r[2] = htons(dst_len)(__uint16_t)(__builtin_constant_p(dst_len) ? (__uint16_t)(((__uint16_t )(dst_len) & 0xffU) << 8 | ((__uint16_t)(dst_len) & 0xff00U) >> 8) : __swap16md(dst_len)); | |||
| 1105 | memcpy(&r[3], unescaped_dst, dst_len); | |||
| 1106 | return r; | |||
| 1107 | } | |||
| 1108 | ||||
| 1109 | static uint16_t * | |||
| 1110 | zparser_conv_svcbparam_key_value(region_type *region, | |||
| 1111 | const char *key, size_t key_len, const char *val, size_t val_len) | |||
| 1112 | { | |||
| 1113 | uint16_t svcparamkey = svcbparam_lookup_key(key, key_len); | |||
| 1114 | uint16_t *r; | |||
| 1115 | ||||
| 1116 | switch (svcparamkey) { | |||
| 1117 | case SVCB_KEY_PORT3: | |||
| 1118 | return zparser_conv_svcbparam_port_value(region, val); | |||
| 1119 | case SVCB_KEY_IPV4HINT4: | |||
| 1120 | return zparser_conv_svcbparam_ipv4hint_value(region, val); | |||
| 1121 | case SVCB_KEY_IPV6HINT6: | |||
| 1122 | return zparser_conv_svcbparam_ipv6hint_value(region, val); | |||
| 1123 | case SVCB_KEY_MANDATORY0: | |||
| 1124 | return zparser_conv_svcbparam_mandatory_value(region, val, val_len); | |||
| 1125 | case SVCB_KEY_NO_DEFAULT_ALPN2: | |||
| 1126 | if(zone_is_slave(parser->current_zone->opts)) | |||
| 1127 | zc_warning_prev_line("no-default-alpn should not have a value"); | |||
| 1128 | else | |||
| 1129 | zc_error_prev_line("no-default-alpn should not have a value"); | |||
| 1130 | break; | |||
| 1131 | case SVCB_KEY_ECH5: | |||
| 1132 | return zparser_conv_svcbparam_ech_value(region, val); | |||
| 1133 | case SVCB_KEY_ALPN1: | |||
| 1134 | return zparser_conv_svcbparam_alpn_value(region, val, val_len); | |||
| 1135 | default: | |||
| 1136 | break; | |||
| 1137 | } | |||
| 1138 | r = alloc_rdata(region, 2 * sizeof(uint16_t) + val_len); | |||
| 1139 | r[1] = htons(svcparamkey)(__uint16_t)(__builtin_constant_p(svcparamkey) ? (__uint16_t) (((__uint16_t)(svcparamkey) & 0xffU) << 8 | ((__uint16_t )(svcparamkey) & 0xff00U) >> 8) : __swap16md(svcparamkey )); | |||
| 1140 | r[2] = htons(val_len)(__uint16_t)(__builtin_constant_p(val_len) ? (__uint16_t)(((__uint16_t )(val_len) & 0xffU) << 8 | ((__uint16_t)(val_len) & 0xff00U) >> 8) : __swap16md(val_len)); | |||
| 1141 | memcpy(r + 3, val, val_len); | |||
| 1142 | return r; | |||
| 1143 | } | |||
| 1144 | ||||
| 1145 | uint16_t * | |||
| 1146 | zparser_conv_svcbparam(region_type *region, const char *key, size_t key_len | |||
| 1147 | , const char *val, size_t val_len) | |||
| 1148 | { | |||
| 1149 | const char *eq; | |||
| 1150 | uint16_t *r; | |||
| 1151 | uint16_t svcparamkey; | |||
| 1152 | ||||
| 1153 | /* Form <key>="<value>" (or at least with quoted value) */ | |||
| 1154 | if (val && val_len) { | |||
| 1155 | /* Does key end with '=' */ | |||
| 1156 | if (key_len && key[key_len - 1] == '=') | |||
| 1157 | return zparser_conv_svcbparam_key_value( | |||
| 1158 | region, key, key_len - 1, val, val_len); | |||
| 1159 | ||||
| 1160 | zc_error_prev_line( "SvcParam syntax error in param: %s\"%s\"" | |||
| 1161 | , key, val); | |||
| 1162 | } | |||
| 1163 | assert(val == NULL)((void)0); | |||
| 1164 | if ((eq = memchr(key, '=', key_len))) { | |||
| 1165 | size_t new_key_len = eq - key; | |||
| 1166 | ||||
| 1167 | if (key_len - new_key_len - 1 > 0) | |||
| 1168 | return zparser_conv_svcbparam_key_value(region, | |||
| 1169 | key, new_key_len, eq+1, key_len - new_key_len - 1); | |||
| 1170 | key_len = new_key_len; | |||
| 1171 | } | |||
| 1172 | /* Some SvcParamKeys require values */ | |||
| 1173 | svcparamkey = svcbparam_lookup_key(key, key_len); | |||
| 1174 | switch (svcparamkey) { | |||
| 1175 | case SVCB_KEY_MANDATORY0: | |||
| 1176 | case SVCB_KEY_ALPN1: | |||
| 1177 | case SVCB_KEY_PORT3: | |||
| 1178 | case SVCB_KEY_IPV4HINT4: | |||
| 1179 | case SVCB_KEY_IPV6HINT6: | |||
| 1180 | if(zone_is_slave(parser->current_zone->opts)) | |||
| 1181 | zc_warning_prev_line("value expected for SvcParam: %s", key); | |||
| 1182 | else | |||
| 1183 | zc_error_prev_line("value expected for SvcParam: %s", key); | |||
| 1184 | break; | |||
| 1185 | default: | |||
| 1186 | break; | |||
| 1187 | } | |||
| 1188 | /* SvcParam is only a SvcParamKey */ | |||
| 1189 | r = alloc_rdata(region, 2 * sizeof(uint16_t)); | |||
| 1190 | r[1] = htons(svcparamkey)(__uint16_t)(__builtin_constant_p(svcparamkey) ? (__uint16_t) (((__uint16_t)(svcparamkey) & 0xffU) << 8 | ((__uint16_t )(svcparamkey) & 0xff00U) >> 8) : __swap16md(svcparamkey )); | |||
| 1191 | r[2] = 0; | |||
| 1192 | return r; | |||
| 1193 | } | |||
| 1194 | ||||
| 1195 | /* Parse an int terminated in the specified range. */ | |||
| 1196 | static int | |||
| 1197 | parse_int(const char *str, | |||
| 1198 | char **end, | |||
| 1199 | int *result, | |||
| 1200 | const char *name, | |||
| 1201 | int min, | |||
| 1202 | int max) | |||
| 1203 | { | |||
| 1204 | *result = (int) strtol(str, end, 10); | |||
| 1205 | if (*result < min || *result > max) { | |||
| 1206 | zc_error_prev_line("%s must be within the range [%d .. %d]", | |||
| 1207 | name, | |||
| 1208 | min, | |||
| 1209 | max); | |||
| 1210 | return 0; | |||
| 1211 | } else { | |||
| 1212 | return 1; | |||
| 1213 | } | |||
| 1214 | } | |||
| 1215 | ||||
| 1216 | /* RFC1876 conversion routines */ | |||
| 1217 | static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000, | |||
| 1218 | 1000000,10000000,100000000,1000000000}; | |||
| 1219 | ||||
| 1220 | /* | |||
| 1221 | * Converts ascii size/precision X * 10**Y(cm) to 0xXY. | |||
| 1222 | * Sets the given pointer to the last used character. | |||
| 1223 | * | |||
| 1224 | */ | |||
| 1225 | static uint8_t | |||
| 1226 | precsize_aton (char *cp, char **endptr) | |||
| 1227 | { | |||
| 1228 | unsigned int mval = 0, cmval = 0; | |||
| 1229 | uint8_t retval = 0; | |||
| 1230 | int exponent; | |||
| 1231 | int mantissa; | |||
| 1232 | ||||
| 1233 | while (isdigit((unsigned char)*cp)) | |||
| 1234 | mval = mval * 10 + hexdigit_to_int(*cp++); | |||
| 1235 | ||||
| 1236 | if (*cp == '.') { /* centimeters */ | |||
| 1237 | cp++; | |||
| 1238 | if (isdigit((unsigned char)*cp)) { | |||
| 1239 | cmval = hexdigit_to_int(*cp++) * 10; | |||
| 1240 | if (isdigit((unsigned char)*cp)) { | |||
| 1241 | cmval += hexdigit_to_int(*cp++); | |||
| 1242 | } | |||
| 1243 | } | |||
| 1244 | } | |||
| 1245 | ||||
| 1246 | if(mval >= poweroften[7]) { | |||
| 1247 | assert(poweroften[7] != 0)((void)0); | |||
| 1248 | /* integer overflow possible for *100 */ | |||
| 1249 | mantissa = mval / poweroften[7]; | |||
| ||||
| 1250 | exponent = 9; /* max */ | |||
| 1251 | } | |||
| 1252 | else { | |||
| 1253 | cmval = (mval * 100) + cmval; | |||
| 1254 | ||||
| 1255 | for (exponent = 0; exponent < 9; exponent++) | |||
| 1256 | if (cmval < poweroften[exponent+1]) | |||
| 1257 | break; | |||
| 1258 | ||||
| 1259 | assert(poweroften[exponent] != 0)((void)0); | |||
| 1260 | mantissa = cmval / poweroften[exponent]; | |||
| 1261 | } | |||
| 1262 | if (mantissa > 9) | |||
| 1263 | mantissa = 9; | |||
| 1264 | ||||
| 1265 | retval = (mantissa << 4) | exponent; | |||
| 1266 | ||||
| 1267 | if (*cp == 'm') cp++; | |||
| 1268 | ||||
| 1269 | *endptr = cp; | |||
| 1270 | ||||
| 1271 | return (retval); | |||
| 1272 | } | |||
| 1273 | ||||
| 1274 | /* | |||
| 1275 | * Parses a specific part of rdata. | |||
| 1276 | * | |||
| 1277 | * Returns: | |||
| 1278 | * | |||
| 1279 | * number of elements parsed | |||
| 1280 | * zero on error | |||
| 1281 | * | |||
| 1282 | */ | |||
| 1283 | uint16_t * | |||
| 1284 | zparser_conv_loc(region_type *region, char *str) | |||
| 1285 | { | |||
| 1286 | uint16_t *r; | |||
| 1287 | uint32_t *p; | |||
| 1288 | int i; | |||
| 1289 | int deg, min, secs; /* Secs is stored times 1000. */ | |||
| 1290 | uint32_t lat = 0, lon = 0, alt = 0; | |||
| 1291 | /* encoded defaults: version=0 sz=1m hp=10000m vp=10m */ | |||
| 1292 | uint8_t vszhpvp[4] = {0, 0x12, 0x16, 0x13}; | |||
| 1293 | char *start; | |||
| 1294 | double d; | |||
| 1295 | ||||
| 1296 | for(;;) { | |||
| ||||
| 1297 | deg = min = secs = 0; | |||
| 1298 | ||||
| 1299 | /* Degrees */ | |||
| 1300 | if (*str == '\0') { | |||
| 1301 | zc_error_prev_line("unexpected end of LOC data"); | |||
| 1302 | return NULL((void*)0); | |||
| 1303 | } | |||
| 1304 | ||||
| 1305 | if (!parse_int(str, &str, °, "degrees", 0, 180)) | |||
| 1306 | return NULL((void*)0); | |||
| 1307 | if (!isspace((unsigned char)*str)) { | |||
| 1308 | zc_error_prev_line("space expected after degrees"); | |||
| 1309 | return NULL((void*)0); | |||
| 1310 | } | |||
| 1311 | ++str; | |||
| 1312 | ||||
| 1313 | /* Minutes? */ | |||
| 1314 | if (isdigit((unsigned char)*str)) { | |||
| 1315 | if (!parse_int(str, &str, &min, "minutes", 0, 60)) | |||
| 1316 | return NULL((void*)0); | |||
| 1317 | if (!isspace((unsigned char)*str)) { | |||
| 1318 | zc_error_prev_line("space expected after minutes"); | |||
| 1319 | return NULL((void*)0); | |||
| 1320 | } | |||
| 1321 | ++str; | |||
| 1322 | } | |||
| 1323 | ||||
| 1324 | /* Seconds? */ | |||
| 1325 | if (isdigit((unsigned char)*str)) { | |||
| 1326 | start = str; | |||
| 1327 | if (!parse_int(str, &str, &i, "seconds", 0, 60)) { | |||
| 1328 | return NULL((void*)0); | |||
| 1329 | } | |||
| 1330 | ||||
| 1331 | if (*str == '.' && !parse_int(str + 1, &str, &i, "seconds fraction", 0, 999)) { | |||
| 1332 | return NULL((void*)0); | |||
| 1333 | } | |||
| 1334 | ||||
| 1335 | if (!isspace((unsigned char)*str)) { | |||
| 1336 | zc_error_prev_line("space expected after seconds"); | |||
| 1337 | return NULL((void*)0); | |||
| 1338 | } | |||
| 1339 | /* No need for precision specifiers, it's a double */ | |||
| 1340 | if (sscanf(start, "%lf", &d) != 1) { | |||
| 1341 | zc_error_prev_line("error parsing seconds"); | |||
| 1342 | } | |||
| 1343 | ||||
| 1344 | if (d < 0.0 || d > 60.0) { | |||
| 1345 | zc_error_prev_line("seconds not in range 0.0 .. 60.0"); | |||
| 1346 | } | |||
| 1347 | ||||
| 1348 | secs = (int) (d * 1000.0 + 0.5); | |||
| 1349 | ++str; | |||
| 1350 | } | |||
| 1351 | ||||
| 1352 | switch(*str) { | |||
| 1353 | case 'N': | |||
| 1354 | case 'n': | |||
| 1355 | lat = ((uint32_t)1<<31) + (deg * 3600000 + min * 60000 + secs); | |||
| 1356 | break; | |||
| 1357 | case 'E': | |||
| 1358 | case 'e': | |||
| 1359 | lon = ((uint32_t)1<<31) + (deg * 3600000 + min * 60000 + secs); | |||
| 1360 | break; | |||
| 1361 | case 'S': | |||
| 1362 | case 's': | |||
| 1363 | lat = ((uint32_t)1<<31) - (deg * 3600000 + min * 60000 + secs); | |||
| 1364 | break; | |||
| 1365 | case 'W': | |||
| 1366 | case 'w': | |||
| 1367 | lon = ((uint32_t)1<<31) - (deg * 3600000 + min * 60000 + secs); | |||
| 1368 | break; | |||
| 1369 | default: | |||
| 1370 | zc_error_prev_line("invalid latitude/longtitude: '%c'", *str); | |||
| 1371 | return NULL((void*)0); | |||
| 1372 | } | |||
| 1373 | ++str; | |||
| 1374 | ||||
| 1375 | if (lat
| |||
| 1376 | break; | |||
| 1377 | ||||
| 1378 | if (!isspace((unsigned char)*str)) { | |||
| 1379 | zc_error_prev_line("space expected after latitude/longitude"); | |||
| 1380 | return NULL((void*)0); | |||
| 1381 | } | |||
| 1382 | ++str; | |||
| 1383 | } | |||
| 1384 | ||||
| 1385 | /* Altitude */ | |||
| 1386 | if (*str == '\0') { | |||
| 1387 | zc_error_prev_line("unexpected end of LOC data"); | |||
| 1388 | return NULL((void*)0); | |||
| 1389 | } | |||
| 1390 | ||||
| 1391 | if (!isspace((unsigned char)*str)) { | |||
| 1392 | zc_error_prev_line("space expected before altitude"); | |||
| 1393 | return NULL((void*)0); | |||
| 1394 | } | |||
| 1395 | ++str; | |||
| 1396 | ||||
| 1397 | start = str; | |||
| 1398 | ||||
| 1399 | /* Sign */ | |||
| 1400 | if (*str == '+' || *str == '-') { | |||
| 1401 | ++str; | |||
| 1402 | } | |||
| 1403 | ||||
| 1404 | /* Meters of altitude... */ | |||
| 1405 | if(strtol(str, &str, 10) == LONG_MAX9223372036854775807L) { | |||
| 1406 | zc_error_prev_line("altitude too large, number overflow"); | |||
| 1407 | return NULL((void*)0); | |||
| 1408 | } | |||
| 1409 | switch(*str) { | |||
| 1410 | case ' ': | |||
| 1411 | case '\0': | |||
| 1412 | case 'm': | |||
| 1413 | break; | |||
| 1414 | case '.': | |||
| 1415 | if (!parse_int(str + 1, &str, &i, "altitude fraction", 0, 99)) { | |||
| 1416 | return NULL((void*)0); | |||
| 1417 | } | |||
| 1418 | if (!isspace((unsigned char)*str) && *str != '\0' && *str != 'm') { | |||
| 1419 | zc_error_prev_line("altitude fraction must be a number"); | |||
| 1420 | return NULL((void*)0); | |||
| 1421 | } | |||
| 1422 | break; | |||
| 1423 | default: | |||
| 1424 | zc_error_prev_line("altitude must be expressed in meters"); | |||
| 1425 | return NULL((void*)0); | |||
| 1426 | } | |||
| 1427 | if (!isspace((unsigned char)*str) && *str != '\0') | |||
| 1428 | ++str; | |||
| 1429 | ||||
| 1430 | if (sscanf(start, "%lf", &d) != 1) { | |||
| 1431 | zc_error_prev_line("error parsing altitude"); | |||
| 1432 | } | |||
| 1433 | ||||
| 1434 | alt = (uint32_t) (10000000.0 + d * 100 + 0.5); | |||
| 1435 | ||||
| 1436 | if (!isspace((unsigned char)*str) && *str != '\0') { | |||
| 1437 | zc_error_prev_line("unexpected character after altitude"); | |||
| 1438 | return NULL((void*)0); | |||
| 1439 | } | |||
| 1440 | ||||
| 1441 | /* Now parse size, horizontal precision and vertical precision if any */ | |||
| 1442 | for(i = 1; isspace((unsigned char)*str) && i <= 3; i++) { | |||
| 1443 | vszhpvp[i] = precsize_aton(str + 1, &str); | |||
| 1444 | ||||
| 1445 | if (!isspace((unsigned char)*str) && *str != '\0') { | |||
| 1446 | zc_error_prev_line("invalid size or precision"); | |||
| 1447 | return NULL((void*)0); | |||
| 1448 | } | |||
| 1449 | } | |||
| 1450 | ||||
| 1451 | /* Allocate required space... */ | |||
| 1452 | r = alloc_rdata(region, 16); | |||
| 1453 | p = (uint32_t *) (r + 1); | |||
| 1454 | ||||
| 1455 | memmove(p, vszhpvp, 4); | |||
| 1456 | write_uint32(p + 1, lat); | |||
| 1457 | write_uint32(p + 2, lon); | |||
| 1458 | write_uint32(p + 3, alt); | |||
| 1459 | ||||
| 1460 | return r; | |||
| 1461 | } | |||
| 1462 | ||||
| 1463 | /* | |||
| 1464 | * Convert an APL RR RDATA element. | |||
| 1465 | */ | |||
| 1466 | uint16_t * | |||
| 1467 | zparser_conv_apl_rdata(region_type *region, char *str) | |||
| 1468 | { | |||
| 1469 | int negated = 0; | |||
| 1470 | uint16_t address_family; | |||
| 1471 | uint8_t prefix; | |||
| 1472 | uint8_t maximum_prefix; | |||
| 1473 | uint8_t length; | |||
| 1474 | uint8_t address[IP6ADDRLEN(128/8)]; | |||
| 1475 | char *colon = strchr(str, ':'); | |||
| 1476 | char *slash = strchr(str, '/'); | |||
| 1477 | int af; | |||
| 1478 | int rc; | |||
| 1479 | uint16_t rdlength; | |||
| 1480 | uint16_t *r; | |||
| 1481 | uint8_t *t; | |||
| 1482 | char *end; | |||
| 1483 | long p; | |||
| 1484 | ||||
| 1485 | if (!colon) { | |||
| 1486 | zc_error("address family separator is missing"); | |||
| 1487 | return NULL((void*)0); | |||
| 1488 | } | |||
| 1489 | if (!slash) { | |||
| 1490 | zc_error("prefix separator is missing"); | |||
| 1491 | return NULL((void*)0); | |||
| 1492 | } | |||
| 1493 | ||||
| 1494 | *colon = '\0'; | |||
| 1495 | *slash = '\0'; | |||
| 1496 | ||||
| 1497 | if (*str == '!') { | |||
| 1498 | negated = 1; | |||
| 1499 | ++str; | |||
| 1500 | } | |||
| 1501 | ||||
| 1502 | if (strcmp(str, "1") == 0) { | |||
| 1503 | address_family = htons(1)(__uint16_t)(__builtin_constant_p(1) ? (__uint16_t)(((__uint16_t )(1) & 0xffU) << 8 | ((__uint16_t)(1) & 0xff00U ) >> 8) : __swap16md(1)); | |||
| 1504 | af = AF_INET2; | |||
| 1505 | length = sizeof(in_addr_t); | |||
| 1506 | maximum_prefix = length * 8; | |||
| 1507 | } else if (strcmp(str, "2") == 0) { | |||
| 1508 | address_family = htons(2)(__uint16_t)(__builtin_constant_p(2) ? (__uint16_t)(((__uint16_t )(2) & 0xffU) << 8 | ((__uint16_t)(2) & 0xff00U ) >> 8) : __swap16md(2)); | |||
| 1509 | af = AF_INET624; | |||
| 1510 | length = IP6ADDRLEN(128/8); | |||
| 1511 | maximum_prefix = length * 8; | |||
| 1512 | } else { | |||
| 1513 | zc_error("invalid address family '%s'", str); | |||
| 1514 | return NULL((void*)0); | |||
| 1515 | } | |||
| 1516 | ||||
| 1517 | rc = inet_pton(af, colon + 1, address); | |||
| 1518 | if (rc == 0) { | |||
| 1519 | zc_error("invalid address '%s'", colon + 1); | |||
| 1520 | return NULL((void*)0); | |||
| 1521 | } else if (rc == -1) { | |||
| 1522 | zc_error("inet_pton failed: %s", strerror(errno(*__errno()))); | |||
| 1523 | return NULL((void*)0); | |||
| 1524 | } | |||
| 1525 | ||||
| 1526 | /* Strip trailing zero octets. */ | |||
| 1527 | while (length > 0 && address[length - 1] == 0) | |||
| 1528 | --length; | |||
| 1529 | ||||
| 1530 | ||||
| 1531 | p = strtol(slash + 1, &end, 10); | |||
| 1532 | if (p < 0 || p > maximum_prefix) { | |||
| 1533 | zc_error("prefix not in the range 0 .. %d", maximum_prefix); | |||
| 1534 | return NULL((void*)0); | |||
| 1535 | } else if (*end != '\0') { | |||
| 1536 | zc_error("invalid prefix '%s'", slash + 1); | |||
| 1537 | return NULL((void*)0); | |||
| 1538 | } | |||
| 1539 | prefix = (uint8_t) p; | |||
| 1540 | ||||
| 1541 | rdlength = (sizeof(address_family) + sizeof(prefix) + sizeof(length) | |||
| 1542 | + length); | |||
| 1543 | r = alloc_rdata(region, rdlength); | |||
| 1544 | t = (uint8_t *) (r + 1); | |||
| 1545 | ||||
| 1546 | memcpy(t, &address_family, sizeof(address_family)); | |||
| 1547 | t += sizeof(address_family); | |||
| 1548 | memcpy(t, &prefix, sizeof(prefix)); | |||
| 1549 | t += sizeof(prefix); | |||
| 1550 | memcpy(t, &length, sizeof(length)); | |||
| 1551 | if (negated) { | |||
| 1552 | *t |= APL_NEGATION_MASK0x80U; | |||
| 1553 | } | |||
| 1554 | t += sizeof(length); | |||
| 1555 | memcpy(t, address, length); | |||
| 1556 | ||||
| 1557 | return r; | |||
| 1558 | } | |||
| 1559 | ||||
| 1560 | /* | |||
| 1561 | * Below some function that also convert but not to wireformat | |||
| 1562 | * but to "normal" (int,long,char) types | |||
| 1563 | */ | |||
| 1564 | ||||
| 1565 | uint32_t | |||
| 1566 | zparser_ttl2int(const char *ttlstr, int* error) | |||
| 1567 | { | |||
| 1568 | /* convert a ttl value to a integer | |||
| 1569 | * return the ttl in a int | |||
| 1570 | * -1 on error | |||
| 1571 | */ | |||
| 1572 | ||||
| 1573 | uint32_t ttl; | |||
| 1574 | const char *t; | |||
| 1575 | ||||
| 1576 | ttl = strtottl(ttlstr, &t); | |||
| 1577 | if (*t != 0) { | |||
| 1578 | zc_error_prev_line("invalid TTL value: %s",ttlstr); | |||
| 1579 | *error = 1; | |||
| 1580 | } | |||
| 1581 | ||||
| 1582 | return ttl; | |||
| 1583 | } | |||
| 1584 | ||||
| 1585 | ||||
| 1586 | void | |||
| 1587 | zadd_rdata_wireformat(uint16_t *data) | |||
| 1588 | { | |||
| 1589 | if (parser->current_rr.rdata_count >= MAXRDATALEN64) { | |||
| 1590 | zc_error_prev_line("too many rdata elements"); | |||
| 1591 | } else { | |||
| 1592 | parser->current_rr.rdatas[parser->current_rr.rdata_count].data | |||
| 1593 | = data; | |||
| 1594 | ++parser->current_rr.rdata_count; | |||
| 1595 | } | |||
| 1596 | } | |||
| 1597 | ||||
| 1598 | /** | |||
| 1599 | * Used for TXT RR's to grow with undefined number of strings. | |||
| 1600 | */ | |||
| 1601 | void | |||
| 1602 | zadd_rdata_txt_wireformat(uint16_t *data, int first) | |||
| 1603 | { | |||
| 1604 | rdata_atom_type *rd; | |||
| 1605 | if (parser->current_rr.rdata_count >= MAXRDATALEN64) { | |||
| 1606 | zc_error_prev_line("too many rdata txt elements"); | |||
| 1607 | return; | |||
| 1608 | } | |||
| 1609 | ||||
| 1610 | /* First STR in str_seq, allocate 65K in first unused rdata | |||
| 1611 | * else find last used rdata */ | |||
| 1612 | if (first) { | |||
| 1613 | rd = &parser->current_rr.rdatas[parser->current_rr.rdata_count]; | |||
| 1614 | if ((rd->data = (uint16_t *) region_alloc(parser->rr_region, | |||
| 1615 | sizeof(uint16_t) + 65535 * sizeof(uint8_t))) == NULL((void*)0)) { | |||
| 1616 | zc_error_prev_line("Could not allocate memory for TXT RR"); | |||
| 1617 | return; | |||
| 1618 | } | |||
| 1619 | parser->current_rr.rdata_count++; | |||
| 1620 | rd->data[0] = 0; | |||
| 1621 | } | |||
| 1622 | else | |||
| 1623 | rd = &parser->current_rr.rdatas[parser->current_rr.rdata_count-1]; | |||
| 1624 | ||||
| 1625 | if ((size_t)rd->data[0] + (size_t)data[0] > 65535) { | |||
| 1626 | zc_error_prev_line("too large rdata element"); | |||
| 1627 | return; | |||
| 1628 | } | |||
| 1629 | ||||
| 1630 | memcpy((uint8_t *)rd->data + 2 + rd->data[0], data + 1, data[0]); | |||
| 1631 | rd->data[0] += data[0]; | |||
| 1632 | } | |||
| 1633 | ||||
| 1634 | /** | |||
| 1635 | * Clean up after last call of zadd_rdata_txt_wireformat | |||
| 1636 | */ | |||
| 1637 | void | |||
| 1638 | zadd_rdata_txt_clean_wireformat() | |||
| 1639 | { | |||
| 1640 | uint16_t *tmp_data; | |||
| 1641 | rdata_atom_type *rd = &parser->current_rr.rdatas[parser->current_rr.rdata_count-1]; | |||
| 1642 | if(!rd || !rd->data) | |||
| 1643 | return; /* previous syntax failure */ | |||
| 1644 | if ((tmp_data = (uint16_t *) region_alloc(parser->region, | |||
| 1645 | ((size_t)rd->data[0]) + ((size_t)2))) != NULL((void*)0)) { | |||
| 1646 | memcpy(tmp_data, rd->data, rd->data[0] + 2); | |||
| 1647 | /* rd->data of u16+65535 freed when rr_region is freed */ | |||
| 1648 | rd->data = tmp_data; | |||
| 1649 | } | |||
| 1650 | else { | |||
| 1651 | /* We could not get memory in non-volatile region */ | |||
| 1652 | zc_error_prev_line("could not allocate memory for rdata"); | |||
| 1653 | return; | |||
| 1654 | } | |||
| 1655 | } | |||
| 1656 | ||||
| 1657 | static int | |||
| 1658 | svcparam_key_cmp(const void *a, const void *b) | |||
| 1659 | { | |||
| 1660 | return ((int)read_uint16(rdata_atom_data(*(rdata_atom_type *)a))) | |||
| 1661 | - ((int)read_uint16(rdata_atom_data(*(rdata_atom_type *)b))); | |||
| 1662 | } | |||
| 1663 | ||||
| 1664 | void | |||
| 1665 | zadd_rdata_svcb_check_wireformat() | |||
| 1666 | { | |||
| 1667 | size_t i; | |||
| 1668 | uint8_t paramkeys[65536]; | |||
| 1669 | int prev_key = - 1; | |||
| 1670 | int key = 0; | |||
| 1671 | size_t size; | |||
| 1672 | uint16_t *mandatory_values; | |||
| 1673 | ||||
| 1674 | if (parser->current_rr.rdata_count <= 2) { | |||
| 1675 | if (!parser->error_occurred) | |||
| 1676 | zc_error_prev_line("invalid SVCB or HTTPS rdata"); | |||
| 1677 | return; | |||
| 1678 | } else for (i = 2; i < parser->current_rr.rdata_count; i++) { | |||
| 1679 | if (parser->current_rr.rdatas[i].data == NULL((void*)0) | |||
| 1680 | || rdata_atom_data(parser->current_rr.rdatas[i]) == NULL((void*)0) | |||
| 1681 | || rdata_atom_size(parser->current_rr.rdatas[i]) < 4) { | |||
| 1682 | if (!parser->error_occurred) | |||
| 1683 | zc_error_prev_line("invalid SVCB or HTTPS rdata"); | |||
| 1684 | return; | |||
| 1685 | } | |||
| 1686 | } | |||
| 1687 | /* After this point, all rdatas do have data larger than 4 bytes. | |||
| 1688 | * So we may assume a uint16_t SVCB key followed by uint16_t length | |||
| 1689 | * in each rdata in the remainder of this function. | |||
| 1690 | */ | |||
| 1691 | memset(paramkeys, 0, sizeof(paramkeys)); | |||
| 1692 | /* | |||
| 1693 | * In draft-ietf-dnsop-svcb-https-04 Section 7: | |||
| 1694 | * In wire format, the keys are represented by their numeric values in | |||
| 1695 | * network byte order, concatenated in ascending order. | |||
| 1696 | * | |||
| 1697 | * svcparam_key_cmp assumes the rdatas to have a SVCB key, which is | |||
| 1698 | * safe because we checked. | |||
| 1699 | * | |||
| 1700 | */ | |||
| 1701 | qsort( (void *)&parser->current_rr.rdatas[2] | |||
| 1702 | , parser->current_rr.rdata_count - 2 | |||
| 1703 | , sizeof(rdata_atom_type) | |||
| 1704 | , svcparam_key_cmp | |||
| 1705 | ); | |||
| 1706 | ||||
| 1707 | for (i = 2; i < parser->current_rr.rdata_count; i++) { | |||
| 1708 | assert(parser->current_rr.rdatas[i].data)((void)0); | |||
| 1709 | assert(rdata_atom_data(parser->current_rr.rdatas[i]))((void)0); | |||
| 1710 | assert(rdata_atom_size(parser->current_rr.rdatas[i]) >= sizeof(uint16_t))((void)0); | |||
| 1711 | ||||
| 1712 | key = read_uint16(rdata_atom_data(parser->current_rr.rdatas[i])); | |||
| 1713 | ||||
| 1714 | /* In draft-ietf-dnsop-svcb-https-04 Section 7: | |||
| 1715 | * | |||
| 1716 | * Keys (...) MUST NOT appear more than once. | |||
| 1717 | * | |||
| 1718 | * If they key has already been seen, we have a duplicate | |||
| 1719 | */ | |||
| 1720 | if (!paramkeys[key]) | |||
| 1721 | /* keep track of keys that are present */ | |||
| 1722 | paramkeys[key] = 1; | |||
| 1723 | ||||
| 1724 | else if (key < SVCPARAMKEY_COUNT7) { | |||
| 1725 | if(zone_is_slave(parser->current_zone->opts)) | |||
| 1726 | zc_warning_prev_line( | |||
| 1727 | "Duplicate key found: %s", | |||
| 1728 | svcparamkey_strs[key]); | |||
| 1729 | else { | |||
| 1730 | zc_error_prev_line( | |||
| 1731 | "Duplicate key found: %s", | |||
| 1732 | svcparamkey_strs[key]); | |||
| 1733 | } | |||
| 1734 | } else if(zone_is_slave(parser->current_zone->opts)) | |||
| 1735 | zc_warning_prev_line( | |||
| 1736 | "Duplicate key found: key%d", key); | |||
| 1737 | else | |||
| 1738 | zc_error_prev_line( | |||
| 1739 | "Duplicate key found: key%d", key); | |||
| 1740 | } | |||
| 1741 | /* Checks when a mandatory key is present */ | |||
| 1742 | if (!paramkeys[SVCB_KEY_MANDATORY0]) | |||
| 1743 | return; | |||
| 1744 | ||||
| 1745 | size = rdata_atom_size(parser->current_rr.rdatas[2]); | |||
| 1746 | assert(size >= 4)((void)0); | |||
| 1747 | mandatory_values = (void*)rdata_atom_data(parser->current_rr.rdatas[2]); | |||
| 1748 | mandatory_values += 2; /* skip the key type and length */ | |||
| 1749 | ||||
| 1750 | if (size % 2) | |||
| 1751 | zc_error_prev_line("mandatory rdata must be a multiple of shorts"); | |||
| 1752 | ||||
| 1753 | else for (i = 0; i < (size - 4)/2; i++) { | |||
| 1754 | key = ntohs(mandatory_values[i])(__uint16_t)(__builtin_constant_p(mandatory_values[i]) ? (__uint16_t )(((__uint16_t)(mandatory_values[i]) & 0xffU) << 8 | ((__uint16_t)(mandatory_values[i]) & 0xff00U) >> 8 ) : __swap16md(mandatory_values[i])); | |||
| 1755 | ||||
| 1756 | if (paramkeys[key]) | |||
| 1757 | ; /* pass */ | |||
| 1758 | ||||
| 1759 | else if (key < SVCPARAMKEY_COUNT7) { | |||
| 1760 | if(zone_is_slave(parser->current_zone->opts)) | |||
| 1761 | zc_warning_prev_line("mandatory SvcParamKey: %s is missing " | |||
| 1762 | "the record", svcparamkey_strs[key]); | |||
| 1763 | else | |||
| 1764 | zc_error_prev_line("mandatory SvcParamKey: %s is missing " | |||
| 1765 | "the record", svcparamkey_strs[key]); | |||
| 1766 | } else { | |||
| 1767 | if(zone_is_slave(parser->current_zone->opts)) | |||
| 1768 | zc_warning_prev_line("mandatory SvcParamKey: key%d is missing " | |||
| 1769 | "the record", key); | |||
| 1770 | else | |||
| 1771 | zc_error_prev_line("mandatory SvcParamKey: key%d is missing " | |||
| 1772 | "the record", key); | |||
| 1773 | } | |||
| 1774 | ||||
| 1775 | /* In draft-ietf-dnsop-svcb-https-04 Section 8 | |||
| 1776 | * automatically mandatory MUST NOT appear in its own value-list | |||
| 1777 | */ | |||
| 1778 | if (key == SVCB_KEY_MANDATORY0) { | |||
| 1779 | if(zone_is_slave(parser->current_zone->opts)) | |||
| 1780 | zc_warning_prev_line("mandatory MUST not be included" | |||
| 1781 | " as mandatory parameter"); | |||
| 1782 | else | |||
| 1783 | zc_error_prev_line("mandatory MUST not be included" | |||
| 1784 | " as mandatory parameter"); | |||
| 1785 | } | |||
| 1786 | if (key == prev_key) { | |||
| 1787 | if(zone_is_slave(parser->current_zone->opts)) | |||
| 1788 | zc_warning_prev_line("Keys inSvcParam mandatory " | |||
| 1789 | "MUST NOT appear more than once."); | |||
| 1790 | else | |||
| 1791 | zc_error_prev_line("Keys in SvcParam mandatory " | |||
| 1792 | "MUST NOT appear more than once."); | |||
| 1793 | } | |||
| 1794 | prev_key = key; | |||
| 1795 | } | |||
| 1796 | } | |||
| 1797 | ||||
| 1798 | void | |||
| 1799 | zadd_rdata_domain(domain_type *domain) | |||
| 1800 | { | |||
| 1801 | if (parser->current_rr.rdata_count >= MAXRDATALEN64) { | |||
| 1802 | zc_error_prev_line("too many rdata elements"); | |||
| 1803 | } else { | |||
| 1804 | parser->current_rr.rdatas[parser->current_rr.rdata_count].domain | |||
| 1805 | = domain; | |||
| 1806 | domain->usage ++; /* new reference to domain */ | |||
| 1807 | ++parser->current_rr.rdata_count; | |||
| 1808 | } | |||
| 1809 | } | |||
| 1810 | ||||
| 1811 | void | |||
| 1812 | parse_unknown_rdata(uint16_t type, uint16_t *wireformat) | |||
| 1813 | { | |||
| 1814 | buffer_type packet; | |||
| 1815 | uint16_t size; | |||
| 1816 | ssize_t rdata_count; | |||
| 1817 | ssize_t i; | |||
| 1818 | rdata_atom_type *rdatas; | |||
| 1819 | ||||
| 1820 | if (wireformat) { | |||
| 1821 | size = *wireformat; | |||
| 1822 | } else { | |||
| 1823 | return; | |||
| 1824 | } | |||
| 1825 | ||||
| 1826 | buffer_create_from(&packet, wireformat + 1, *wireformat); | |||
| 1827 | rdata_count = rdata_wireformat_to_rdata_atoms(parser->region, | |||
| 1828 | parser->db->domains, | |||
| 1829 | type, | |||
| 1830 | size, | |||
| 1831 | &packet, | |||
| 1832 | &rdatas); | |||
| 1833 | if (rdata_count == -1) { | |||
| 1834 | zc_error_prev_line("bad unknown RDATA"); | |||
| 1835 | return; | |||
| 1836 | } | |||
| 1837 | ||||
| 1838 | for (i = 0; i < rdata_count; ++i) { | |||
| 1839 | if (rdata_atom_is_domain(type, i)) { | |||
| 1840 | zadd_rdata_domain(rdatas[i].domain); | |||
| 1841 | } else { | |||
| 1842 | zadd_rdata_wireformat(rdatas[i].data); | |||
| 1843 | } | |||
| 1844 | } | |||
| 1845 | region_recycle(parser->region, rdatas, | |||
| 1846 | rdata_count*sizeof(rdata_atom_type)); | |||
| 1847 | } | |||
| 1848 | ||||
| 1849 | ||||
| 1850 | /* | |||
| 1851 | * Compares two rdata arrays. | |||
| 1852 | * | |||
| 1853 | * Returns: | |||
| 1854 | * | |||
| 1855 | * zero if they are equal | |||
| 1856 | * non-zero if not | |||
| 1857 | * | |||
| 1858 | */ | |||
| 1859 | static int | |||
| 1860 | zrdatacmp(uint16_t type, rr_type *a, rr_type *b) | |||
| 1861 | { | |||
| 1862 | int i = 0; | |||
| 1863 | ||||
| 1864 | assert(a)((void)0); | |||
| 1865 | assert(b)((void)0); | |||
| 1866 | ||||
| 1867 | /* One is shorter than another */ | |||
| 1868 | if (a->rdata_count != b->rdata_count) | |||
| 1869 | return 1; | |||
| 1870 | ||||
| 1871 | /* Compare element by element */ | |||
| 1872 | for (i = 0; i < a->rdata_count; ++i) { | |||
| 1873 | if (rdata_atom_is_domain(type, i)) { | |||
| 1874 | if (rdata_atom_domain(a->rdatas[i]) | |||
| 1875 | != rdata_atom_domain(b->rdatas[i])) | |||
| 1876 | { | |||
| 1877 | return 1; | |||
| 1878 | } | |||
| 1879 | } else if(rdata_atom_is_literal_domain(type, i)) { | |||
| 1880 | if (rdata_atom_size(a->rdatas[i]) | |||
| 1881 | != rdata_atom_size(b->rdatas[i])) | |||
| 1882 | return 1; | |||
| 1883 | if (!dname_equal_nocase(rdata_atom_data(a->rdatas[i]), | |||
| 1884 | rdata_atom_data(b->rdatas[i]), | |||
| 1885 | rdata_atom_size(a->rdatas[i]))) | |||
| 1886 | return 1; | |||
| 1887 | } else { | |||
| 1888 | if (rdata_atom_size(a->rdatas[i]) | |||
| 1889 | != rdata_atom_size(b->rdatas[i])) | |||
| 1890 | { | |||
| 1891 | return 1; | |||
| 1892 | } | |||
| 1893 | if (memcmp(rdata_atom_data(a->rdatas[i]), | |||
| 1894 | rdata_atom_data(b->rdatas[i]), | |||
| 1895 | rdata_atom_size(a->rdatas[i])) != 0) | |||
| 1896 | { | |||
| 1897 | return 1; | |||
| 1898 | } | |||
| 1899 | } | |||
| 1900 | } | |||
| 1901 | ||||
| 1902 | /* Otherwise they are equal */ | |||
| 1903 | return 0; | |||
| 1904 | } | |||
| 1905 | ||||
| 1906 | /* | |||
| 1907 | * | |||
| 1908 | * Opens a zone file. | |||
| 1909 | * | |||
| 1910 | * Returns: | |||
| 1911 | * | |||
| 1912 | * - pointer to the parser structure | |||
| 1913 | * - NULL on error and errno set | |||
| 1914 | * | |||
| 1915 | */ | |||
| 1916 | static int | |||
| 1917 | zone_open(const char *filename, uint32_t ttl, uint16_t klass, | |||
| 1918 | const dname_type *origin) | |||
| 1919 | { | |||
| 1920 | /* Open the zone file... */ | |||
| 1921 | if (strcmp(filename, "-") == 0) { | |||
| 1922 | yyin = stdin(&__sF[0]); | |||
| 1923 | filename = "<stdin>"; | |||
| 1924 | warn_if_directory("zonefile from stdin", yyin, filename); | |||
| 1925 | } else { | |||
| 1926 | if (!(yyin = fopen(filename, "r"))) { | |||
| 1927 | return 0; | |||
| 1928 | } | |||
| 1929 | warn_if_directory("zonefile", yyin, filename); | |||
| 1930 | } | |||
| 1931 | ||||
| 1932 | zparser_init(filename, ttl, klass, origin); | |||
| 1933 | ||||
| 1934 | return 1; | |||
| 1935 | } | |||
| 1936 | ||||
| 1937 | ||||
| 1938 | void | |||
| 1939 | set_bitnsec(uint8_t bits[NSEC_WINDOW_COUNT256][NSEC_WINDOW_BITS_SIZE(256 / 8)], | |||
| 1940 | uint16_t index) | |||
| 1941 | { | |||
| 1942 | /* | |||
| 1943 | * The bits are counted from left to right, so bit #0 is the | |||
| 1944 | * left most bit. | |||
| 1945 | */ | |||
| 1946 | uint8_t window = index / 256; | |||
| 1947 | uint8_t bit = index % 256; | |||
| 1948 | ||||
| 1949 | bits[window][bit / 8] |= (1 << (7 - bit % 8)); | |||
| 1950 | } | |||
| 1951 | ||||
| 1952 | ||||
| 1953 | static int | |||
| 1954 | has_soa(domain_type* domain) | |||
| 1955 | { | |||
| 1956 | rrset_type* p = NULL((void*)0); | |||
| 1957 | if(!domain) return 0; | |||
| 1958 | for(p = domain->rrsets; p; p = p->next) | |||
| 1959 | if(rrset_rrtype(p) == TYPE_SOA6) | |||
| 1960 | return 1; | |||
| 1961 | return 0; | |||
| 1962 | } | |||
| 1963 | ||||
| 1964 | int | |||
| 1965 | process_rr(void) | |||
| 1966 | { | |||
| 1967 | zone_type *zone = parser->current_zone; | |||
| 1968 | rr_type *rr = &parser->current_rr; | |||
| 1969 | rrset_type *rrset; | |||
| 1970 | size_t max_rdlength; | |||
| 1971 | int i; | |||
| 1972 | rrtype_descriptor_type *descriptor | |||
| 1973 | = rrtype_descriptor_by_type(rr->type); | |||
| 1974 | ||||
| 1975 | /* We only support IN class */ | |||
| 1976 | if (rr->klass != CLASS_IN1) { | |||
| 1977 | if(zone_is_slave(zone->opts)) | |||
| 1978 | zc_warning_prev_line("only class IN is supported"); | |||
| 1979 | else | |||
| 1980 | zc_error_prev_line("only class IN is supported"); | |||
| 1981 | return 0; | |||
| 1982 | } | |||
| 1983 | ||||
| 1984 | /* Make sure the maximum RDLENGTH does not exceed 65535 bytes. */ | |||
| 1985 | max_rdlength = rdata_maximum_wireformat_size( | |||
| 1986 | descriptor, rr->rdata_count, rr->rdatas); | |||
| 1987 | ||||
| 1988 | if (max_rdlength > MAX_RDLENGTH65535) { | |||
| 1989 | zc_error_prev_line("maximum rdata length exceeds %d octets", MAX_RDLENGTH65535); | |||
| 1990 | return 0; | |||
| 1991 | } | |||
| 1992 | ||||
| 1993 | /* We cannot print invalid owner names, | |||
| 1994 | * so error on that before it is used in printing other errors. | |||
| 1995 | */ | |||
| 1996 | if (rr->owner == error_domain | |||
| 1997 | || domain_dname(rr->owner) == error_dname) { | |||
| 1998 | zc_error_prev_line("invalid owner name"); | |||
| 1999 | return 0; | |||
| 2000 | } | |||
| 2001 | ||||
| 2002 | /* we have the zone already */ | |||
| 2003 | assert(zone)((void)0); | |||
| 2004 | if (rr->type == TYPE_SOA6) { | |||
| 2005 | if (rr->owner != zone->apex) { | |||
| 2006 | char s[MAXDOMAINLEN255*5]; | |||
| 2007 | snprintf(s, sizeof(s), "%s", domain_to_string(zone->apex)); | |||
| 2008 | zc_error_prev_line( | |||
| 2009 | "SOA record with invalid domain name, '%s' is not '%s'", domain_to_string(rr->owner), s); | |||
| 2010 | return 0; | |||
| 2011 | } | |||
| 2012 | if(has_soa(rr->owner)) { | |||
| 2013 | if(zone_is_slave(zone->opts)) | |||
| 2014 | zc_warning_prev_line("this SOA record was already encountered"); | |||
| 2015 | else | |||
| 2016 | zc_error_prev_line("this SOA record was already encountered"); | |||
| 2017 | return 0; | |||
| 2018 | } | |||
| 2019 | rr->owner->is_apex = 1; | |||
| 2020 | } | |||
| 2021 | ||||
| 2022 | if (!domain_is_subdomain(rr->owner, zone->apex)) | |||
| 2023 | { | |||
| 2024 | char s[MAXDOMAINLEN255*5]; | |||
| 2025 | snprintf(s, sizeof(s), "%s", domain_to_string(zone->apex)); | |||
| 2026 | if(zone_is_slave(zone->opts)) | |||
| 2027 | zc_warning_prev_line("out of zone data: %s is outside the zone for fqdn %s", domain_to_string(rr->owner), s); | |||
| 2028 | else | |||
| 2029 | zc_error_prev_line("out of zone data: %s is outside the zone for fqdn %s", domain_to_string(rr->owner), s); | |||
| 2030 | return 0; | |||
| 2031 | } | |||
| 2032 | ||||
| 2033 | /* Do we have this type of rrset already? */ | |||
| 2034 | rrset = domain_find_rrset(rr->owner, zone, rr->type); | |||
| 2035 | if (!rrset) { | |||
| 2036 | rrset = (rrset_type *) region_alloc(parser->region, | |||
| 2037 | sizeof(rrset_type)); | |||
| 2038 | rrset->zone = zone; | |||
| 2039 | rrset->rr_count = 1; | |||
| 2040 | rrset->rrs = (rr_type *) region_alloc(parser->region, | |||
| 2041 | sizeof(rr_type)); | |||
| 2042 | rrset->rrs[0] = *rr; | |||
| 2043 | ||||
| 2044 | /* Add it */ | |||
| 2045 | domain_add_rrset(rr->owner, rrset); | |||
| 2046 | } else { | |||
| 2047 | rr_type* o; | |||
| 2048 | if (rr->type != TYPE_RRSIG46 && rrset->rrs[0].ttl != rr->ttl) { | |||
| 2049 | zc_warning_prev_line( | |||
| 2050 | "%s TTL %u does not match the TTL %u of the %s RRset", | |||
| 2051 | domain_to_string(rr->owner), (unsigned)rr->ttl, | |||
| 2052 | (unsigned)rrset->rrs[0].ttl, | |||
| 2053 | rrtype_to_string(rr->type)); | |||
| 2054 | } | |||
| 2055 | ||||
| 2056 | /* Search for possible duplicates... */ | |||
| 2057 | for (i = 0; i < rrset->rr_count; i++) { | |||
| 2058 | if (!zrdatacmp(rr->type, rr, &rrset->rrs[i])) { | |||
| 2059 | break; | |||
| 2060 | } | |||
| 2061 | } | |||
| 2062 | ||||
| 2063 | /* Discard the duplicates... */ | |||
| 2064 | if (i < rrset->rr_count) { | |||
| 2065 | /* add rdatas to recycle bin. */ | |||
| 2066 | size_t i; | |||
| 2067 | for (i = 0; i < rr->rdata_count; i++) { | |||
| 2068 | if(!rdata_atom_is_domain(rr->type, i)) | |||
| 2069 | region_recycle(parser->region, rr->rdatas[i].data, | |||
| 2070 | rdata_atom_size(rr->rdatas[i]) | |||
| 2071 | + sizeof(uint16_t)); | |||
| 2072 | } | |||
| 2073 | region_recycle(parser->region, rr->rdatas, | |||
| 2074 | sizeof(rdata_atom_type)*rr->rdata_count); | |||
| 2075 | return 0; | |||
| 2076 | } | |||
| 2077 | if(rrset->rr_count == 65535) { | |||
| 2078 | zc_error_prev_line("too many RRs for domain RRset"); | |||
| 2079 | return 0; | |||
| 2080 | } | |||
| 2081 | ||||
| 2082 | /* Add it... */ | |||
| 2083 | o = rrset->rrs; | |||
| 2084 | rrset->rrs = (rr_type *) region_alloc_array(parser->region, | |||
| 2085 | (rrset->rr_count + 1), sizeof(rr_type)); | |||
| 2086 | memcpy(rrset->rrs, o, (rrset->rr_count) * sizeof(rr_type)); | |||
| 2087 | region_recycle(parser->region, o, | |||
| 2088 | (rrset->rr_count) * sizeof(rr_type)); | |||
| 2089 | rrset->rrs[rrset->rr_count] = *rr; | |||
| 2090 | ++rrset->rr_count; | |||
| 2091 | } | |||
| 2092 | ||||
| 2093 | if(rr->type == TYPE_DNAME39 && rrset->rr_count > 1) { | |||
| 2094 | if(zone_is_slave(zone->opts)) | |||
| 2095 | zc_warning_prev_line("multiple DNAMEs at the same name"); | |||
| 2096 | else | |||
| 2097 | zc_error_prev_line("multiple DNAMEs at the same name"); | |||
| 2098 | } | |||
| 2099 | if(rr->type == TYPE_CNAME5 && rrset->rr_count > 1) { | |||
| 2100 | if(zone_is_slave(zone->opts)) | |||
| 2101 | zc_warning_prev_line("multiple CNAMEs at the same name"); | |||
| 2102 | else | |||
| 2103 | zc_error_prev_line("multiple CNAMEs at the same name"); | |||
| 2104 | } | |||
| 2105 | if((rr->type == TYPE_DNAME39 && domain_find_rrset(rr->owner, zone, TYPE_CNAME5)) | |||
| 2106 | ||(rr->type == TYPE_CNAME5 && domain_find_rrset(rr->owner, zone, TYPE_DNAME39))) { | |||
| 2107 | if(zone_is_slave(zone->opts)) | |||
| 2108 | zc_warning_prev_line("DNAME and CNAME at the same name"); | |||
| 2109 | else | |||
| 2110 | zc_error_prev_line("DNAME and CNAME at the same name"); | |||
| 2111 | } | |||
| 2112 | if(domain_find_rrset(rr->owner, zone, TYPE_CNAME5) && | |||
| 2113 | domain_find_non_cname_rrset(rr->owner, zone)) { | |||
| 2114 | if(zone_is_slave(zone->opts)) | |||
| 2115 | zc_warning_prev_line("CNAME and other data at the same name"); | |||
| 2116 | else | |||
| 2117 | zc_error_prev_line("CNAME and other data at the same name"); | |||
| 2118 | } | |||
| 2119 | ||||
| 2120 | /* Check we have SOA */ | |||
| 2121 | if(rr->owner == zone->apex) | |||
| 2122 | apex_rrset_checks(parser->db, rrset, rr->owner); | |||
| 2123 | ||||
| 2124 | if(parser->line % ZONEC_PCT_COUNT100000 == 0 && time(NULL((void*)0)) > startzonec + ZONEC_PCT_TIME5) { | |||
| 2125 | struct stat buf; | |||
| 2126 | startzonec = time(NULL((void*)0)); | |||
| 2127 | buf.st_size = 0; | |||
| 2128 | fstat(fileno(yyin)(!__isthreaded ? ((yyin)->_file) : (fileno)(yyin)), &buf); | |||
| 2129 | if(buf.st_size == 0) buf.st_size = 1; | |||
| 2130 | VERBOSITY(1, (LOG_INFO, "parse %s %d %%",do { if ((1) <= verbosity) { log_msg (6, "parse %s %d %%", parser->current_zone->opts->name, (int)((uint64_t)ftell (yyin)*(uint64_t)100/(uint64_t)buf.st_size)) ; } } while (0) | |||
| 2131 | parser->current_zone->opts->name,do { if ((1) <= verbosity) { log_msg (6, "parse %s %d %%", parser->current_zone->opts->name, (int)((uint64_t)ftell (yyin)*(uint64_t)100/(uint64_t)buf.st_size)) ; } } while (0) | |||
| 2132 | (int)((uint64_t)ftell(yyin)*(uint64_t)100/(uint64_t)buf.st_size)))do { if ((1) <= verbosity) { log_msg (6, "parse %s %d %%", parser->current_zone->opts->name, (int)((uint64_t)ftell (yyin)*(uint64_t)100/(uint64_t)buf.st_size)) ; } } while (0); | |||
| 2133 | } | |||
| 2134 | ++totalrrs; | |||
| 2135 | return 1; | |||
| 2136 | } | |||
| 2137 | ||||
| 2138 | /* | |||
| 2139 | * Find rrset type for any zone | |||
| 2140 | */ | |||
| 2141 | static rrset_type* | |||
| 2142 | domain_find_rrset_any(domain_type *domain, uint16_t type) | |||
| 2143 | { | |||
| 2144 | rrset_type *result = domain->rrsets; | |||
| 2145 | while (result) { | |||
| 2146 | if (rrset_rrtype(result) == type) { | |||
| 2147 | return result; | |||
| 2148 | } | |||
| 2149 | result = result->next; | |||
| 2150 | } | |||
| 2151 | return NULL((void*)0); | |||
| 2152 | } | |||
| 2153 | ||||
| 2154 | /* | |||
| 2155 | * Check for DNAME type. Nothing is allowed below it | |||
| 2156 | */ | |||
| 2157 | static void | |||
| 2158 | check_dname(zone_type* zone) | |||
| 2159 | { | |||
| 2160 | domain_type* domain; | |||
| 2161 | for(domain = zone->apex; domain && domain_is_subdomain(domain, | |||
| 2162 | zone->apex); domain=domain_next(domain)) | |||
| 2163 | { | |||
| 2164 | if(domain->is_existing) { | |||
| 2165 | /* there may not be DNAMEs above it */ | |||
| 2166 | domain_type* parent = domain->parent; | |||
| 2167 | #ifdef NSEC3 | |||
| 2168 | if(domain_has_only_NSEC3(domain, NULL((void*)0))) | |||
| 2169 | continue; | |||
| 2170 | #endif | |||
| 2171 | while(parent) { | |||
| 2172 | if(domain_find_rrset_any(parent, TYPE_DNAME39)) { | |||
| 2173 | zc_error("While checking node %s,", | |||
| 2174 | domain_to_string(domain)); | |||
| 2175 | zc_error("DNAME at %s has data below it. " | |||
| 2176 | "This is not allowed (rfc 2672).", | |||
| 2177 | domain_to_string(parent)); | |||
| 2178 | return; | |||
| 2179 | } | |||
| 2180 | parent = parent->parent; | |||
| 2181 | } | |||
| 2182 | } | |||
| 2183 | } | |||
| 2184 | } | |||
| 2185 | ||||
| 2186 | /* | |||
| 2187 | * Reads the specified zone into the memory | |||
| 2188 | * nsd_options can be NULL if no config file is passed. | |||
| 2189 | */ | |||
| 2190 | unsigned int | |||
| 2191 | zonec_read(const char* name, const char* zonefile, zone_type* zone) | |||
| 2192 | { | |||
| 2193 | const dname_type *dname; | |||
| 2194 | ||||
| 2195 | totalrrs = 0; | |||
| 2196 | startzonec = time(NULL((void*)0)); | |||
| 2197 | parser->errors = 0; | |||
| 2198 | ||||
| 2199 | dname = dname_parse(parser->rr_region, name); | |||
| 2200 | if (!dname) { | |||
| 2201 | zc_error("incorrect zone name '%s'", name); | |||
| 2202 | return 1; | |||
| 2203 | } | |||
| 2204 | ||||
| 2205 | #ifndef ROOT_SERVER | |||
| 2206 | /* Is it a root zone? Are we a root server then? Idiot proof. */ | |||
| 2207 | if (dname->label_count == 1) { | |||
| 2208 | zc_error("not configured as a root server"); | |||
| 2209 | return 1; | |||
| 2210 | } | |||
| 2211 | #endif | |||
| 2212 | ||||
| 2213 | /* Open the zone file */ | |||
| 2214 | if (!zone_open(zonefile, 3600, CLASS_IN1, dname)) { | |||
| 2215 | zc_error("cannot open '%s': %s", zonefile, strerror(errno(*__errno()))); | |||
| 2216 | return 1; | |||
| 2217 | } | |||
| 2218 | parser->current_zone = zone; | |||
| 2219 | ||||
| 2220 | /* Parse and process all RRs. */ | |||
| 2221 | yyparse(); | |||
| 2222 | ||||
| 2223 | /* remove origin if it was unused */ | |||
| 2224 | if(parser->origin != error_domain) | |||
| 2225 | domain_table_deldomain(parser->db, parser->origin); | |||
| 2226 | /* rr_region has been emptied by now */ | |||
| 2227 | dname = dname_parse(parser->rr_region, name); | |||
| 2228 | ||||
| 2229 | /* check if zone file contained a correct SOA record */ | |||
| 2230 | if (!parser->current_zone) { | |||
| 2231 | zc_error("zone configured as '%s' has no content.", name); | |||
| 2232 | } else if(!parser->current_zone->soa_rrset || | |||
| 2233 | parser->current_zone->soa_rrset->rr_count == 0) { | |||
| 2234 | zc_error("zone configured as '%s' has no SOA record.", name); | |||
| 2235 | } else if(dname_compare(domain_dname( | |||
| 2236 | parser->current_zone->soa_rrset->rrs[0].owner), dname) != 0) { | |||
| 2237 | zc_error("zone configured as '%s', but SOA has owner '%s'.", | |||
| 2238 | name, domain_to_string( | |||
| 2239 | parser->current_zone->soa_rrset->rrs[0].owner)); | |||
| 2240 | } | |||
| 2241 | region_free_all(parser->rr_region); | |||
| 2242 | ||||
| 2243 | parser_flush(); | |||
| 2244 | fclose(yyin); | |||
| 2245 | if(!zone_is_slave(zone->opts)) | |||
| 2246 | check_dname(zone); | |||
| 2247 | ||||
| 2248 | parser->filename = NULL((void*)0); | |||
| 2249 | return parser->errors; | |||
| 2250 | } | |||
| 2251 | ||||
| 2252 | ||||
| 2253 | /* | |||
| 2254 | * setup parse | |||
| 2255 | */ | |||
| 2256 | void | |||
| 2257 | zonec_setup_parser(namedb_type* db) | |||
| 2258 | { | |||
| 2259 | region_type* rr_region = region_create(xalloc, free); | |||
| 2260 | parser = zparser_create(db->region, rr_region, db); | |||
| 2261 | assert(parser)((void)0); | |||
| 2262 | /* Unique pointers used to mark errors. */ | |||
| 2263 | error_dname = (dname_type *) region_alloc(db->region, 1); | |||
| 2264 | error_domain = (domain_type *) region_alloc(db->region, 1); | |||
| 2265 | /* Open the network database */ | |||
| 2266 | setprotoent(1); | |||
| 2267 | setservent(1); | |||
| 2268 | } | |||
| 2269 | ||||
| 2270 | /** desetup parse */ | |||
| 2271 | void | |||
| 2272 | zonec_desetup_parser(void) | |||
| 2273 | { | |||
| 2274 | if(parser) { | |||
| 2275 | endservent(); | |||
| 2276 | endprotoent(); | |||
| 2277 | region_destroy(parser->rr_region); | |||
| 2278 | /* removed when parser->region(=db->region) is destroyed: | |||
| 2279 | * region_recycle(parser->region, (void*)error_dname, 1); | |||
| 2280 | * region_recycle(parser->region, (void*)error_domain, 1); */ | |||
| 2281 | /* clear memory for exit, but this is not portable to | |||
| 2282 | * other versions of lex. yylex_destroy(); */ | |||
| 2283 | #ifdef MEMCLEAN /* OS collects memory pages */ | |||
| 2284 | yylex_destroy(); | |||
| 2285 | #endif | |||
| 2286 | } | |||
| 2287 | } | |||
| 2288 | ||||
| 2289 | static domain_table_type* orig_domains = NULL((void*)0); | |||
| 2290 | static region_type* orig_region = NULL((void*)0); | |||
| 2291 | static region_type* orig_dbregion = NULL((void*)0); | |||
| 2292 | ||||
| 2293 | /** setup for string parse */ | |||
| 2294 | void | |||
| 2295 | zonec_setup_string_parser(region_type* region, domain_table_type* domains) | |||
| 2296 | { | |||
| 2297 | assert(parser)((void)0); /* global parser must be setup */ | |||
| 2298 | orig_domains = parser->db->domains; | |||
| 2299 | orig_region = parser->region; | |||
| 2300 | orig_dbregion = parser->db->region; | |||
| 2301 | parser->region = region; | |||
| 2302 | parser->db->region = region; | |||
| 2303 | parser->db->domains = domains; | |||
| 2304 | zparser_init("string", 3600, CLASS_IN1, domain_dname(domains->root)); | |||
| 2305 | } | |||
| 2306 | ||||
| 2307 | /** desetup string parse */ | |||
| 2308 | void | |||
| 2309 | zonec_desetup_string_parser(void) | |||
| 2310 | { | |||
| 2311 | parser->region = orig_region; | |||
| 2312 | parser->db->domains = orig_domains; | |||
| 2313 | parser->db->region = orig_dbregion; | |||
| 2314 | } | |||
| 2315 | ||||
| 2316 | /** parse a string into temporary storage */ | |||
| 2317 | int | |||
| 2318 | zonec_parse_string(region_type* region, domain_table_type* domains, | |||
| 2319 | zone_type* zone, char* str, domain_type** parsed, int* num_rrs) | |||
| 2320 | { | |||
| 2321 | int errors; | |||
| 2322 | zonec_setup_string_parser(region, domains); | |||
| 2323 | parser->current_zone = zone; | |||
| 2324 | parser->errors = 0; | |||
| 2325 | totalrrs = 0; | |||
| 2326 | startzonec = time(NULL((void*)0))+100000; /* disable */ | |||
| 2327 | parser_push_stringbuf(str); | |||
| 2328 | yyparse(); | |||
| 2329 | parser_pop_stringbuf(); | |||
| 2330 | errors = parser->errors; | |||
| 2331 | *num_rrs = totalrrs; | |||
| 2332 | if(*num_rrs == 0) | |||
| 2333 | *parsed = NULL((void*)0); | |||
| 2334 | else *parsed = parser->prev_dname; | |||
| 2335 | /* remove origin if it was not used during the parse */ | |||
| 2336 | if(parser->origin != error_domain) | |||
| 2337 | domain_table_deldomain(parser->db, parser->origin); | |||
| 2338 | region_free_all(parser->rr_region); | |||
| 2339 | zonec_desetup_string_parser(); | |||
| 2340 | parser_flush(); | |||
| 2341 | return errors; | |||
| 2342 | } | |||
| 2343 | ||||
| 2344 | /** check SSHFP type for failures and emit warnings */ | |||
| 2345 | void check_sshfp(void) | |||
| 2346 | { | |||
| 2347 | uint8_t hash; | |||
| 2348 | uint16_t size; | |||
| 2349 | if(parser->current_rr.rdata_count < 3) | |||
| 2350 | return; /* cannot check it, too few rdata elements */ | |||
| 2351 | if(!parser->current_rr.rdatas[0].data || | |||
| 2352 | !parser->current_rr.rdatas[1].data || | |||
| 2353 | !parser->current_rr.rdatas[2].data || | |||
| 2354 | !parser->current_rr.owner) | |||
| 2355 | return; /* cannot check, NULLs (due to earlier errors) */ | |||
| 2356 | if(rdata_atom_size(parser->current_rr.rdatas[1]) != 1) | |||
| 2357 | return; /* wrong size of the hash type rdata element */ | |||
| 2358 | hash = rdata_atom_data(parser->current_rr.rdatas[1])[0]; | |||
| 2359 | size = rdata_atom_size(parser->current_rr.rdatas[2]); | |||
| 2360 | if(hash == 1 && size != 20) { | |||
| 2361 | zc_warning_prev_line("SSHFP %s of type SHA1 has hash of " | |||
| 2362 | "wrong length, %d bytes, should be 20", | |||
| 2363 | domain_to_string(parser->current_rr.owner), | |||
| 2364 | (int)size); | |||
| 2365 | } else if(hash == 2 && size != 32) { | |||
| 2366 | zc_warning_prev_line("SSHFP %s of type SHA256 has hash of " | |||
| 2367 | "wrong length, %d bytes, should be 32", | |||
| 2368 | domain_to_string(parser->current_rr.owner), | |||
| 2369 | (int)size); | |||
| 2370 | } | |||
| 2371 | } |