1 1.1 elric /* $NetBSD: getaddrinfo.c,v 1.3 2023/06/19 21:41:45 christos Exp $ */ 2 1.1 elric 3 1.1 elric /* 4 1.1 elric * Copyright (c) 1999 - 2001 Kungliga Tekniska Hgskolan 5 1.1 elric * (Royal Institute of Technology, Stockholm, Sweden). 6 1.1 elric * All rights reserved. 7 1.1 elric * 8 1.1 elric * Redistribution and use in source and binary forms, with or without 9 1.1 elric * modification, are permitted provided that the following conditions 10 1.1 elric * are met: 11 1.1 elric * 12 1.1 elric * 1. Redistributions of source code must retain the above copyright 13 1.1 elric * notice, this list of conditions and the following disclaimer. 14 1.1 elric * 15 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 elric * notice, this list of conditions and the following disclaimer in the 17 1.1 elric * documentation and/or other materials provided with the distribution. 18 1.1 elric * 19 1.1 elric * 3. Neither the name of the Institute nor the names of its contributors 20 1.1 elric * may be used to endorse or promote products derived from this software 21 1.1 elric * without specific prior written permission. 22 1.1 elric * 23 1.1 elric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 1.1 elric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 elric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.1 elric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 1.1 elric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.1 elric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.1 elric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.1 elric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.1 elric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.1 elric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.1 elric * SUCH DAMAGE. 34 1.1 elric */ 35 1.1 elric 36 1.1 elric #include <config.h> 37 1.1 elric 38 1.1 elric #include <krb5/roken.h> 39 1.1 elric 40 1.1 elric /* 41 1.1 elric * uses hints->ai_socktype and hints->ai_protocol 42 1.1 elric */ 43 1.1 elric 44 1.1 elric static int 45 1.1 elric get_port_protocol_socktype (const char *servname, 46 1.1 elric const struct addrinfo *hints, 47 1.1 elric int *port, 48 1.1 elric int *protocol, 49 1.1 elric int *socktype) 50 1.1 elric { 51 1.1 elric struct servent *se; 52 1.1 elric const char *proto_str = NULL; 53 1.1 elric 54 1.1 elric *socktype = 0; 55 1.1 elric 56 1.1 elric if (hints != NULL && hints->ai_protocol != 0) { 57 1.1 elric struct protoent *protoent = getprotobynumber (hints->ai_protocol); 58 1.1 elric 59 1.1 elric if (protoent == NULL) 60 1.1 elric return EAI_SOCKTYPE; /* XXX */ 61 1.1 elric 62 1.1 elric proto_str = protoent->p_name; 63 1.1 elric *protocol = protoent->p_proto; 64 1.1 elric } 65 1.1 elric 66 1.1 elric if (hints != NULL) 67 1.1 elric *socktype = hints->ai_socktype; 68 1.1 elric 69 1.1 elric if (*socktype == SOCK_STREAM) { 70 1.1 elric se = getservbyname (servname, proto_str ? proto_str : "tcp"); 71 1.1 elric if (proto_str == NULL) 72 1.1 elric *protocol = IPPROTO_TCP; 73 1.1 elric } else if (*socktype == SOCK_DGRAM) { 74 1.1 elric se = getservbyname (servname, proto_str ? proto_str : "udp"); 75 1.1 elric if (proto_str == NULL) 76 1.1 elric *protocol = IPPROTO_UDP; 77 1.1 elric } else if (*socktype == 0) { 78 1.1 elric if (proto_str != NULL) { 79 1.1 elric se = getservbyname (servname, proto_str); 80 1.1 elric } else { 81 1.1 elric se = getservbyname (servname, "tcp"); 82 1.1 elric *protocol = IPPROTO_TCP; 83 1.1 elric *socktype = SOCK_STREAM; 84 1.1 elric if (se == NULL) { 85 1.1 elric se = getservbyname (servname, "udp"); 86 1.1 elric *protocol = IPPROTO_UDP; 87 1.1 elric *socktype = SOCK_DGRAM; 88 1.1 elric } 89 1.1 elric } 90 1.1 elric } else 91 1.1 elric return EAI_SOCKTYPE; 92 1.1 elric 93 1.1 elric if (se == NULL) { 94 1.1 elric char *endstr; 95 1.1 elric 96 1.1 elric *port = htons(strtol (servname, &endstr, 10)); 97 1.1 elric if (servname == endstr) 98 1.1 elric return EAI_NONAME; 99 1.1 elric } else { 100 1.1 elric *port = se->s_port; 101 1.1 elric } 102 1.1 elric return 0; 103 1.1 elric } 104 1.1 elric 105 1.1 elric static int 106 1.1 elric add_one (int port, int protocol, int socktype, 107 1.1 elric struct addrinfo ***ptr, 108 1.1 elric int (*func)(struct addrinfo *, void *data, int port), 109 1.1 elric void *data, 110 1.1 elric char *canonname) 111 1.1 elric { 112 1.1 elric struct addrinfo *a; 113 1.1 elric int ret; 114 1.1 elric 115 1.1 elric a = malloc (sizeof (*a)); 116 1.1 elric if (a == NULL) 117 1.1 elric return EAI_MEMORY; 118 1.1 elric memset (a, 0, sizeof(*a)); 119 1.1 elric a->ai_flags = 0; 120 1.1 elric a->ai_next = NULL; 121 1.1 elric a->ai_protocol = protocol; 122 1.1 elric a->ai_socktype = socktype; 123 1.1 elric a->ai_canonname = canonname; 124 1.1 elric ret = (*func)(a, data, port); 125 1.1 elric if (ret) { 126 1.1 elric free (a); 127 1.1 elric return ret; 128 1.1 elric } 129 1.1 elric **ptr = a; 130 1.1 elric *ptr = &a->ai_next; 131 1.1 elric return 0; 132 1.1 elric } 133 1.1 elric 134 1.1 elric static int 135 1.1 elric const_v4 (struct addrinfo *a, void *data, int port) 136 1.1 elric { 137 1.1 elric struct sockaddr_in *sin4; 138 1.1 elric struct in_addr *addr = (struct in_addr *)data; 139 1.1 elric 140 1.1 elric a->ai_family = PF_INET; 141 1.1 elric a->ai_addrlen = sizeof(*sin4); 142 1.1 elric a->ai_addr = malloc (sizeof(*sin4)); 143 1.1 elric if (a->ai_addr == NULL) 144 1.1 elric return EAI_MEMORY; 145 1.1 elric sin4 = (struct sockaddr_in *)a->ai_addr; 146 1.1 elric memset (sin4, 0, sizeof(*sin4)); 147 1.1 elric sin4->sin_family = AF_INET; 148 1.1 elric sin4->sin_port = port; 149 1.1 elric sin4->sin_addr = *addr; 150 1.1 elric return 0; 151 1.1 elric } 152 1.1 elric 153 1.1 elric #ifdef HAVE_IPV6 154 1.1 elric static int 155 1.1 elric const_v6 (struct addrinfo *a, void *data, int port) 156 1.1 elric { 157 1.1 elric struct sockaddr_in6 *sin6; 158 1.1 elric struct in6_addr *addr = (struct in6_addr *)data; 159 1.1 elric 160 1.1 elric a->ai_family = PF_INET6; 161 1.1 elric a->ai_addrlen = sizeof(*sin6); 162 1.1 elric a->ai_addr = malloc (sizeof(*sin6)); 163 1.1 elric if (a->ai_addr == NULL) 164 1.1 elric return EAI_MEMORY; 165 1.1 elric sin6 = (struct sockaddr_in6 *)a->ai_addr; 166 1.1 elric memset (sin6, 0, sizeof(*sin6)); 167 1.1 elric sin6->sin6_family = AF_INET6; 168 1.1 elric sin6->sin6_port = port; 169 1.1 elric sin6->sin6_addr = *addr; 170 1.1 elric return 0; 171 1.1 elric } 172 1.1 elric #endif 173 1.1 elric 174 1.1 elric /* this is mostly a hack for some versions of AIX that has a prototype 175 1.1 elric for in6addr_loopback but no actual symbol in libc */ 176 1.1 elric #if defined(HAVE_IPV6) && !defined(HAVE_IN6ADDR_LOOPBACK) && defined(IN6ADDR_LOOPBACK_INIT) 177 1.1 elric #define in6addr_loopback _roken_in6addr_loopback 178 1.1 elric struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 179 1.1 elric #endif 180 1.1 elric 181 1.1 elric static int 182 1.1 elric get_null (const struct addrinfo *hints, 183 1.1 elric int port, int protocol, int socktype, 184 1.1 elric struct addrinfo **res) 185 1.1 elric { 186 1.1 elric struct in_addr v4_addr; 187 1.1 elric #ifdef HAVE_IPV6 188 1.1 elric struct in6_addr v6_addr; 189 1.1 elric #endif 190 1.1 elric struct addrinfo *first = NULL; 191 1.1 elric struct addrinfo **current = &first; 192 1.1 elric int family = PF_UNSPEC; 193 1.3 christos int ret = 0; 194 1.1 elric 195 1.1 elric if (hints != NULL) 196 1.1 elric family = hints->ai_family; 197 1.1 elric 198 1.1 elric if (hints && hints->ai_flags & AI_PASSIVE) { 199 1.1 elric v4_addr.s_addr = INADDR_ANY; 200 1.1 elric #ifdef HAVE_IPV6 201 1.1 elric v6_addr = in6addr_any; 202 1.1 elric #endif 203 1.1 elric } else { 204 1.1 elric v4_addr.s_addr = htonl(INADDR_LOOPBACK); 205 1.1 elric #ifdef HAVE_IPV6 206 1.1 elric v6_addr = in6addr_loopback; 207 1.1 elric #endif 208 1.1 elric } 209 1.1 elric 210 1.1 elric #ifdef HAVE_IPV6 211 1.1 elric if (family == PF_INET6 || family == PF_UNSPEC) { 212 1.1 elric ret = add_one (port, protocol, socktype, 213 1.1 elric ¤t, const_v6, &v6_addr, NULL); 214 1.3 christos if (ret) 215 1.3 christos return ret; 216 1.1 elric } 217 1.1 elric #endif 218 1.1 elric if (family == PF_INET || family == PF_UNSPEC) { 219 1.1 elric ret = add_one (port, protocol, socktype, 220 1.1 elric ¤t, const_v4, &v4_addr, NULL); 221 1.1 elric } 222 1.1 elric *res = first; 223 1.3 christos return ret; 224 1.1 elric } 225 1.1 elric 226 1.1 elric static int 227 1.1 elric add_hostent (int port, int protocol, int socktype, 228 1.1 elric struct addrinfo ***current, 229 1.1 elric int (*func)(struct addrinfo *, void *data, int port), 230 1.1 elric struct hostent *he, int *flags) 231 1.1 elric { 232 1.1 elric int ret; 233 1.1 elric char *canonname = NULL; 234 1.1 elric char **h; 235 1.1 elric 236 1.1 elric if (*flags & AI_CANONNAME) { 237 1.1 elric struct hostent *he2 = NULL; 238 1.1 elric const char *tmp_canon; 239 1.1 elric 240 1.1 elric tmp_canon = hostent_find_fqdn (he); 241 1.1 elric if (strchr (tmp_canon, '.') == NULL) { 242 1.1 elric int error; 243 1.1 elric 244 1.1 elric he2 = getipnodebyaddr (he->h_addr_list[0], he->h_length, 245 1.1 elric he->h_addrtype, &error); 246 1.1 elric if (he2 != NULL) { 247 1.1 elric const char *tmp = hostent_find_fqdn (he2); 248 1.1 elric 249 1.1 elric if (strchr (tmp, '.') != NULL) 250 1.1 elric tmp_canon = tmp; 251 1.1 elric } 252 1.1 elric } 253 1.1 elric 254 1.1 elric canonname = strdup (tmp_canon); 255 1.1 elric if (he2 != NULL) 256 1.1 elric freehostent (he2); 257 1.1 elric if (canonname == NULL) 258 1.1 elric return EAI_MEMORY; 259 1.1 elric } 260 1.1 elric 261 1.1 elric for (h = he->h_addr_list; *h != NULL; ++h) { 262 1.1 elric ret = add_one (port, protocol, socktype, 263 1.1 elric current, func, *h, canonname); 264 1.1 elric if (ret) 265 1.1 elric return ret; 266 1.1 elric if (*flags & AI_CANONNAME) { 267 1.1 elric *flags &= ~AI_CANONNAME; 268 1.1 elric canonname = NULL; 269 1.1 elric } 270 1.1 elric } 271 1.1 elric return 0; 272 1.1 elric } 273 1.1 elric 274 1.1 elric static int 275 1.1 elric get_number (const char *nodename, 276 1.1 elric const struct addrinfo *hints, 277 1.1 elric int port, int protocol, int socktype, 278 1.1 elric struct addrinfo **res) 279 1.1 elric { 280 1.1 elric struct addrinfo *first = NULL; 281 1.1 elric struct addrinfo **current = &first; 282 1.1 elric int family = PF_UNSPEC; 283 1.1 elric int ret; 284 1.1 elric 285 1.1 elric if (hints != NULL) { 286 1.1 elric family = hints->ai_family; 287 1.1 elric } 288 1.1 elric 289 1.1 elric #ifdef HAVE_IPV6 290 1.1 elric if (family == PF_INET6 || family == PF_UNSPEC) { 291 1.1 elric struct in6_addr v6_addr; 292 1.1 elric 293 1.1 elric if (inet_pton (PF_INET6, nodename, &v6_addr) == 1) { 294 1.1 elric ret = add_one (port, protocol, socktype, 295 1.1 elric ¤t, const_v6, &v6_addr, NULL); 296 1.1 elric *res = first; 297 1.1 elric return ret; 298 1.1 elric } 299 1.1 elric } 300 1.1 elric #endif 301 1.1 elric if (family == PF_INET || family == PF_UNSPEC) { 302 1.1 elric struct in_addr v4_addr; 303 1.1 elric 304 1.1 elric if (inet_pton (PF_INET, nodename, &v4_addr) == 1) { 305 1.1 elric ret = add_one (port, protocol, socktype, 306 1.1 elric ¤t, const_v4, &v4_addr, NULL); 307 1.1 elric *res = first; 308 1.1 elric return ret; 309 1.1 elric } 310 1.1 elric } 311 1.1 elric return EAI_NONAME; 312 1.1 elric } 313 1.1 elric 314 1.1 elric static int 315 1.1 elric get_nodes (const char *nodename, 316 1.1 elric const struct addrinfo *hints, 317 1.1 elric int port, int protocol, int socktype, 318 1.1 elric struct addrinfo **res) 319 1.1 elric { 320 1.1 elric struct addrinfo *first = NULL; 321 1.1 elric struct addrinfo **current = &first; 322 1.1 elric int family = PF_UNSPEC; 323 1.1 elric int flags = 0; 324 1.1 elric int ret = EAI_NONAME; 325 1.1 elric int error; 326 1.1 elric 327 1.1 elric if (hints != NULL) { 328 1.1 elric family = hints->ai_family; 329 1.1 elric flags = hints->ai_flags; 330 1.1 elric } 331 1.1 elric 332 1.1 elric #ifdef HAVE_IPV6 333 1.1 elric if (family == PF_INET6 || family == PF_UNSPEC) { 334 1.1 elric struct hostent *he; 335 1.1 elric 336 1.1 elric he = getipnodebyname (nodename, PF_INET6, 0, &error); 337 1.1 elric 338 1.1 elric if (he != NULL) { 339 1.1 elric ret = add_hostent (port, protocol, socktype, 340 1.1 elric ¤t, const_v6, he, &flags); 341 1.1 elric freehostent (he); 342 1.1 elric } 343 1.1 elric } 344 1.1 elric #endif 345 1.1 elric if (family == PF_INET || family == PF_UNSPEC) { 346 1.1 elric struct hostent *he; 347 1.1 elric 348 1.1 elric he = getipnodebyname (nodename, PF_INET, 0, &error); 349 1.1 elric 350 1.1 elric if (he != NULL) { 351 1.1 elric ret = add_hostent (port, protocol, socktype, 352 1.1 elric ¤t, const_v4, he, &flags); 353 1.1 elric freehostent (he); 354 1.1 elric } 355 1.1 elric } 356 1.1 elric *res = first; 357 1.1 elric return ret; 358 1.1 elric } 359 1.1 elric 360 1.1 elric /* 361 1.1 elric * hints: 362 1.1 elric * 363 1.1 elric * struct addrinfo { 364 1.1 elric * int ai_flags; 365 1.1 elric * int ai_family; 366 1.1 elric * int ai_socktype; 367 1.1 elric * int ai_protocol; 368 1.1 elric * ... 369 1.1 elric * }; 370 1.1 elric */ 371 1.1 elric 372 1.1 elric ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 373 1.1 elric getaddrinfo(const char *nodename, 374 1.1 elric const char *servname, 375 1.1 elric const struct addrinfo *hints, 376 1.1 elric struct addrinfo **res) 377 1.1 elric { 378 1.1 elric int ret; 379 1.1 elric int port = 0; 380 1.1 elric int protocol = 0; 381 1.1 elric int socktype = 0; 382 1.1 elric 383 1.1 elric *res = NULL; 384 1.1 elric 385 1.1 elric if (servname == NULL && nodename == NULL) 386 1.1 elric return EAI_NONAME; 387 1.1 elric 388 1.1 elric if (hints != NULL 389 1.1 elric && hints->ai_family != PF_UNSPEC 390 1.1 elric && hints->ai_family != PF_INET 391 1.1 elric #ifdef HAVE_IPV6 392 1.1 elric && hints->ai_family != PF_INET6 393 1.1 elric #endif 394 1.1 elric ) 395 1.1 elric return EAI_FAMILY; 396 1.1 elric 397 1.1 elric if (servname != NULL) { 398 1.1 elric ret = get_port_protocol_socktype (servname, hints, 399 1.1 elric &port, &protocol, &socktype); 400 1.1 elric if (ret) 401 1.1 elric return ret; 402 1.1 elric } 403 1.1 elric if (nodename != NULL) { 404 1.1 elric ret = get_number (nodename, hints, port, protocol, socktype, res); 405 1.1 elric if (ret) { 406 1.1 elric if(hints && hints->ai_flags & AI_NUMERICHOST) 407 1.1 elric ret = EAI_NONAME; 408 1.1 elric else 409 1.1 elric ret = get_nodes (nodename, hints, port, protocol, socktype, 410 1.1 elric res); 411 1.1 elric } 412 1.1 elric } else { 413 1.1 elric ret = get_null (hints, port, protocol, socktype, res); 414 1.1 elric } 415 1.1 elric if (ret) 416 1.1 elric freeaddrinfo (*res); 417 1.1 elric return ret; 418 1.1 elric } 419