root/lib/replace/getaddrinfo.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_hostent_err
  2. canon_name_from_hostent
  3. get_my_canon_name
  4. get_canon_name_from_addr
  5. alloc_entry
  6. getaddr_info_single_addr
  7. getaddr_info_name
  8. rep_getaddrinfo
  9. rep_freeaddrinfo
  10. rep_gai_strerror
  11. gethostnameinfo
  12. getservicenameinfo
  13. rep_getnameinfo

   1 /*
   2 PostgreSQL Database Management System
   3 (formerly known as Postgres, then as Postgres95)
   4 
   5 Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group
   6 
   7 Portions Copyright (c) 1994, The Regents of the University of California
   8 
   9 Permission to use, copy, modify, and distribute this software and its
  10 documentation for any purpose, without fee, and without a written agreement
  11 is hereby granted, provided that the above copyright notice and this paragraph
  12 and the following two paragraphs appear in all copies.
  13 
  14 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  15 DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
  16 LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
  17 EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
  18 SUCH DAMAGE.
  19 
  20 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  21 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  22 AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
  23 ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS
  24 TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  25 
  26 */
  27 
  28 /*-------------------------------------------------------------------------
  29  *
  30  * getaddrinfo.c
  31  *        Support getaddrinfo() on platforms that don't have it.
  32  *
  33  * We also supply getnameinfo() here, assuming that the platform will have
  34  * it if and only if it has getaddrinfo().      If this proves false on some
  35  * platform, we'll need to split this file and provide a separate configure
  36  * test for getnameinfo().
  37  *
  38  * Copyright (c) 2003-2007, PostgreSQL Global Development Group
  39  *
  40  * Copyright (C) 2007 Jeremy Allison.
  41  * Modified to return multiple IPv4 addresses for Samba.
  42  *
  43  *-------------------------------------------------------------------------
  44  */
  45 
  46 #include "replace.h"
  47 #include "system/network.h"
  48 
  49 #ifndef SMB_MALLOC
  50 #define SMB_MALLOC(s) malloc(s)
  51 #endif
  52 
  53 #ifndef SMB_STRDUP
  54 #define SMB_STRDUP(s) strdup(s)
  55 #endif
  56 
  57 static int check_hostent_err(struct hostent *hp)
     /* [<][>][^][v][top][bottom][index][help] */
  58 {
  59         if (!hp) {
  60                 switch (h_errno) {
  61                         case HOST_NOT_FOUND:
  62                         case NO_DATA:
  63                                 return EAI_NONAME;
  64                         case TRY_AGAIN:
  65                                 return EAI_AGAIN;
  66                         case NO_RECOVERY:
  67                         default:
  68                                 return EAI_FAIL;
  69                 }
  70         }
  71         if (!hp->h_name || hp->h_addrtype != AF_INET) {
  72                 return EAI_FAIL;
  73         }
  74         return 0;
  75 }
  76 
  77 static char *canon_name_from_hostent(struct hostent *hp,
     /* [<][>][^][v][top][bottom][index][help] */
  78                                 int *perr)
  79 {
  80         char *ret = NULL;
  81 
  82         *perr = check_hostent_err(hp);
  83         if (*perr) {
  84                 return NULL;
  85         }
  86         ret = SMB_STRDUP(hp->h_name);
  87         if (!ret) {
  88                 *perr = EAI_MEMORY;
  89         }
  90         return ret;
  91 }
  92 
  93 static char *get_my_canon_name(int *perr)
     /* [<][>][^][v][top][bottom][index][help] */
  94 {
  95         char name[HOST_NAME_MAX+1];
  96 
  97         if (gethostname(name, HOST_NAME_MAX) == -1) {
  98                 *perr = EAI_FAIL;
  99                 return NULL;
 100         }
 101         /* Ensure null termination. */
 102         name[HOST_NAME_MAX] = '\0';
 103         return canon_name_from_hostent(gethostbyname(name), perr);
 104 }
 105 
 106 static char *get_canon_name_from_addr(struct in_addr ip,
     /* [<][>][^][v][top][bottom][index][help] */
 107                                 int *perr)
 108 {
 109         return canon_name_from_hostent(
 110                         gethostbyaddr(&ip, sizeof(ip), AF_INET),
 111                         perr);
 112 }
 113 
 114 static struct addrinfo *alloc_entry(const struct addrinfo *hints,
     /* [<][>][^][v][top][bottom][index][help] */
 115                                 struct in_addr ip,
 116                                 unsigned short port)
 117 {
 118         struct sockaddr_in *psin = NULL;
 119         struct addrinfo *ai = SMB_MALLOC(sizeof(*ai));
 120 
 121         if (!ai) {
 122                 return NULL;
 123         }
 124         memset(ai, '\0', sizeof(*ai));
 125 
 126         psin = SMB_MALLOC(sizeof(*psin));
 127         if (!psin) {
 128                 free(ai);
 129                 return NULL;
 130         }
 131 
 132         memset(psin, '\0', sizeof(*psin));
 133 
 134         psin->sin_family = AF_INET;
 135         psin->sin_port = htons(port);
 136         psin->sin_addr = ip;
 137 
 138         ai->ai_flags = 0;
 139         ai->ai_family = AF_INET;
 140         ai->ai_socktype = hints->ai_socktype;
 141         ai->ai_protocol = hints->ai_protocol;
 142         ai->ai_addrlen = sizeof(*psin);
 143         ai->ai_addr = (struct sockaddr *) psin;
 144         ai->ai_canonname = NULL;
 145         ai->ai_next = NULL;
 146 
 147         return ai;
 148 }
 149 
 150 /*
 151  * get address info for a single ipv4 address.
 152  *
 153  *      Bugs:   - servname can only be a number, not text.
 154  */
 155 
 156 static int getaddr_info_single_addr(const char *service,
     /* [<][>][^][v][top][bottom][index][help] */
 157                                 uint32_t addr,
 158                                 const struct addrinfo *hints,
 159                                 struct addrinfo **res)
 160 {
 161 
 162         struct addrinfo *ai = NULL;
 163         struct in_addr ip;
 164         unsigned short port = 0;
 165 
 166         if (service) {
 167                 port = (unsigned short)atoi(service);
 168         }
 169         ip.s_addr = htonl(addr);
 170 
 171         ai = alloc_entry(hints, ip, port);
 172         if (!ai) {
 173                 return EAI_MEMORY;
 174         }
 175 
 176         /* If we're asked for the canonical name,
 177          * make sure it returns correctly. */
 178         if (!(hints->ai_flags & AI_NUMERICSERV) &&
 179                         hints->ai_flags & AI_CANONNAME) {
 180                 int err;
 181                 if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) {
 182                         ai->ai_canonname = get_my_canon_name(&err);
 183                 } else {
 184                         ai->ai_canonname =
 185                         get_canon_name_from_addr(ip,&err);
 186                 }
 187                 if (ai->ai_canonname == NULL) {
 188                         freeaddrinfo(ai);
 189                         return err;
 190                 }
 191         }
 192 
 193         *res = ai;
 194         return 0;
 195 }
 196 
 197 /*
 198  * get address info for multiple ipv4 addresses.
 199  *
 200  *      Bugs:   - servname can only be a number, not text.
 201  */
 202 
 203 static int getaddr_info_name(const char *node,
     /* [<][>][^][v][top][bottom][index][help] */
 204                                 const char *service,
 205                                 const struct addrinfo *hints,
 206                                 struct addrinfo **res)
 207 {
 208         struct addrinfo *listp = NULL, *prevp = NULL;
 209         char **pptr = NULL;
 210         int err;
 211         struct hostent *hp = NULL;
 212         unsigned short port = 0;
 213 
 214         if (service) {
 215                 port = (unsigned short)atoi(service);
 216         }
 217 
 218         hp = gethostbyname(node);
 219         err = check_hostent_err(hp);
 220         if (err) {
 221                 return err;
 222         }
 223 
 224         for(pptr = hp->h_addr_list; *pptr; pptr++) {
 225                 struct in_addr ip = *(struct in_addr *)*pptr;
 226                 struct addrinfo *ai = alloc_entry(hints, ip, port);
 227 
 228                 if (!ai) {
 229                         freeaddrinfo(listp);
 230                         return EAI_MEMORY;
 231                 }
 232 
 233                 if (!listp) {
 234                         listp = ai;
 235                         prevp = ai;
 236                         ai->ai_canonname = SMB_STRDUP(hp->h_name);
 237                         if (!ai->ai_canonname) {
 238                                 freeaddrinfo(listp);
 239                                 return EAI_MEMORY;
 240                         }
 241                 } else {
 242                         prevp->ai_next = ai;
 243                         prevp = ai;
 244                 }
 245         }
 246         *res = listp;
 247         return 0;
 248 }
 249 
 250 /*
 251  * get address info for ipv4 sockets.
 252  *
 253  *      Bugs:   - servname can only be a number, not text.
 254  */
 255 
 256 int rep_getaddrinfo(const char *node,
     /* [<][>][^][v][top][bottom][index][help] */
 257                 const char *service,
 258                 const struct addrinfo * hintp,
 259                 struct addrinfo ** res)
 260 {
 261         struct addrinfo hints;
 262 
 263         /* Setup the hints struct. */
 264         if (hintp == NULL) {
 265                 memset(&hints, 0, sizeof(hints));
 266                 hints.ai_family = AF_INET;
 267                 hints.ai_socktype = SOCK_STREAM;
 268         } else {
 269                 memcpy(&hints, hintp, sizeof(hints));
 270         }
 271 
 272         if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) {
 273                 return EAI_FAMILY;
 274         }
 275 
 276         if (hints.ai_socktype == 0) {
 277                 hints.ai_socktype = SOCK_STREAM;
 278         }
 279 
 280         if (!node && !service) {
 281                 return EAI_NONAME;
 282         }
 283 
 284         if (node) {
 285                 if (node[0] == '\0') {
 286                         return getaddr_info_single_addr(service,
 287                                         INADDR_ANY,
 288                                         &hints,
 289                                         res);
 290                 } else if (hints.ai_flags & AI_NUMERICHOST) {
 291                         struct in_addr ip;
 292                         if (!inet_aton(node, &ip)) {
 293                                 return EAI_FAIL;
 294                         }
 295                         return getaddr_info_single_addr(service,
 296                                         ntohl(ip.s_addr),
 297                                         &hints,
 298                                         res);
 299                 } else {
 300                         return getaddr_info_name(node,
 301                                                 service,
 302                                                 &hints,
 303                                                 res);
 304                 }
 305         } else if (hints.ai_flags & AI_PASSIVE) {
 306                 return getaddr_info_single_addr(service,
 307                                         INADDR_ANY,
 308                                         &hints,
 309                                         res);
 310         }
 311         return getaddr_info_single_addr(service,
 312                                         INADDR_LOOPBACK,
 313                                         &hints,
 314                                         res);
 315 }
 316 
 317 
 318 void rep_freeaddrinfo(struct addrinfo *res)
     /* [<][>][^][v][top][bottom][index][help] */
 319 {
 320         struct addrinfo *next = NULL;
 321 
 322         for (;res; res = next) {
 323                 next = res->ai_next;
 324                 if (res->ai_canonname) {
 325                         free(res->ai_canonname);
 326                 }
 327                 if (res->ai_addr) {
 328                         free(res->ai_addr);
 329                 }
 330                 free(res);
 331         }
 332 }
 333 
 334 
 335 const char *rep_gai_strerror(int errcode)
     /* [<][>][^][v][top][bottom][index][help] */
 336 {
 337 #ifdef HAVE_HSTRERROR
 338         int                     hcode;
 339 
 340         switch (errcode)
 341         {
 342                 case EAI_NONAME:
 343                         hcode = HOST_NOT_FOUND;
 344                         break;
 345                 case EAI_AGAIN:
 346                         hcode = TRY_AGAIN;
 347                         break;
 348                 case EAI_FAIL:
 349                 default:
 350                         hcode = NO_RECOVERY;
 351                         break;
 352         }
 353 
 354         return hstrerror(hcode);
 355 #else                                                   /* !HAVE_HSTRERROR */
 356 
 357         switch (errcode)
 358         {
 359                 case EAI_NONAME:
 360                         return "Unknown host";
 361                 case EAI_AGAIN:
 362                         return "Host name lookup failure";
 363 #ifdef EAI_BADFLAGS
 364                 case EAI_BADFLAGS:
 365                         return "Invalid argument";
 366 #endif
 367 #ifdef EAI_FAMILY
 368                 case EAI_FAMILY:
 369                         return "Address family not supported";
 370 #endif
 371 #ifdef EAI_MEMORY
 372                 case EAI_MEMORY:
 373                         return "Not enough memory";
 374 #endif
 375 #ifdef EAI_NODATA
 376                 case EAI_NODATA:
 377                         return "No host data of that type was found";
 378 #endif
 379 #ifdef EAI_SERVICE
 380                 case EAI_SERVICE:
 381                         return "Class type not found";
 382 #endif
 383 #ifdef EAI_SOCKTYPE
 384                 case EAI_SOCKTYPE:
 385                         return "Socket type not supported";
 386 #endif
 387                 default:
 388                         return "Unknown server error";
 389         }
 390 #endif   /* HAVE_HSTRERROR */
 391 }
 392 
 393 static int gethostnameinfo(const struct sockaddr *sa,
     /* [<][>][^][v][top][bottom][index][help] */
 394                         char *node,
 395                         size_t nodelen,
 396                         int flags)
 397 {
 398         int ret = -1;
 399         char *p = NULL;
 400 
 401         if (!(flags & NI_NUMERICHOST)) {
 402                 struct hostent *hp = gethostbyaddr(
 403                                 &((struct sockaddr_in *)sa)->sin_addr,
 404                                 sizeof(struct in_addr),
 405                                 sa->sa_family);
 406                 ret = check_hostent_err(hp);
 407                 if (ret == 0) {
 408                         /* Name looked up successfully. */
 409                         ret = snprintf(node, nodelen, "%s", hp->h_name);
 410                         if (ret < 0 || (size_t)ret >= nodelen) {
 411                                 return EAI_MEMORY;
 412                         }
 413                         if (flags & NI_NOFQDN) {
 414                                 p = strchr(node,'.');
 415                                 if (p) {
 416                                         *p = '\0';
 417                                 }
 418                         }
 419                         return 0;
 420                 }
 421 
 422                 if (flags & NI_NAMEREQD) {
 423                         /* If we require a name and didn't get one,
 424                          * automatically fail. */
 425                         return ret;
 426                 }
 427                 /* Otherwise just fall into the numeric host code... */
 428         }
 429         p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr);
 430         ret = snprintf(node, nodelen, "%s", p);
 431         if (ret < 0 || (size_t)ret >= nodelen) {
 432                 return EAI_MEMORY;
 433         }
 434         return 0;
 435 }
 436 
 437 static int getservicenameinfo(const struct sockaddr *sa,
     /* [<][>][^][v][top][bottom][index][help] */
 438                         char *service,
 439                         size_t servicelen,
 440                         int flags)
 441 {
 442         int ret = -1;
 443         int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
 444 
 445         if (!(flags & NI_NUMERICSERV)) {
 446                 struct servent *se = getservbyport(
 447                                 port,
 448                                 (flags & NI_DGRAM) ? "udp" : "tcp");
 449                 if (se && se->s_name) {
 450                         /* Service name looked up successfully. */
 451                         ret = snprintf(service, servicelen, "%s", se->s_name);
 452                         if (ret < 0 || (size_t)ret >= servicelen) {
 453                                 return EAI_MEMORY;
 454                         }
 455                         return 0;
 456                 }
 457                 /* Otherwise just fall into the numeric service code... */
 458         }
 459         ret = snprintf(service, servicelen, "%d", port);
 460         if (ret < 0 || (size_t)ret >= servicelen) {
 461                 return EAI_MEMORY;
 462         }
 463         return 0;
 464 }
 465 
 466 /*
 467  * Convert an ipv4 address to a hostname.
 468  *
 469  * Bugs:        - No IPv6 support.
 470  */
 471 int rep_getnameinfo(const struct sockaddr *sa, socklen_t salen,
     /* [<][>][^][v][top][bottom][index][help] */
 472                         char *node, size_t nodelen,
 473                         char *service, size_t servicelen, int flags)
 474 {
 475 
 476         /* Invalid arguments. */
 477         if (sa == NULL || (node == NULL && service == NULL)) {
 478                 return EAI_FAIL;
 479         }
 480 
 481         if (sa->sa_family != AF_INET) {
 482                 return EAI_FAIL;
 483         }
 484 
 485         if (salen < sizeof(struct sockaddr_in)) {
 486                 return EAI_FAIL;
 487         }
 488 
 489         if (node) {
 490                 return gethostnameinfo(sa, node, nodelen, flags);
 491         }
 492 
 493         if (service) {
 494                 return getservicenameinfo(sa, service, servicelen, flags);
 495         }
 496         return 0;
 497 }

/* [<][>][^][v][top][bottom][index][help] */