1*c4cedadeSeric /* $OpenBSD: asr_utils.c,v 1.4 2013/03/29 23:01:24 eric Exp $ */ 2b44da627Seric /* 3b44da627Seric * Copyright (c) 2009-2012 Eric Faurot <eric@faurot.net> 4b44da627Seric * 5b44da627Seric * Permission to use, copy, modify, and distribute this software for any 6b44da627Seric * purpose with or without fee is hereby granted, provided that the above 7b44da627Seric * copyright notice and this permission notice appear in all copies. 8b44da627Seric * 9b44da627Seric * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10b44da627Seric * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11b44da627Seric * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12b44da627Seric * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13b44da627Seric * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14b44da627Seric * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15b44da627Seric * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16b44da627Seric */ 17b44da627Seric 18b44da627Seric #include <sys/types.h> 19b44da627Seric #include <sys/socket.h> 20*c4cedadeSeric #include <net/if.h> 21b44da627Seric #include <netinet/in.h> 22b44da627Seric #include <arpa/inet.h> 23b44da627Seric #include <arpa/nameser.h> 24b44da627Seric 25b44da627Seric #include <ctype.h> 26b44da627Seric #include <errno.h> 27*c4cedadeSeric #include <stdint.h> 28b44da627Seric #include <stdio.h> 29*c4cedadeSeric #include <stdlib.h> 30b44da627Seric #include <string.h> 31b44da627Seric #include <unistd.h> 32b44da627Seric 33b44da627Seric #include "asr.h" 34b44da627Seric #include "asr_private.h" 35b44da627Seric 36b44da627Seric static int dname_check_label(const char*, size_t); 37b44da627Seric static ssize_t dname_expand(const unsigned char*, size_t, size_t, size_t*, 38b44da627Seric char *, size_t); 39b44da627Seric 40975956b6Seric static int unpack_data(struct unpack*, void*, size_t); 41975956b6Seric static int unpack_u16(struct unpack*, uint16_t*); 42975956b6Seric static int unpack_u32(struct unpack*, uint32_t*); 43975956b6Seric static int unpack_inaddr(struct unpack*, struct in_addr*); 44975956b6Seric static int unpack_in6addr(struct unpack*, struct in6_addr*); 45975956b6Seric static int unpack_dname(struct unpack*, char*, size_t); 46b44da627Seric 47975956b6Seric static int pack_data(struct pack*, const void*, size_t); 48975956b6Seric static int pack_u16(struct pack*, uint16_t); 49975956b6Seric static int pack_dname(struct pack*, const char*); 50b44da627Seric 51b44da627Seric static int 52b44da627Seric dname_check_label(const char *s, size_t l) 53b44da627Seric { 54b44da627Seric if (l == 0 || l > 63) 55b44da627Seric return (-1); 56b44da627Seric 57b44da627Seric for (l--; l; l--, s++) 58b44da627Seric if (!(isalnum(*s) || *s == '_' || *s == '-')) 59b44da627Seric return (-1); 60b44da627Seric 61b44da627Seric return (0); 62b44da627Seric } 63b44da627Seric 64b44da627Seric ssize_t 65b44da627Seric dname_from_fqdn(const char *str, char *dst, size_t max) 66b44da627Seric { 67b44da627Seric ssize_t res; 68b44da627Seric size_t l, n; 69b44da627Seric char *d; 70b44da627Seric 71b44da627Seric res = 0; 72b44da627Seric 73b44da627Seric /* special case: the root domain */ 74b44da627Seric if (str[0] == '.') { 75b44da627Seric if (str[1] != '\0') 76b44da627Seric return (-1); 77b44da627Seric if (dst && max >= 1) 78b44da627Seric *dst = '\0'; 79b44da627Seric return (1); 80b44da627Seric } 81b44da627Seric 82b44da627Seric for (; *str; str = d + 1) { 83b44da627Seric 84b44da627Seric d = strchr(str, '.'); 85b44da627Seric if (d == NULL || d == str) 86b44da627Seric return (-1); 87b44da627Seric 88b44da627Seric l = (d - str); 89b44da627Seric 90b44da627Seric if (dname_check_label(str, l) == -1) 91b44da627Seric return (-1); 92b44da627Seric 93b44da627Seric res += l + 1; 94b44da627Seric 95b44da627Seric if (dst) { 96b44da627Seric *dst++ = l; 97b44da627Seric max -= 1; 98b44da627Seric n = (l > max) ? max : l; 99b44da627Seric memmove(dst, str, n); 100b44da627Seric max -= n; 101b44da627Seric if (max == 0) 102b44da627Seric dst = NULL; 103b44da627Seric else 104b44da627Seric dst += n; 105b44da627Seric } 106b44da627Seric } 107b44da627Seric 108b44da627Seric if (dst) 109b44da627Seric *dst++ = '\0'; 110b44da627Seric 111b44da627Seric return (res + 1); 112b44da627Seric } 113b44da627Seric 114b44da627Seric static ssize_t 115b44da627Seric dname_expand(const unsigned char *data, size_t len, size_t offset, 116b44da627Seric size_t *newoffset, char *dst, size_t max) 117b44da627Seric { 118b44da627Seric size_t n, count, end, ptr, start; 119b44da627Seric ssize_t res; 120b44da627Seric 121b44da627Seric if (offset >= len) 122b44da627Seric return (-1); 123b44da627Seric 124b44da627Seric res = 0; 125b44da627Seric end = start = offset; 126b44da627Seric 127b44da627Seric for (; (n = data[offset]); ) { 128b44da627Seric if ((n & 0xc0) == 0xc0) { 129b44da627Seric if (offset + 2 > len) 130b44da627Seric return (-1); 131b44da627Seric ptr = 256 * (n & ~0xc0) + data[offset + 1]; 132b44da627Seric if (ptr >= start) 133b44da627Seric return (-1); 134b44da627Seric if (end < offset + 2) 135b44da627Seric end = offset + 2; 136b44da627Seric offset = ptr; 137b44da627Seric continue; 138b44da627Seric } 139b44da627Seric if (offset + n + 1 > len) 140b44da627Seric return (-1); 141b44da627Seric 142b44da627Seric if (dname_check_label(data + offset + 1, n) == -1) 143b44da627Seric return (-1); 144b44da627Seric 145b44da627Seric /* copy n + at offset+1 */ 146b44da627Seric if (dst != NULL && max != 0) { 147b44da627Seric count = (max < n + 1) ? (max) : (n + 1); 148b44da627Seric memmove(dst, data + offset, count); 149b44da627Seric dst += count; 150b44da627Seric max -= count; 151b44da627Seric } 152b44da627Seric res += n + 1; 153b44da627Seric offset += n + 1; 154b44da627Seric if (end < offset) 155b44da627Seric end = offset; 156b44da627Seric } 157b44da627Seric if (end < offset + 1) 158b44da627Seric end = offset + 1; 159b44da627Seric 160b44da627Seric if (dst != NULL && max != 0) 161b44da627Seric dst[0] = 0; 162b44da627Seric if (newoffset) 163b44da627Seric *newoffset = end; 164b44da627Seric return (res + 1); 165b44da627Seric } 166b44da627Seric 167b44da627Seric void 168975956b6Seric pack_init(struct pack *pack, char *buf, size_t len) 169b44da627Seric { 170975956b6Seric pack->buf = buf; 171b44da627Seric pack->len = len; 172b44da627Seric pack->offset = 0; 173b44da627Seric pack->err = NULL; 174b44da627Seric } 175b44da627Seric 176975956b6Seric void 177975956b6Seric unpack_init(struct unpack *unpack, const char *buf, size_t len) 178975956b6Seric { 179975956b6Seric unpack->buf = buf; 180975956b6Seric unpack->len = len; 181975956b6Seric unpack->offset = 0; 182975956b6Seric unpack->err = NULL; 183975956b6Seric } 184975956b6Seric 185b44da627Seric static int 186975956b6Seric unpack_data(struct unpack *p, void *data, size_t len) 187b44da627Seric { 188b44da627Seric if (p->err) 189b44da627Seric return (-1); 190b44da627Seric 191b44da627Seric if (p->len - p->offset < len) { 192b44da627Seric p->err = "too short"; 193b44da627Seric return (-1); 194b44da627Seric } 195b44da627Seric 196975956b6Seric memmove(data, p->buf + p->offset, len); 197b44da627Seric p->offset += len; 198b44da627Seric 199b44da627Seric return (0); 200b44da627Seric } 201b44da627Seric 202b44da627Seric static int 203975956b6Seric unpack_u16(struct unpack *p, uint16_t *u16) 204b44da627Seric { 205b44da627Seric if (unpack_data(p, u16, 2) == -1) 206b44da627Seric return (-1); 207b44da627Seric 208b44da627Seric *u16 = ntohs(*u16); 209b44da627Seric 210b44da627Seric return (0); 211b44da627Seric } 212b44da627Seric 213b44da627Seric static int 214975956b6Seric unpack_u32(struct unpack *p, uint32_t *u32) 215b44da627Seric { 216b44da627Seric if (unpack_data(p, u32, 4) == -1) 217b44da627Seric return (-1); 218b44da627Seric 219b44da627Seric *u32 = ntohl(*u32); 220b44da627Seric 221b44da627Seric return (0); 222b44da627Seric } 223b44da627Seric 224b44da627Seric static int 225975956b6Seric unpack_inaddr(struct unpack *p, struct in_addr *a) 226b44da627Seric { 227b44da627Seric return (unpack_data(p, a, 4)); 228b44da627Seric } 229b44da627Seric 230b44da627Seric static int 231975956b6Seric unpack_in6addr(struct unpack *p, struct in6_addr *a6) 232b44da627Seric { 233b44da627Seric return (unpack_data(p, a6, 16)); 234b44da627Seric } 235b44da627Seric 236b44da627Seric static int 237975956b6Seric unpack_dname(struct unpack *p, char *dst, size_t max) 238b44da627Seric { 239b44da627Seric ssize_t e; 240b44da627Seric 241b44da627Seric if (p->err) 242b44da627Seric return (-1); 243b44da627Seric 244975956b6Seric e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max); 245b44da627Seric if (e == -1) { 246b44da627Seric p->err = "bad domain name"; 247b44da627Seric return (-1); 248b44da627Seric } 249b44da627Seric if (e < 0 || e > MAXDNAME) { 250b44da627Seric p->err = "domain name too long"; 251b44da627Seric return (-1); 252b44da627Seric } 253b44da627Seric 254b44da627Seric return (0); 255b44da627Seric } 256b44da627Seric 257b44da627Seric int 258975956b6Seric unpack_header(struct unpack *p, struct header *h) 259b44da627Seric { 260b44da627Seric if (unpack_data(p, h, HFIXEDSZ) == -1) 261b44da627Seric return (-1); 262b44da627Seric 263b44da627Seric h->flags = ntohs(h->flags); 264b44da627Seric h->qdcount = ntohs(h->qdcount); 265b44da627Seric h->ancount = ntohs(h->ancount); 266b44da627Seric h->nscount = ntohs(h->nscount); 267b44da627Seric h->arcount = ntohs(h->arcount); 268b44da627Seric 269b44da627Seric return (0); 270b44da627Seric } 271b44da627Seric 272b44da627Seric int 273975956b6Seric unpack_query(struct unpack *p, struct query *q) 274b44da627Seric { 275b44da627Seric unpack_dname(p, q->q_dname, sizeof(q->q_dname)); 276b44da627Seric unpack_u16(p, &q->q_type); 277b44da627Seric unpack_u16(p, &q->q_class); 278b44da627Seric 279b44da627Seric return (p->err) ? (-1) : (0); 280b44da627Seric } 281b44da627Seric 282b44da627Seric int 283975956b6Seric unpack_rr(struct unpack *p, struct rr *rr) 284b44da627Seric { 285b44da627Seric uint16_t rdlen; 286b44da627Seric size_t save_offset; 287b44da627Seric 288b44da627Seric unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname)); 289b44da627Seric unpack_u16(p, &rr->rr_type); 290b44da627Seric unpack_u16(p, &rr->rr_class); 291b44da627Seric unpack_u32(p, &rr->rr_ttl); 292b44da627Seric unpack_u16(p, &rdlen); 293b44da627Seric 294b44da627Seric if (p->err) 295b44da627Seric return (-1); 296b44da627Seric 297b44da627Seric if (p->len - p->offset < rdlen) { 298b44da627Seric p->err = "too short"; 299b44da627Seric return (-1); 300b44da627Seric } 301b44da627Seric 302b44da627Seric save_offset = p->offset; 303b44da627Seric 304b44da627Seric switch (rr->rr_type) { 305b44da627Seric 306b44da627Seric case T_CNAME: 307b44da627Seric unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname)); 308b44da627Seric break; 309b44da627Seric 310b44da627Seric case T_MX: 311b44da627Seric unpack_u16(p, &rr->rr.mx.preference); 312b44da627Seric unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange)); 313b44da627Seric break; 314b44da627Seric 315b44da627Seric case T_NS: 316b44da627Seric unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname)); 317b44da627Seric break; 318b44da627Seric 319b44da627Seric case T_PTR: 320b44da627Seric unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname)); 321b44da627Seric break; 322b44da627Seric 323b44da627Seric case T_SOA: 324b44da627Seric unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname)); 325b44da627Seric unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname)); 326b44da627Seric unpack_u32(p, &rr->rr.soa.serial); 327b44da627Seric unpack_u32(p, &rr->rr.soa.refresh); 328b44da627Seric unpack_u32(p, &rr->rr.soa.retry); 329b44da627Seric unpack_u32(p, &rr->rr.soa.expire); 330b44da627Seric unpack_u32(p, &rr->rr.soa.minimum); 331b44da627Seric break; 332b44da627Seric 333b44da627Seric case T_A: 334b44da627Seric if (rr->rr_class != C_IN) 335b44da627Seric goto other; 336b44da627Seric unpack_inaddr(p, &rr->rr.in_a.addr); 337b44da627Seric break; 338b44da627Seric 339b44da627Seric case T_AAAA: 340b44da627Seric if (rr->rr_class != C_IN) 341b44da627Seric goto other; 342b44da627Seric unpack_in6addr(p, &rr->rr.in_aaaa.addr6); 343b44da627Seric break; 344b44da627Seric default: 345b44da627Seric other: 346975956b6Seric rr->rr.other.rdata = p->buf + p->offset; 347b44da627Seric rr->rr.other.rdlen = rdlen; 348b44da627Seric p->offset += rdlen; 349b44da627Seric } 350b44da627Seric 351b44da627Seric if (p->err) 352b44da627Seric return (-1); 353b44da627Seric 354b44da627Seric /* make sure that the advertised rdlen is really ok */ 355b44da627Seric if (p->offset - save_offset != rdlen) 356b44da627Seric p->err = "bad dlen"; 357b44da627Seric 358b44da627Seric return (p->err) ? (-1) : (0); 359b44da627Seric } 360b44da627Seric 361b44da627Seric static int 362975956b6Seric pack_data(struct pack *p, const void *data, size_t len) 363b44da627Seric { 364b44da627Seric if (p->err) 365b44da627Seric return (-1); 366b44da627Seric 367b44da627Seric if (p->len < p->offset + len) { 368b44da627Seric p->err = "no space"; 369b44da627Seric return (-1); 370b44da627Seric } 371b44da627Seric 372975956b6Seric memmove(p->buf + p->offset, data, len); 373b44da627Seric p->offset += len; 374b44da627Seric 375b44da627Seric return (0); 376b44da627Seric } 377b44da627Seric 378b44da627Seric static int 379975956b6Seric pack_u16(struct pack *p, uint16_t v) 380b44da627Seric { 381b44da627Seric v = htons(v); 382b44da627Seric 383b44da627Seric return (pack_data(p, &v, 2)); 384b44da627Seric } 385b44da627Seric 386b44da627Seric static int 387975956b6Seric pack_dname(struct pack *p, const char *dname) 388b44da627Seric { 389b44da627Seric /* dname compression would be nice to have here. 390b44da627Seric * need additionnal context. 391b44da627Seric */ 392b44da627Seric return (pack_data(p, dname, strlen(dname) + 1)); 393b44da627Seric } 394b44da627Seric 395b44da627Seric int 396975956b6Seric pack_header(struct pack *p, const struct header *h) 397b44da627Seric { 398b44da627Seric struct header c; 399b44da627Seric 400b44da627Seric c.id = h->id; 401b44da627Seric c.flags = htons(h->flags); 402b44da627Seric c.qdcount = htons(h->qdcount); 403b44da627Seric c.ancount = htons(h->ancount); 404b44da627Seric c.nscount = htons(h->nscount); 405b44da627Seric c.arcount = htons(h->arcount); 406b44da627Seric 407b44da627Seric return (pack_data(p, &c, HFIXEDSZ)); 408b44da627Seric } 409b44da627Seric 410b44da627Seric int 411975956b6Seric pack_query(struct pack *p, uint16_t type, uint16_t class, const char *dname) 412b44da627Seric { 413b44da627Seric pack_dname(p, dname); 414b44da627Seric pack_u16(p, type); 415b44da627Seric pack_u16(p, class); 416b44da627Seric 417b44da627Seric return (p->err) ? (-1) : (0); 418b44da627Seric } 419b44da627Seric 420b44da627Seric int 421b44da627Seric sockaddr_from_str(struct sockaddr *sa, int family, const char *str) 422b44da627Seric { 423b44da627Seric struct in_addr ina; 424b44da627Seric struct in6_addr in6a; 425b44da627Seric struct sockaddr_in *sin; 426b44da627Seric struct sockaddr_in6 *sin6; 427*c4cedadeSeric char *cp, *str2; 428*c4cedadeSeric const char *errstr; 429b44da627Seric 430b44da627Seric switch (family) { 431b44da627Seric case PF_UNSPEC: 432b44da627Seric if (sockaddr_from_str(sa, PF_INET, str) == 0) 433b44da627Seric return (0); 434b44da627Seric return sockaddr_from_str(sa, PF_INET6, str); 435b44da627Seric 436b44da627Seric case PF_INET: 437b44da627Seric if (inet_pton(PF_INET, str, &ina) != 1) 438b44da627Seric return (-1); 439b44da627Seric 440b44da627Seric sin = (struct sockaddr_in *)sa; 441b44da627Seric memset(sin, 0, sizeof *sin); 442b44da627Seric sin->sin_len = sizeof(struct sockaddr_in); 443b44da627Seric sin->sin_family = PF_INET; 444b44da627Seric sin->sin_addr.s_addr = ina.s_addr; 445b44da627Seric return (0); 446b44da627Seric 447b44da627Seric case PF_INET6: 448*c4cedadeSeric cp = strchr(str, SCOPE_DELIMITER); 449*c4cedadeSeric if (cp) { 450*c4cedadeSeric str2 = strdup(str); 451*c4cedadeSeric if (str2 == NULL) 452*c4cedadeSeric return (-1); 453*c4cedadeSeric str2[cp - str] = '\0'; 454*c4cedadeSeric if (inet_pton(PF_INET6, str2, &in6a) != 1) { 455*c4cedadeSeric free(str2); 456*c4cedadeSeric return (-1); 457*c4cedadeSeric } 458*c4cedadeSeric cp++; 459*c4cedadeSeric free(str2); 460*c4cedadeSeric } else if (inet_pton(PF_INET6, str, &in6a) != 1) 461b44da627Seric return (-1); 462b44da627Seric 463b44da627Seric sin6 = (struct sockaddr_in6 *)sa; 464b44da627Seric memset(sin6, 0, sizeof *sin6); 465b44da627Seric sin6->sin6_len = sizeof(struct sockaddr_in6); 466b44da627Seric sin6->sin6_family = PF_INET6; 467b44da627Seric sin6->sin6_addr = in6a; 468*c4cedadeSeric 469*c4cedadeSeric if (cp == NULL) 470*c4cedadeSeric return (0); 471*c4cedadeSeric 472*c4cedadeSeric if (IN6_IS_ADDR_LINKLOCAL(&in6a) || 473*c4cedadeSeric IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || 474*c4cedadeSeric IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) 475*c4cedadeSeric if ((sin6->sin6_scope_id = if_nametoindex(cp))) 476*c4cedadeSeric return (0); 477*c4cedadeSeric 478*c4cedadeSeric sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr); 479*c4cedadeSeric if (errstr) 480*c4cedadeSeric return (-1); 481b44da627Seric return (0); 482b44da627Seric 483b44da627Seric default: 484b44da627Seric break; 485b44da627Seric } 486b44da627Seric 487b44da627Seric return (-1); 488b44da627Seric } 489