1 /* $OpenBSD: gethostnamadr.c,v 1.7 2013/05/27 17:31:01 eric Exp $ */ 2 /* 3 * Copyright (c) 2012 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 struct hostent *_gethostbyname(const char *, int); 30 static void _fillhostent(const struct hostent *, struct hostent *, char *buf, 31 size_t); 32 33 static struct hostent _hostent; 34 static char _entbuf[4096]; 35 36 static char *_empty[] = { NULL, }; 37 38 static void 39 _fillhostent(const struct hostent *h, struct hostent *r, char *buf, size_t len) 40 { 41 char **ptr, *end, *pos; 42 size_t n, i; 43 int naliases, naddrs; 44 45 bzero(buf, len); 46 bzero(r, sizeof(*r)); 47 r->h_aliases = _empty; 48 r->h_addr_list = _empty; 49 50 end = buf + len; 51 ptr = (char **)ALIGN(buf); 52 53 if ((char *)ptr >= end) 54 return; 55 56 for (naliases = 0; h->h_aliases[naliases]; naliases++) 57 ; 58 for (naddrs = 0; h->h_addr_list[naddrs]; naddrs++) 59 ; 60 61 pos = (char *)(ptr + (naliases + 1) + (naddrs + 1)); 62 if (pos >= end) 63 return; 64 65 r->h_name = NULL; 66 r->h_addrtype = h->h_addrtype; 67 r->h_length = h->h_length; 68 r->h_aliases = ptr; 69 r->h_addr_list = ptr + naliases + 1; 70 71 n = strlcpy(pos, h->h_name, end - pos); 72 if (n >= end - pos) 73 return; 74 r->h_name = pos; 75 pos += n + 1; 76 77 for (i = 0; i < naliases; i++) { 78 n = strlcpy(pos, h->h_aliases[i], end - pos); 79 if (n >= end - pos) 80 return; 81 r->h_aliases[i] = pos; 82 pos += n + 1; 83 } 84 85 pos = (char *)ALIGN(pos); 86 if (pos >= end) 87 return; 88 89 for (i = 0; i < naddrs; i++) { 90 if (r->h_length > end - pos) 91 return; 92 memmove(pos, h->h_addr_list[i], r->h_length); 93 r->h_addr_list[i] = pos; 94 pos += r->h_length; 95 } 96 } 97 98 static struct hostent * 99 _gethostbyname(const char *name, int af) 100 { 101 struct async *as; 102 struct async_res ar; 103 104 if (af == -1) 105 as = gethostbyname_async(name, NULL); 106 else 107 as = gethostbyname2_async(name, af, NULL); 108 109 if (as == NULL) { 110 h_errno = NETDB_INTERNAL; 111 return (NULL); 112 } 113 114 async_run_sync(as, &ar); 115 116 errno = ar.ar_errno; 117 h_errno = ar.ar_h_errno; 118 if (ar.ar_hostent == NULL) 119 return (NULL); 120 121 _fillhostent(ar.ar_hostent, &_hostent, _entbuf, sizeof(_entbuf)); 122 free(ar.ar_hostent); 123 124 return (&_hostent); 125 } 126 127 struct hostent * 128 gethostbyname(const char *name) 129 { 130 struct hostent *h; 131 132 res_init(); 133 134 if (_res.options & RES_USE_INET6 && 135 (h = _gethostbyname(name, AF_INET6))) 136 return (h); 137 138 return _gethostbyname(name, AF_INET); 139 } 140 141 struct hostent * 142 gethostbyname2(const char *name, int af) 143 { 144 res_init(); 145 146 return _gethostbyname(name, af); 147 } 148 149 struct hostent * 150 gethostbyaddr(const void *addr, socklen_t len, int af) 151 { 152 struct async *as; 153 struct async_res ar; 154 155 res_init(); 156 157 as = gethostbyaddr_async(addr, len, af, NULL); 158 if (as == NULL) { 159 h_errno = NETDB_INTERNAL; 160 return (NULL); 161 } 162 163 async_run_sync(as, &ar); 164 165 errno = ar.ar_errno; 166 h_errno = ar.ar_h_errno; 167 if (ar.ar_hostent == NULL) 168 return (NULL); 169 170 _fillhostent(ar.ar_hostent, &_hostent, _entbuf, sizeof(_entbuf)); 171 free(ar.ar_hostent); 172 173 return (&_hostent); 174 } 175