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