1*92f75510Seric /* $OpenBSD: asr_utils.c,v 1.14 2017/02/17 22:24:45 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> 20c4cedadeSeric #include <net/if.h> 21b44da627Seric #include <netinet/in.h> 22b44da627Seric #include <arpa/inet.h> 23b44da627Seric #include <arpa/nameser.h> 24d216d6b1Seric #include <netdb.h> 25b44da627Seric 26d216d6b1Seric #include <asr.h> 27b44da627Seric #include <ctype.h> 28b44da627Seric #include <errno.h> 29c4cedadeSeric #include <stdint.h> 30b44da627Seric #include <stdio.h> 31c4cedadeSeric #include <stdlib.h> 32b44da627Seric #include <string.h> 33b44da627Seric #include <unistd.h> 34b44da627Seric 35b44da627Seric #include "asr_private.h" 36b44da627Seric 37b44da627Seric static int dname_check_label(const char *, size_t); 38b44da627Seric static ssize_t dname_expand(const unsigned char *, size_t, size_t, size_t *, 39b44da627Seric char *, size_t); 40b44da627Seric 41f90bf415Seric static int unpack_data(struct asr_unpack *, void *, size_t); 42f90bf415Seric static int unpack_u16(struct asr_unpack *, uint16_t *); 43f90bf415Seric static int unpack_u32(struct asr_unpack *, uint32_t *); 44f90bf415Seric static int unpack_inaddr(struct asr_unpack *, struct in_addr *); 45f90bf415Seric static int unpack_in6addr(struct asr_unpack *, struct in6_addr *); 46f90bf415Seric static int unpack_dname(struct asr_unpack *, char *, size_t); 47b44da627Seric 48f90bf415Seric static int pack_data(struct asr_pack *, const void *, size_t); 49f90bf415Seric static int pack_u16(struct asr_pack *, uint16_t); 50f90bf415Seric static int pack_dname(struct asr_pack *, const char *); 51b44da627Seric 52b44da627Seric static int 53b44da627Seric dname_check_label(const char *s, size_t l) 54b44da627Seric { 55b44da627Seric if (l == 0 || l > 63) 56b44da627Seric return (-1); 57b44da627Seric 58b44da627Seric return (0); 59b44da627Seric } 60b44da627Seric 61b44da627Seric ssize_t 62253ef892Sderaadt _asr_dname_from_fqdn(const char *str, char *dst, size_t max) 63b44da627Seric { 64b44da627Seric ssize_t res; 65b44da627Seric size_t l, n; 66b44da627Seric char *d; 67b44da627Seric 68b44da627Seric res = 0; 69b44da627Seric 70b44da627Seric /* special case: the root domain */ 71b44da627Seric if (str[0] == '.') { 72b44da627Seric if (str[1] != '\0') 73b44da627Seric return (-1); 74b44da627Seric if (dst && max >= 1) 75b44da627Seric *dst = '\0'; 76b44da627Seric return (1); 77b44da627Seric } 78b44da627Seric 79b44da627Seric for (; *str; str = d + 1) { 80b44da627Seric 81b44da627Seric d = strchr(str, '.'); 82b44da627Seric if (d == NULL || d == str) 83b44da627Seric return (-1); 84b44da627Seric 85b44da627Seric l = (d - str); 86b44da627Seric 87b44da627Seric if (dname_check_label(str, l) == -1) 88b44da627Seric return (-1); 89b44da627Seric 90b44da627Seric res += l + 1; 91b44da627Seric 92b44da627Seric if (dst) { 93b44da627Seric *dst++ = l; 94b44da627Seric max -= 1; 95b44da627Seric n = (l > max) ? max : l; 96b44da627Seric memmove(dst, str, n); 97b44da627Seric max -= n; 98b44da627Seric if (max == 0) 99b44da627Seric dst = NULL; 100b44da627Seric else 101b44da627Seric dst += n; 102b44da627Seric } 103b44da627Seric } 104b44da627Seric 105b44da627Seric if (dst) 106b44da627Seric *dst++ = '\0'; 107b44da627Seric 108b44da627Seric return (res + 1); 109b44da627Seric } 110b44da627Seric 111b44da627Seric static ssize_t 112b44da627Seric dname_expand(const unsigned char *data, size_t len, size_t offset, 113b44da627Seric size_t *newoffset, char *dst, size_t max) 114b44da627Seric { 115b44da627Seric size_t n, count, end, ptr, start; 116b44da627Seric ssize_t res; 117b44da627Seric 118b44da627Seric if (offset >= len) 119b44da627Seric return (-1); 120b44da627Seric 121b44da627Seric res = 0; 122b44da627Seric end = start = offset; 123b44da627Seric 124b44da627Seric for (; (n = data[offset]); ) { 125b44da627Seric if ((n & 0xc0) == 0xc0) { 126b44da627Seric if (offset + 2 > len) 127b44da627Seric return (-1); 128b44da627Seric ptr = 256 * (n & ~0xc0) + data[offset + 1]; 129b44da627Seric if (ptr >= start) 130b44da627Seric return (-1); 131b44da627Seric if (end < offset + 2) 132b44da627Seric end = offset + 2; 1336f68500aSeric offset = start = ptr; 134b44da627Seric continue; 135b44da627Seric } 136b44da627Seric if (offset + n + 1 > len) 137b44da627Seric return (-1); 138b44da627Seric 139b44da627Seric if (dname_check_label(data + offset + 1, n) == -1) 140b44da627Seric return (-1); 141b44da627Seric 142b44da627Seric /* copy n + at offset+1 */ 143b44da627Seric if (dst != NULL && max != 0) { 144b44da627Seric count = (max < n + 1) ? (max) : (n + 1); 145b44da627Seric memmove(dst, data + offset, count); 146b44da627Seric dst += count; 147b44da627Seric max -= count; 148b44da627Seric } 149b44da627Seric res += n + 1; 150b44da627Seric offset += n + 1; 151b44da627Seric if (end < offset) 152b44da627Seric end = offset; 153b44da627Seric } 154b44da627Seric if (end < offset + 1) 155b44da627Seric end = offset + 1; 156b44da627Seric 157b44da627Seric if (dst != NULL && max != 0) 158b44da627Seric dst[0] = 0; 159b44da627Seric if (newoffset) 160b44da627Seric *newoffset = end; 161b44da627Seric return (res + 1); 162b44da627Seric } 163b44da627Seric 164b44da627Seric void 165253ef892Sderaadt _asr_pack_init(struct asr_pack *pack, char *buf, size_t len) 166b44da627Seric { 167975956b6Seric pack->buf = buf; 168b44da627Seric pack->len = len; 169b44da627Seric pack->offset = 0; 170*92f75510Seric pack->err = 0; 171b44da627Seric } 172b44da627Seric 173975956b6Seric void 174253ef892Sderaadt _asr_unpack_init(struct asr_unpack *unpack, const char *buf, size_t len) 175975956b6Seric { 176975956b6Seric unpack->buf = buf; 177975956b6Seric unpack->len = len; 178975956b6Seric unpack->offset = 0; 179*92f75510Seric unpack->err = 0; 180975956b6Seric } 181975956b6Seric 182b44da627Seric static int 183f90bf415Seric unpack_data(struct asr_unpack *p, void *data, size_t len) 184b44da627Seric { 185b44da627Seric if (p->err) 186b44da627Seric return (-1); 187b44da627Seric 188b44da627Seric if (p->len - p->offset < len) { 189*92f75510Seric p->err = EOVERFLOW; 190b44da627Seric return (-1); 191b44da627Seric } 192b44da627Seric 193975956b6Seric memmove(data, p->buf + p->offset, len); 194b44da627Seric p->offset += len; 195b44da627Seric 196b44da627Seric return (0); 197b44da627Seric } 198b44da627Seric 199b44da627Seric static int 200f90bf415Seric unpack_u16(struct asr_unpack *p, uint16_t *u16) 201b44da627Seric { 202b44da627Seric if (unpack_data(p, u16, 2) == -1) 203b44da627Seric return (-1); 204b44da627Seric 205b44da627Seric *u16 = ntohs(*u16); 206b44da627Seric 207b44da627Seric return (0); 208b44da627Seric } 209b44da627Seric 210b44da627Seric static int 211f90bf415Seric unpack_u32(struct asr_unpack *p, uint32_t *u32) 212b44da627Seric { 213b44da627Seric if (unpack_data(p, u32, 4) == -1) 214b44da627Seric return (-1); 215b44da627Seric 216b44da627Seric *u32 = ntohl(*u32); 217b44da627Seric 218b44da627Seric return (0); 219b44da627Seric } 220b44da627Seric 221b44da627Seric static int 222f90bf415Seric unpack_inaddr(struct asr_unpack *p, struct in_addr *a) 223b44da627Seric { 224b44da627Seric return (unpack_data(p, a, 4)); 225b44da627Seric } 226b44da627Seric 227b44da627Seric static int 228f90bf415Seric unpack_in6addr(struct asr_unpack *p, struct in6_addr *a6) 229b44da627Seric { 230b44da627Seric return (unpack_data(p, a6, 16)); 231b44da627Seric } 232b44da627Seric 233b44da627Seric static int 234f90bf415Seric unpack_dname(struct asr_unpack *p, char *dst, size_t max) 235b44da627Seric { 236b44da627Seric ssize_t e; 237b44da627Seric 238b44da627Seric if (p->err) 239b44da627Seric return (-1); 240b44da627Seric 241975956b6Seric e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max); 242b44da627Seric if (e == -1) { 243*92f75510Seric p->err = EINVAL; 244b44da627Seric return (-1); 245b44da627Seric } 246b44da627Seric if (e < 0 || e > MAXDNAME) { 247*92f75510Seric p->err = ERANGE; 248b44da627Seric return (-1); 249b44da627Seric } 250b44da627Seric 251b44da627Seric return (0); 252b44da627Seric } 253b44da627Seric 254b44da627Seric int 255253ef892Sderaadt _asr_unpack_header(struct asr_unpack *p, struct asr_dns_header *h) 256b44da627Seric { 257b44da627Seric if (unpack_data(p, h, HFIXEDSZ) == -1) 258b44da627Seric return (-1); 259b44da627Seric 260b44da627Seric h->flags = ntohs(h->flags); 261b44da627Seric h->qdcount = ntohs(h->qdcount); 262b44da627Seric h->ancount = ntohs(h->ancount); 263b44da627Seric h->nscount = ntohs(h->nscount); 264b44da627Seric h->arcount = ntohs(h->arcount); 265b44da627Seric 266b44da627Seric return (0); 267b44da627Seric } 268b44da627Seric 269b44da627Seric int 270253ef892Sderaadt _asr_unpack_query(struct asr_unpack *p, struct asr_dns_query *q) 271b44da627Seric { 272b44da627Seric unpack_dname(p, q->q_dname, sizeof(q->q_dname)); 273b44da627Seric unpack_u16(p, &q->q_type); 274b44da627Seric unpack_u16(p, &q->q_class); 275b44da627Seric 276b44da627Seric return (p->err) ? (-1) : (0); 277b44da627Seric } 278b44da627Seric 279b44da627Seric int 280253ef892Sderaadt _asr_unpack_rr(struct asr_unpack *p, struct asr_dns_rr *rr) 281b44da627Seric { 282b44da627Seric uint16_t rdlen; 283b44da627Seric size_t save_offset; 284b44da627Seric 285b44da627Seric unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname)); 286b44da627Seric unpack_u16(p, &rr->rr_type); 287b44da627Seric unpack_u16(p, &rr->rr_class); 288b44da627Seric unpack_u32(p, &rr->rr_ttl); 289b44da627Seric unpack_u16(p, &rdlen); 290b44da627Seric 291b44da627Seric if (p->err) 292b44da627Seric return (-1); 293b44da627Seric 294b44da627Seric if (p->len - p->offset < rdlen) { 295*92f75510Seric p->err = EOVERFLOW; 296b44da627Seric return (-1); 297b44da627Seric } 298b44da627Seric 299b44da627Seric save_offset = p->offset; 300b44da627Seric 301b44da627Seric switch (rr->rr_type) { 302b44da627Seric 303b44da627Seric case T_CNAME: 304b44da627Seric unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname)); 305b44da627Seric break; 306b44da627Seric 307b44da627Seric case T_MX: 308b44da627Seric unpack_u16(p, &rr->rr.mx.preference); 309b44da627Seric unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange)); 310b44da627Seric break; 311b44da627Seric 312b44da627Seric case T_NS: 313b44da627Seric unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname)); 314b44da627Seric break; 315b44da627Seric 316b44da627Seric case T_PTR: 317b44da627Seric unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname)); 318b44da627Seric break; 319b44da627Seric 320b44da627Seric case T_SOA: 321b44da627Seric unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname)); 322b44da627Seric unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname)); 323b44da627Seric unpack_u32(p, &rr->rr.soa.serial); 324b44da627Seric unpack_u32(p, &rr->rr.soa.refresh); 325b44da627Seric unpack_u32(p, &rr->rr.soa.retry); 326b44da627Seric unpack_u32(p, &rr->rr.soa.expire); 327b44da627Seric unpack_u32(p, &rr->rr.soa.minimum); 328b44da627Seric break; 329b44da627Seric 330b44da627Seric case T_A: 331b44da627Seric if (rr->rr_class != C_IN) 332b44da627Seric goto other; 333b44da627Seric unpack_inaddr(p, &rr->rr.in_a.addr); 334b44da627Seric break; 335b44da627Seric 336b44da627Seric case T_AAAA: 337b44da627Seric if (rr->rr_class != C_IN) 338b44da627Seric goto other; 339b44da627Seric unpack_in6addr(p, &rr->rr.in_aaaa.addr6); 340b44da627Seric break; 341b44da627Seric default: 342b44da627Seric other: 343975956b6Seric rr->rr.other.rdata = p->buf + p->offset; 344b44da627Seric rr->rr.other.rdlen = rdlen; 345b44da627Seric p->offset += rdlen; 346b44da627Seric } 347b44da627Seric 348b44da627Seric if (p->err) 349b44da627Seric return (-1); 350b44da627Seric 351b44da627Seric /* make sure that the advertised rdlen is really ok */ 352b44da627Seric if (p->offset - save_offset != rdlen) 353*92f75510Seric p->err = EINVAL; 354b44da627Seric 355b44da627Seric return (p->err) ? (-1) : (0); 356b44da627Seric } 357b44da627Seric 358b44da627Seric static int 359f90bf415Seric pack_data(struct asr_pack *p, const void *data, size_t len) 360b44da627Seric { 361b44da627Seric if (p->err) 362b44da627Seric return (-1); 363b44da627Seric 364b44da627Seric if (p->len < p->offset + len) { 365*92f75510Seric p->err = EOVERFLOW; 366b44da627Seric return (-1); 367b44da627Seric } 368b44da627Seric 369975956b6Seric memmove(p->buf + p->offset, data, len); 370b44da627Seric p->offset += len; 371b44da627Seric 372b44da627Seric return (0); 373b44da627Seric } 374b44da627Seric 375b44da627Seric static int 376f90bf415Seric pack_u16(struct asr_pack *p, uint16_t v) 377b44da627Seric { 378b44da627Seric v = htons(v); 379b44da627Seric 380b44da627Seric return (pack_data(p, &v, 2)); 381b44da627Seric } 382b44da627Seric 383b44da627Seric static int 384f90bf415Seric pack_dname(struct asr_pack *p, const char *dname) 385b44da627Seric { 386b44da627Seric /* dname compression would be nice to have here. 387b44da627Seric * need additionnal context. 388b44da627Seric */ 389b44da627Seric return (pack_data(p, dname, strlen(dname) + 1)); 390b44da627Seric } 391b44da627Seric 392b44da627Seric int 393253ef892Sderaadt _asr_pack_header(struct asr_pack *p, const struct asr_dns_header *h) 394b44da627Seric { 395f90bf415Seric struct asr_dns_header c; 396b44da627Seric 397b44da627Seric c.id = h->id; 398b44da627Seric c.flags = htons(h->flags); 399b44da627Seric c.qdcount = htons(h->qdcount); 400b44da627Seric c.ancount = htons(h->ancount); 401b44da627Seric c.nscount = htons(h->nscount); 402b44da627Seric c.arcount = htons(h->arcount); 403b44da627Seric 404b44da627Seric return (pack_data(p, &c, HFIXEDSZ)); 405b44da627Seric } 406b44da627Seric 407b44da627Seric int 408253ef892Sderaadt _asr_pack_query(struct asr_pack *p, uint16_t type, uint16_t class, const char *dname) 409b44da627Seric { 410b44da627Seric pack_dname(p, dname); 411b44da627Seric pack_u16(p, type); 412b44da627Seric pack_u16(p, class); 413b44da627Seric 414b44da627Seric return (p->err) ? (-1) : (0); 415b44da627Seric } 416b44da627Seric 417b44da627Seric int 418253ef892Sderaadt _asr_sockaddr_from_str(struct sockaddr *sa, int family, const char *str) 419b44da627Seric { 420b44da627Seric struct in_addr ina; 421b44da627Seric struct in6_addr in6a; 422b44da627Seric struct sockaddr_in *sin; 423b44da627Seric struct sockaddr_in6 *sin6; 424c4cedadeSeric char *cp, *str2; 425c4cedadeSeric const char *errstr; 426b44da627Seric 427b44da627Seric switch (family) { 428b44da627Seric case PF_UNSPEC: 429253ef892Sderaadt if (_asr_sockaddr_from_str(sa, PF_INET, str) == 0) 430b44da627Seric return (0); 431253ef892Sderaadt return _asr_sockaddr_from_str(sa, PF_INET6, str); 432b44da627Seric 433b44da627Seric case PF_INET: 434b44da627Seric if (inet_pton(PF_INET, str, &ina) != 1) 435b44da627Seric return (-1); 436b44da627Seric 437b44da627Seric sin = (struct sockaddr_in *)sa; 438b44da627Seric memset(sin, 0, sizeof *sin); 439b44da627Seric sin->sin_len = sizeof(struct sockaddr_in); 440b44da627Seric sin->sin_family = PF_INET; 441b44da627Seric sin->sin_addr.s_addr = ina.s_addr; 442b44da627Seric return (0); 443b44da627Seric 444b44da627Seric case PF_INET6: 445c4cedadeSeric cp = strchr(str, SCOPE_DELIMITER); 446c4cedadeSeric if (cp) { 447c4cedadeSeric str2 = strdup(str); 448c4cedadeSeric if (str2 == NULL) 449c4cedadeSeric return (-1); 450c4cedadeSeric str2[cp - str] = '\0'; 451c4cedadeSeric if (inet_pton(PF_INET6, str2, &in6a) != 1) { 452c4cedadeSeric free(str2); 453c4cedadeSeric return (-1); 454c4cedadeSeric } 455c4cedadeSeric cp++; 456c4cedadeSeric free(str2); 457c4cedadeSeric } else if (inet_pton(PF_INET6, str, &in6a) != 1) 458b44da627Seric return (-1); 459b44da627Seric 460b44da627Seric sin6 = (struct sockaddr_in6 *)sa; 461b44da627Seric memset(sin6, 0, sizeof *sin6); 462b44da627Seric sin6->sin6_len = sizeof(struct sockaddr_in6); 463b44da627Seric sin6->sin6_family = PF_INET6; 464b44da627Seric sin6->sin6_addr = in6a; 465c4cedadeSeric 466c4cedadeSeric if (cp == NULL) 467c4cedadeSeric return (0); 468c4cedadeSeric 469c4cedadeSeric if (IN6_IS_ADDR_LINKLOCAL(&in6a) || 470c4cedadeSeric IN6_IS_ADDR_MC_LINKLOCAL(&in6a) || 471c4cedadeSeric IN6_IS_ADDR_MC_INTFACELOCAL(&in6a)) 472c4cedadeSeric if ((sin6->sin6_scope_id = if_nametoindex(cp))) 473c4cedadeSeric return (0); 474c4cedadeSeric 475c4cedadeSeric sin6->sin6_scope_id = strtonum(cp, 0, UINT32_MAX, &errstr); 476c4cedadeSeric if (errstr) 477c4cedadeSeric return (-1); 478b44da627Seric return (0); 479b44da627Seric 480b44da627Seric default: 481b44da627Seric break; 482b44da627Seric } 483b44da627Seric 484b44da627Seric return (-1); 485b44da627Seric } 4865bd9e5c2Seric 4875bd9e5c2Seric ssize_t 488253ef892Sderaadt _asr_addr_as_fqdn(const char *addr, int family, char *dst, size_t max) 4895bd9e5c2Seric { 4905bd9e5c2Seric const struct in6_addr *in6_addr; 4915bd9e5c2Seric in_addr_t in_addr; 4925bd9e5c2Seric 4935bd9e5c2Seric switch (family) { 4945bd9e5c2Seric case AF_INET: 4955bd9e5c2Seric in_addr = ntohl(*((const in_addr_t *)addr)); 4965bd9e5c2Seric snprintf(dst, max, 4975bd9e5c2Seric "%d.%d.%d.%d.in-addr.arpa.", 4985bd9e5c2Seric in_addr & 0xff, 4995bd9e5c2Seric (in_addr >> 8) & 0xff, 5005bd9e5c2Seric (in_addr >> 16) & 0xff, 5015bd9e5c2Seric (in_addr >> 24) & 0xff); 5025bd9e5c2Seric break; 5035bd9e5c2Seric case AF_INET6: 5045bd9e5c2Seric in6_addr = (const struct in6_addr *)addr; 5055bd9e5c2Seric snprintf(dst, max, 5065bd9e5c2Seric "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 5075bd9e5c2Seric "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 5085bd9e5c2Seric "ip6.arpa.", 5095bd9e5c2Seric in6_addr->s6_addr[15] & 0xf, 5105bd9e5c2Seric (in6_addr->s6_addr[15] >> 4) & 0xf, 5115bd9e5c2Seric in6_addr->s6_addr[14] & 0xf, 5125bd9e5c2Seric (in6_addr->s6_addr[14] >> 4) & 0xf, 5135bd9e5c2Seric in6_addr->s6_addr[13] & 0xf, 5145bd9e5c2Seric (in6_addr->s6_addr[13] >> 4) & 0xf, 5155bd9e5c2Seric in6_addr->s6_addr[12] & 0xf, 5165bd9e5c2Seric (in6_addr->s6_addr[12] >> 4) & 0xf, 5175bd9e5c2Seric in6_addr->s6_addr[11] & 0xf, 5185bd9e5c2Seric (in6_addr->s6_addr[11] >> 4) & 0xf, 5195bd9e5c2Seric in6_addr->s6_addr[10] & 0xf, 5205bd9e5c2Seric (in6_addr->s6_addr[10] >> 4) & 0xf, 5215bd9e5c2Seric in6_addr->s6_addr[9] & 0xf, 5225bd9e5c2Seric (in6_addr->s6_addr[9] >> 4) & 0xf, 5235bd9e5c2Seric in6_addr->s6_addr[8] & 0xf, 5245bd9e5c2Seric (in6_addr->s6_addr[8] >> 4) & 0xf, 5255bd9e5c2Seric in6_addr->s6_addr[7] & 0xf, 5265bd9e5c2Seric (in6_addr->s6_addr[7] >> 4) & 0xf, 5275bd9e5c2Seric in6_addr->s6_addr[6] & 0xf, 5285bd9e5c2Seric (in6_addr->s6_addr[6] >> 4) & 0xf, 5295bd9e5c2Seric in6_addr->s6_addr[5] & 0xf, 5305bd9e5c2Seric (in6_addr->s6_addr[5] >> 4) & 0xf, 5315bd9e5c2Seric in6_addr->s6_addr[4] & 0xf, 5325bd9e5c2Seric (in6_addr->s6_addr[4] >> 4) & 0xf, 5335bd9e5c2Seric in6_addr->s6_addr[3] & 0xf, 5345bd9e5c2Seric (in6_addr->s6_addr[3] >> 4) & 0xf, 5355bd9e5c2Seric in6_addr->s6_addr[2] & 0xf, 5365bd9e5c2Seric (in6_addr->s6_addr[2] >> 4) & 0xf, 5375bd9e5c2Seric in6_addr->s6_addr[1] & 0xf, 5385bd9e5c2Seric (in6_addr->s6_addr[1] >> 4) & 0xf, 5395bd9e5c2Seric in6_addr->s6_addr[0] & 0xf, 5405bd9e5c2Seric (in6_addr->s6_addr[0] >> 4) & 0xf); 5415bd9e5c2Seric break; 5425bd9e5c2Seric default: 5435bd9e5c2Seric return (-1); 5445bd9e5c2Seric } 5455bd9e5c2Seric return (0); 5465bd9e5c2Seric } 547