1/* 2 * Portions Copyright (C) 2004, 2005, 2007, 2011, 2012 Internet Systems Consortium, Inc. ("ISC") 3 * Portions Copyright (C) 1999-2001, 2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id$ */ 19 20/*! \file */ 21 22/* 23 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 24 * All rights reserved. 25 * 26 * Redistribution and use in source and binary forms, with or without 27 * modification, are permitted provided that the following conditions 28 * are met: 29 * 1. Redistributions of source code must retain the above copyright 30 * notice, this list of conditions and the following disclaimer. 31 * 2. Redistributions in binary form must reproduce the above copyright 32 * notice, this list of conditions and the following disclaimer in the 33 * documentation and/or other materials provided with the distribution. 34 * 3. Neither the name of the project nor the names of its contributors 35 * may be used to endorse or promote products derived from this software 36 * without specific prior written permission. 37 * 38 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 41 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 */ 50 51/* 52 * XXX 53 * Issues to be discussed: 54 * - Return values. There seems to be no standard for return value (RFC2553) 55 * but INRIA implementation returns EAI_xxx defined for getaddrinfo(). 56 */ 57 58 59/** 60 * This function is equivalent to the getnameinfo(3) function defined in 61 * RFC2133. lwres_getnameinfo() returns the hostname for the struct 62 * sockaddr sa which is salen bytes long. The hostname is of length 63 * hostlen and is returned via *host. The maximum length of the hostname 64 * is 1025 bytes: #NI_MAXHOST. 65 * 66 * The name of the service associated with the port number in sa is 67 * returned in *serv. It is servlen bytes long. The maximum length of the 68 * service name is #NI_MAXSERV - 32 bytes. 69 * 70 * The flags argument sets the following bits: 71 * 72 * \li #NI_NOFQDN: 73 * A fully qualified domain name is not required for local hosts. 74 * The local part of the fully qualified domain name is returned 75 * instead. 76 * 77 * \li #NI_NUMERICHOST 78 * Return the address in numeric form, as if calling inet_ntop(), 79 * instead of a host name. 80 * 81 * \li #NI_NAMEREQD 82 * A name is required. If the hostname cannot be found in the DNS 83 * and this flag is set, a non-zero error code is returned. If the 84 * hostname is not found and the flag is not set, the address is 85 * returned in numeric form. 86 * 87 * \li #NI_NUMERICSERV 88 * The service name is returned as a digit string representing the 89 * port number. 90 * 91 * \li #NI_DGRAM 92 * Specifies that the service being looked up is a datagram 93 * service, and causes getservbyport() to be called with a second 94 * argument of "udp" instead of its default of "tcp". This is 95 * required for the few ports (512-514) that have different 96 * services for UDP and TCP. 97 * 98 * \section getnameinfo_return Return Values 99 * 100 * lwres_getnameinfo() returns 0 on success or a non-zero error code if 101 * an error occurs. 102 * 103 * \section getname_see See Also 104 * 105 * RFC2133, getservbyport(), 106 * lwres_getnamebyaddr(). lwres_net_ntop(). 107 * 108 * \section getnameinfo_bugs Bugs 109 * 110 * RFC2133 fails to define what the nonzero return values of 111 * getnameinfo() are. 112 */ 113 114#include <config.h> 115 116#include <stdio.h> 117#include <string.h> 118 119#include <lwres/lwres.h> 120#include <lwres/net.h> 121#include <lwres/netdb.h> 122#include "print_p.h" 123 124#include "assert_p.h" 125 126#define SUCCESS 0 127 128/*% afd structure definition */ 129static struct afd { 130 int a_af; 131 size_t a_addrlen; 132 size_t a_socklen; 133} afdl [] = { 134 /*! 135 * First entry is linked last... 136 */ 137 { AF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in) }, 138 { AF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6) }, 139 {0, 0, 0}, 140}; 141 142#define ENI_NOSERVNAME 1 143#define ENI_NOHOSTNAME 2 144#define ENI_MEMORY 3 145#define ENI_SYSTEM 4 146#define ENI_FAMILY 5 147#define ENI_SALEN 6 148#define ENI_NOSOCKET 7 149 150/*! 151 * The test against 0 is there to keep the Solaris compiler 152 * from complaining about "end-of-loop code not reached". 153 */ 154#define ERR(code) \ 155 do { result = (code); \ 156 if (result != 0) goto cleanup; \ 157 } while (0) 158 159/*% lightweight resolver socket address structure to hostname and service name */ 160int 161lwres_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 162 size_t hostlen, char *serv, size_t servlen, int flags) 163{ 164 struct afd *afd; 165 struct servent *sp; 166 unsigned short port; 167#ifdef LWRES_PLATFORM_HAVESALEN 168 size_t len; 169#endif 170 int family, i; 171 const void *addr; 172 char *p; 173#if 0 174 unsigned long v4a; 175 unsigned char pfx; 176#endif 177 char numserv[sizeof("65000")]; 178 char numaddr[sizeof("abcd:abcd:abcd:abcd:abcd:abcd:255.255.255.255") 179 + 1 + sizeof("4294967295")]; 180 const char *proto; 181 lwres_uint32_t lwf = 0; 182 lwres_context_t *lwrctx = NULL; 183 lwres_gnbaresponse_t *by = NULL; 184 int result = SUCCESS; 185 int n; 186 187 if (sa == NULL) 188 ERR(ENI_NOSOCKET); 189 190#ifdef LWRES_PLATFORM_HAVESALEN 191 len = sa->sa_len; 192 if (len != salen) 193 ERR(ENI_SALEN); 194#endif 195 196 family = sa->sa_family; 197 for (i = 0; afdl[i].a_af; i++) 198 if (afdl[i].a_af == family) { 199 afd = &afdl[i]; 200 goto found; 201 } 202 ERR(ENI_FAMILY); 203 204 found: 205 if (salen != afd->a_socklen) 206 ERR(ENI_SALEN); 207 208 switch (family) { 209 case AF_INET: 210 port = ((const struct sockaddr_in *)sa)->sin_port; 211 addr = &((const struct sockaddr_in *)sa)->sin_addr.s_addr; 212 break; 213 214 case AF_INET6: 215 port = ((const struct sockaddr_in6 *)sa)->sin6_port; 216 addr = ((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr; 217 break; 218 219 default: 220 port = 0; 221 addr = NULL; 222 POST(port); POST(addr); 223 INSIST(0); 224 } 225 proto = (flags & NI_DGRAM) ? "udp" : "tcp"; 226 227 if (serv == NULL || servlen == 0U) { 228 /* 229 * Caller does not want service. 230 */ 231 } else if ((flags & NI_NUMERICSERV) != 0 || 232 (sp = getservbyport(port, proto)) == NULL) { 233 snprintf(numserv, sizeof(numserv), "%d", ntohs(port)); 234 if ((strlen(numserv) + 1) > servlen) 235 ERR(ENI_MEMORY); 236 strcpy(serv, numserv); 237 } else { 238 if ((strlen(sp->s_name) + 1) > servlen) 239 ERR(ENI_MEMORY); 240 strcpy(serv, sp->s_name); 241 } 242 243#if 0 244 switch (sa->sa_family) { 245 case AF_INET: 246 v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 247 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) 248 flags |= NI_NUMERICHOST; 249 v4a >>= IN_CLASSA_NSHIFT; 250 if (v4a == 0 || v4a == IN_LOOPBACKNET) 251 flags |= NI_NUMERICHOST; 252 break; 253 254 case AF_INET6: 255 pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0]; 256 if (pfx == 0 || pfx == 0xfe || pfx == 0xff) 257 flags |= NI_NUMERICHOST; 258 break; 259 } 260#endif 261 262 if (host == NULL || hostlen == 0U) { 263 /* 264 * What should we do? 265 */ 266 } else if (flags & NI_NUMERICHOST) { 267 if (lwres_net_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) 268 == NULL) 269 ERR(ENI_SYSTEM); 270#if defined(LWRES_HAVE_SIN6_SCOPE_ID) 271 if (afd->a_af == AF_INET6 && 272 ((const struct sockaddr_in6 *)sa)->sin6_scope_id) { 273 char *p = numaddr + strlen(numaddr); 274 const char *stringscope = NULL; 275#if 0 276 if ((flags & NI_NUMERICSCOPE) == 0) { 277 /* 278 * Vendors may want to add support for 279 * non-numeric scope identifier. 280 */ 281 stringscope = foo; 282 } 283#endif 284 if (stringscope == NULL) { 285 snprintf(p, sizeof(numaddr) - (p - numaddr), 286 "%%%u", 287 ((const struct sockaddr_in6 *)sa)->sin6_scope_id); 288 } else { 289 snprintf(p, sizeof(numaddr) - (p - numaddr), 290 "%%%s", stringscope); 291 } 292 } 293#endif 294 if (strlen(numaddr) + 1 > hostlen) 295 ERR(ENI_MEMORY); 296 strcpy(host, numaddr); 297 } else { 298 switch (family) { 299 case AF_INET: 300 lwf = LWRES_ADDRTYPE_V4; 301 break; 302 case AF_INET6: 303 lwf = LWRES_ADDRTYPE_V6; 304 break; 305 default: 306 INSIST(0); 307 } 308 309 n = lwres_context_create(&lwrctx, NULL, NULL, NULL, 0); 310 if (n == 0) 311 (void) lwres_conf_parse(lwrctx, lwres_resolv_conf); 312 313 if (n == 0) 314 n = lwres_getnamebyaddr(lwrctx, lwf, 315 (lwres_uint16_t)afd->a_addrlen, 316 addr, &by); 317 if (n == 0) { 318 if (flags & NI_NOFQDN) { 319 p = strchr(by->realname, '.'); 320 if (p) 321 *p = '\0'; 322 } 323 if ((strlen(by->realname) + 1) > hostlen) 324 ERR(ENI_MEMORY); 325 strcpy(host, by->realname); 326 } else { 327 if (flags & NI_NAMEREQD) 328 ERR(ENI_NOHOSTNAME); 329 if (lwres_net_ntop(afd->a_af, addr, numaddr, 330 sizeof(numaddr)) 331 == NULL) 332 ERR(ENI_NOHOSTNAME); 333 if ((strlen(numaddr) + 1) > hostlen) 334 ERR(ENI_MEMORY); 335 strcpy(host, numaddr); 336 } 337 } 338 result = SUCCESS; 339 cleanup: 340 if (by != NULL) 341 lwres_gnbaresponse_free(lwrctx, &by); 342 if (lwrctx != NULL) { 343 lwres_conf_clear(lwrctx); 344 lwres_context_destroy(&lwrctx); 345 } 346 return (result); 347} 348