1 /* $OpenBSD: gethostnamadr.c,v 1.10 2014/03/25 19:48:11 eric Exp $ */ 2 /* 3 * Copyright (c) 2012,2013 Eric Faurot <eric@openbsd.org> 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 <netinet/in.h> 20 21 #include <errno.h> 22 #include <resolv.h> 23 #include <stdint.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include "asr.h" 28 29 static int _gethostbyname(const char *, int, struct hostent *, char *, size_t, 30 int *); 31 static int _fillhostent(const struct hostent *, struct hostent *, char *, 32 size_t); 33 34 static struct hostent _hostent; 35 static char _entbuf[4096]; 36 37 static char *_empty[] = { NULL, }; 38 39 static int 40 _fillhostent(const struct hostent *h, struct hostent *r, char *buf, size_t len) 41 { 42 char **ptr, *end, *pos; 43 size_t n, i; 44 int naliases, naddrs; 45 46 bzero(buf, len); 47 bzero(r, sizeof(*r)); 48 r->h_aliases = _empty; 49 r->h_addr_list = _empty; 50 51 end = buf + len; 52 ptr = (char **)ALIGN(buf); 53 54 if ((char *)ptr >= end) 55 return (ERANGE); 56 57 for (naliases = 0; h->h_aliases[naliases]; naliases++) 58 ; 59 for (naddrs = 0; h->h_addr_list[naddrs]; naddrs++) 60 ; 61 62 pos = (char *)(ptr + (naliases + 1) + (naddrs + 1)); 63 if (pos >= end) 64 return (ERANGE); 65 66 r->h_name = NULL; 67 r->h_addrtype = h->h_addrtype; 68 r->h_length = h->h_length; 69 r->h_aliases = ptr; 70 r->h_addr_list = ptr + naliases + 1; 71 72 n = strlcpy(pos, h->h_name, end - pos); 73 if (n >= end - pos) 74 return (ERANGE); 75 r->h_name = pos; 76 pos += n + 1; 77 78 for (i = 0; i < naliases; i++) { 79 n = strlcpy(pos, h->h_aliases[i], end - pos); 80 if (n >= end - pos) 81 return (ERANGE); 82 r->h_aliases[i] = pos; 83 pos += n + 1; 84 } 85 86 pos = (char *)ALIGN(pos); 87 if (pos >= end) 88 return (ERANGE); 89 90 for (i = 0; i < naddrs; i++) { 91 if (r->h_length > end - pos) 92 return (ERANGE); 93 memmove(pos, h->h_addr_list[i], r->h_length); 94 r->h_addr_list[i] = pos; 95 pos += r->h_length; 96 } 97 98 return (0); 99 } 100 101 static int 102 _gethostbyname(const char *name, int af, struct hostent *ret, char *buf, 103 size_t buflen, int *h_errnop) 104 { 105 struct asr_query *as; 106 struct asr_result ar; 107 int r; 108 109 if (af == -1) 110 as = gethostbyname_async(name, NULL); 111 else 112 as = gethostbyname2_async(name, af, NULL); 113 114 if (as == NULL) 115 return (errno); 116 117 asr_run_sync(as, &ar); 118 119 errno = ar.ar_errno; 120 *h_errnop = ar.ar_h_errno; 121 if (ar.ar_hostent == NULL) 122 return (0); 123 124 r = _fillhostent(ar.ar_hostent, ret, buf, buflen); 125 free(ar.ar_hostent); 126 127 return (r); 128 } 129 130 struct hostent * 131 gethostbyname(const char *name) 132 { 133 struct hostent *h; 134 135 res_init(); 136 137 if (_res.options & RES_USE_INET6 && 138 (h = gethostbyname2(name, AF_INET6))) 139 return (h); 140 141 return gethostbyname2(name, AF_INET); 142 } 143 144 struct hostent * 145 gethostbyname2(const char *name, int af) 146 { 147 int r; 148 149 res_init(); 150 151 r = _gethostbyname(name, af, &_hostent, _entbuf, sizeof(_entbuf), 152 &h_errno); 153 if (r) { 154 h_errno = NETDB_INTERNAL; 155 errno = r; 156 } 157 158 if (h_errno) 159 return (NULL); 160 161 return (&_hostent); 162 } 163 164 struct hostent * 165 gethostbyaddr(const void *addr, socklen_t len, int af) 166 { 167 struct asr_query *as; 168 struct asr_result ar; 169 int r; 170 171 res_init(); 172 173 as = gethostbyaddr_async(addr, len, af, NULL); 174 if (as == NULL) { 175 h_errno = NETDB_INTERNAL; 176 return (NULL); 177 } 178 179 asr_run_sync(as, &ar); 180 181 errno = ar.ar_errno; 182 h_errno = ar.ar_h_errno; 183 if (ar.ar_hostent == NULL) 184 return (NULL); 185 186 r = _fillhostent(ar.ar_hostent, &_hostent, _entbuf, sizeof(_entbuf)); 187 free(ar.ar_hostent); 188 189 if (r) { 190 h_errno = NETDB_INTERNAL; 191 errno = r; 192 return (NULL); 193 } 194 195 return (&_hostent); 196 } 197