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