1 /* $OpenBSD: asr_utils.c,v 1.18 2017/09/23 20:55:06 jca Exp $ */ 2 /* 3 * Copyright (c) 2009-2012 Eric Faurot <eric@faurot.net> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <net/if.h> 21 #include <netinet/in.h> 22 #include <arpa/inet.h> 23 #include <arpa/nameser.h> 24 #include <netdb.h> 25 26 #include <asr.h> 27 #include <ctype.h> 28 #include <errno.h> 29 #include <stdint.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 35 #include "asr_private.h" 36 37 static int dname_check_label(const char *, size_t); 38 static ssize_t dname_expand(const unsigned char *, size_t, size_t, size_t *, 39 char *, size_t); 40 41 static int unpack_data(struct asr_unpack *, void *, size_t); 42 static int unpack_u16(struct asr_unpack *, uint16_t *); 43 static int unpack_u32(struct asr_unpack *, uint32_t *); 44 static int unpack_inaddr(struct asr_unpack *, struct in_addr *); 45 static int unpack_in6addr(struct asr_unpack *, struct in6_addr *); 46 static int unpack_dname(struct asr_unpack *, char *, size_t); 47 48 static int pack_data(struct asr_pack *, const void *, size_t); 49 static int pack_u16(struct asr_pack *, uint16_t); 50 static int pack_dname(struct asr_pack *, const char *); 51 52 static int 53 dname_check_label(const char *s, size_t l) 54 { 55 if (l == 0 || l > 63) 56 return (-1); 57 58 return (0); 59 } 60 61 ssize_t 62 _asr_dname_from_fqdn(const char *str, char *dst, size_t max) 63 { 64 ssize_t res; 65 size_t l, n; 66 char *d; 67 68 res = 0; 69 70 /* special case: the root domain */ 71 if (str[0] == '.') { 72 if (str[1] != '\0') 73 return (-1); 74 if (dst && max >= 1) 75 *dst = '\0'; 76 return (1); 77 } 78 79 for (; *str; str = d + 1) { 80 81 d = strchr(str, '.'); 82 if (d == NULL || d == str) 83 return (-1); 84 85 l = (d - str); 86 87 if (dname_check_label(str, l) == -1) 88 return (-1); 89 90 res += l + 1; 91 92 if (dst) { 93 *dst++ = l; 94 max -= 1; 95 n = (l > max) ? max : l; 96 memmove(dst, str, n); 97 max -= n; 98 if (max == 0) 99 dst = NULL; 100 else 101 dst += n; 102 } 103 } 104 105 if (dst) 106 *dst++ = '\0'; 107 108 return (res + 1); 109 } 110 111 static ssize_t 112 dname_expand(const unsigned char *data, size_t len, size_t offset, 113 size_t *newoffset, char *dst, size_t max) 114 { 115 size_t n, count, end, ptr, start; 116 ssize_t res; 117 118 if (offset >= len) 119 return (-1); 120 121 res = 0; 122 end = start = offset; 123 124 for (; (n = data[offset]); ) { 125 if ((n & 0xc0) == 0xc0) { 126 if (offset + 2 > len) 127 return (-1); 128 ptr = 256 * (n & ~0xc0) + data[offset + 1]; 129 if (ptr >= start) 130 return (-1); 131 if (end < offset + 2) 132 end = offset + 2; 133 offset = start = ptr; 134 continue; 135 } 136 if (offset + n + 1 > len) 137 return (-1); 138 139 if (dname_check_label(data + offset + 1, n) == -1) 140 return (-1); 141 142 /* copy n + at offset+1 */ 143 if (dst != NULL && max != 0) { 144 count = (max < n + 1) ? (max) : (n + 1); 145 memmove(dst, data + offset, count); 146 dst += count; 147 max -= count; 148 } 149 res += n + 1; 150 offset += n + 1; 151 if (end < offset) 152 end = offset; 153 } 154 if (end < offset + 1) 155 end = offset + 1; 156 157 if (dst != NULL && max != 0) 158 dst[0] = 0; 159 if (newoffset) 160 *newoffset = end; 161 return (res + 1); 162 } 163 164 void 165 _asr_pack_init(struct asr_pack *pack, char *buf, size_t len) 166 { 167 pack->buf = buf; 168 pack->len = len; 169 pack->offset = 0; 170 pack->err = 0; 171 } 172 173 void 174 _asr_unpack_init(struct asr_unpack *unpack, const char *buf, size_t len) 175 { 176 unpack->buf = buf; 177 unpack->len = len; 178 unpack->offset = 0; 179 unpack->err = 0; 180 } 181 182 static int 183 unpack_data(struct asr_unpack *p, void *data, size_t len) 184 { 185 if (p->err) 186 return (-1); 187 188 if (p->len - p->offset < len) { 189 p->err = EOVERFLOW; 190 return (-1); 191 } 192 193 memmove(data, p->buf + p->offset, len); 194 p->offset += len; 195 196 return (0); 197 } 198 199 static int 200 unpack_u16(struct asr_unpack *p, uint16_t *u16) 201 { 202 if (unpack_data(p, u16, 2) == -1) 203 return (-1); 204 205 *u16 = ntohs(*u16); 206 207 return (0); 208 } 209 210 static int 211 unpack_u32(struct asr_unpack *p, uint32_t *u32) 212 { 213 if (unpack_data(p, u32, 4) == -1) 214 return (-1); 215 216 *u32 = ntohl(*u32); 217 218 return (0); 219 } 220 221 static int 222 unpack_inaddr(struct asr_unpack *p, struct in_addr *a) 223 { 224 return (unpack_data(p, a, 4)); 225 } 226 227 static int 228 unpack_in6addr(struct asr_unpack *p, struct in6_addr *a6) 229 { 230 return (unpack_data(p, a6, 16)); 231 } 232 233 static int 234 unpack_dname(struct asr_unpack *p, char *dst, size_t max) 235 { 236 ssize_t e; 237 238 if (p->err) 239 return (-1); 240 241 e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max); 242 if (e == -1) { 243 p->err = EINVAL; 244 return (-1); 245 } 246 if (e < 0 || e > MAXDNAME) { 247 p->err = ERANGE; 248 return (-1); 249 } 250 251 return (0); 252 } 253 254 int 255 _asr_unpack_header(struct asr_unpack *p, struct asr_dns_header *h) 256 { 257 if (unpack_data(p, h, HFIXEDSZ) == -1) 258 return (-1); 259 260 h->flags = ntohs(h->flags); 261 h->qdcount = ntohs(h->qdcount); 262 h->ancount = ntohs(h->ancount); 263 h->nscount = ntohs(h->nscount); 264 h->arcount = ntohs(h->arcount); 265 266 return (0); 267 } 268 269 int 270 _asr_unpack_query(struct asr_unpack *p, struct asr_dns_query *q) 271 { 272 unpack_dname(p, q->q_dname, sizeof(q->q_dname)); 273 unpack_u16(p, &q->q_type); 274 unpack_u16(p, &q->q_class); 275 276 return (p->err) ? (-1) : (0); 277 } 278 279 int 280 _asr_unpack_rr(struct asr_unpack *p, struct asr_dns_rr *rr) 281 { 282 uint16_t rdlen; 283 size_t save_offset; 284 285 unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname)); 286 unpack_u16(p, &rr->rr_type); 287 unpack_u16(p, &rr->rr_class); 288 unpack_u32(p, &rr->rr_ttl); 289 unpack_u16(p, &rdlen); 290 291 if (p->err) 292 return (-1); 293 294 if (p->len - p->offset < rdlen) { 295 p->err = EOVERFLOW; 296 return (-1); 297 } 298 299 save_offset = p->offset; 300 301 switch (rr->rr_type) { 302 303 case T_CNAME: 304 unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname)); 305 break; 306 307 case T_MX: 308 unpack_u16(p, &rr->rr.mx.preference); 309 unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange)); 310 break; 311 312 case T_NS: 313 unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname)); 314 break; 315 316 case T_PTR: 317 unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname)); 318 break; 319 320 case T_SOA: 321 unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname)); 322 unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname)); 323 unpack_u32(p, &rr->rr.soa.serial); 324 unpack_u32(p, &rr->rr.soa.refresh); 325 unpack_u32(p, &rr->rr.soa.retry); 326 unpack_u32(p, &rr->rr.soa.expire); 327 unpack_u32(p, &rr->rr.soa.minimum); 328 break; 329 330 case T_A: 331 if (rr->rr_class != C_IN) 332 goto other; 333 unpack_inaddr(p, &rr->rr.in_a.addr); 334 break; 335 336 case T_AAAA: 337 if (rr->rr_class != C_IN) 338 goto other; 339 unpack_in6addr(p, &rr->rr.in_aaaa.addr6); 340 break; 341 default: 342 other: 343 rr->rr.other.rdata = p->buf + p->offset; 344 rr->rr.other.rdlen = rdlen; 345 p->offset += rdlen; 346 } 347 348 if (p->err) 349 return (-1); 350 351 /* make sure that the advertised rdlen is really ok */ 352 if (p->offset - save_offset != rdlen) 353 p->err = EINVAL; 354 355 return (p->err) ? (-1) : (0); 356 } 357 358 static int 359 pack_data(struct asr_pack *p, const void *data, size_t len) 360 { 361 if (p->err) 362 return (-1); 363 364 if (p->len < p->offset + len) { 365 p->err = EOVERFLOW; 366 return (-1); 367 } 368 369 memmove(p->buf + p->offset, data, len); 370 p->offset += len; 371 372 return (0); 373 } 374 375 static int 376 pack_u16(struct asr_pack *p, uint16_t v) 377 { 378 v = htons(v); 379 380 return (pack_data(p, &v, 2)); 381 } 382 383 static int 384 pack_dname(struct asr_pack *p, const char *dname) 385 { 386 /* dname compression would be nice to have here. 387 * need additionnal context. 388 */ 389 return (pack_data(p, dname, strlen(dname) + 1)); 390 } 391 392 int 393 _asr_pack_header(struct asr_pack *p, const struct asr_dns_header *h) 394 { 395 struct asr_dns_header c; 396 397 c.id = h->id; 398 c.flags = htons(h->flags); 399 c.qdcount = htons(h->qdcount); 400 c.ancount = htons(h->ancount); 401 c.nscount = htons(h->nscount); 402 c.arcount = htons(h->arcount); 403 404 return (pack_data(p, &c, HFIXEDSZ)); 405 } 406 407 int 408 _asr_pack_query(struct asr_pack *p, uint16_t type, uint16_t class, const char *dname) 409 { 410 pack_dname(p, dname); 411 pack_u16(p, type); 412 pack_u16(p, class); 413 414 return (p->err) ? (-1) : (0); 415 } 416 417 int 418 _asr_pack_edns0(struct asr_pack *p, uint16_t pktsz, int dnssec_do) 419 { 420 DPRINT("asr EDNS0 pktsz:%hu dnssec:%s\n", pktsz, 421 dnssec_do ? "yes" : "no"); 422 423 pack_dname(p, ""); /* root */ 424 pack_u16(p, T_OPT); /* OPT */ 425 pack_u16(p, pktsz); /* UDP payload size */ 426 427 /* extended RCODE and flags */ 428 pack_u16(p, 0); 429 pack_u16(p, dnssec_do ? DNS_MESSAGEEXTFLAG_DO : 0); 430 431 pack_u16(p, 0); /* RDATA len */ 432 433 return (p->err) ? (-1) : (0); 434 } 435 436 int 437 _asr_sockaddr_from_str(struct sockaddr *sa, int family, const char *str) 438 { 439 struct in_addr ina; 440 struct in6_addr in6a; 441 struct sockaddr_in *sin; 442 struct sockaddr_in6 *sin6; 443 char *cp, *str2; 444 const char *errstr; 445 446 switch (family) { 447 case PF_UNSPEC: 448 if (_asr_sockaddr_from_str(sa, PF_INET, str) == 0) 449 return (0); 450 return _asr_sockaddr_from_str(sa, PF_INET6, str); 451 452 case PF_INET: 453 if (inet_pton(PF_INET, str, &ina) != 1) 454 return (-1); 455 456 sin = (struct sockaddr_in *)sa; 457 memset(sin, 0, sizeof *sin); 458 sin->sin_len = sizeof(struct sockaddr_in); 459 sin->sin_family = PF_INET; 460 sin->sin_addr.s_addr = ina.s_addr; 461 return (0); 462 463 case PF_INET6: 464 cp = strchr(str, SCOPE_DELIMITER); 465 if (cp) { 466 str2 = strdup(str); 467 if (str2 == NULL) 468 return (-1); 469 str2[cp - str] = '\0'; 470 if (inet_pton(PF_INET6, str2, &in6a) != 1) { 471 free(str2); 472 return (-1); 473 } 474 cp++; 475 free(str2); 476 } else if (inet_pton(PF_INET6, str, &in6a) != 1) 477 return (-1); 478 479 sin6 = (struct sockaddr_in6 *)sa; 480 memset(sin6, 0, sizeof *sin6); 481 sin6->sin6_len = sizeof(struct sockaddr_in6); 482 sin6->sin6_family = PF_INET6; 483 sin6->sin6_addr = in6a; 484 485 if (cp == NULL) 486 return (0); 487 488 if (IN6_IS_ADDR_LINKLOCAL(&in6a) || 489 IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || 490 IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) 491 if ((sin6->sin6_scope_id = if_nametoindex(cp))) 492 return (0); 493 494 sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr); 495 if (errstr) 496 return (-1); 497 return (0); 498 499 default: 500 break; 501 } 502 503 return (-1); 504 } 505 506 ssize_t 507 _asr_addr_as_fqdn(const char *addr, int family, char *dst, size_t max) 508 { 509 const struct in6_addr *in6_addr; 510 in_addr_t in_addr; 511 512 switch (family) { 513 case AF_INET: 514 in_addr = ntohl(*((const in_addr_t *)addr)); 515 snprintf(dst, max, 516 "%d.%d.%d.%d.in-addr.arpa.", 517 in_addr & 0xff, 518 (in_addr >> 8) & 0xff, 519 (in_addr >> 16) & 0xff, 520 (in_addr >> 24) & 0xff); 521 break; 522 case AF_INET6: 523 in6_addr = (const struct in6_addr *)addr; 524 snprintf(dst, max, 525 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 526 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 527 "ip6.arpa.", 528 in6_addr->s6_addr[15] & 0xf, 529 (in6_addr->s6_addr[15] >> 4) & 0xf, 530 in6_addr->s6_addr[14] & 0xf, 531 (in6_addr->s6_addr[14] >> 4) & 0xf, 532 in6_addr->s6_addr[13] & 0xf, 533 (in6_addr->s6_addr[13] >> 4) & 0xf, 534 in6_addr->s6_addr[12] & 0xf, 535 (in6_addr->s6_addr[12] >> 4) & 0xf, 536 in6_addr->s6_addr[11] & 0xf, 537 (in6_addr->s6_addr[11] >> 4) & 0xf, 538 in6_addr->s6_addr[10] & 0xf, 539 (in6_addr->s6_addr[10] >> 4) & 0xf, 540 in6_addr->s6_addr[9] & 0xf, 541 (in6_addr->s6_addr[9] >> 4) & 0xf, 542 in6_addr->s6_addr[8] & 0xf, 543 (in6_addr->s6_addr[8] >> 4) & 0xf, 544 in6_addr->s6_addr[7] & 0xf, 545 (in6_addr->s6_addr[7] >> 4) & 0xf, 546 in6_addr->s6_addr[6] & 0xf, 547 (in6_addr->s6_addr[6] >> 4) & 0xf, 548 in6_addr->s6_addr[5] & 0xf, 549 (in6_addr->s6_addr[5] >> 4) & 0xf, 550 in6_addr->s6_addr[4] & 0xf, 551 (in6_addr->s6_addr[4] >> 4) & 0xf, 552 in6_addr->s6_addr[3] & 0xf, 553 (in6_addr->s6_addr[3] >> 4) & 0xf, 554 in6_addr->s6_addr[2] & 0xf, 555 (in6_addr->s6_addr[2] >> 4) & 0xf, 556 in6_addr->s6_addr[1] & 0xf, 557 (in6_addr->s6_addr[1] >> 4) & 0xf, 558 in6_addr->s6_addr[0] & 0xf, 559 (in6_addr->s6_addr[0] >> 4) & 0xf); 560 break; 561 default: 562 return (-1); 563 } 564 return (0); 565 } 566