/* * get address info for ipv4 sockets. * * Bugs: - only one addrinfo is set even though hintp is NULL or * ai_socktype is 0 * - AI_CANONNAME is not supported. * - servname can only be a number, not text. */ int getaddrinfo(const char *node, const char *service, const struct addrinfo * hintp, struct addrinfo ** res) { struct addrinfo *ai; struct sockaddr_in sin, *psin; struct addrinfo hints; #ifdef WIN32 /* * If Windows has native IPv6 support, use the native Windows routine. * Otherwise, fall through and use our own code. */ if (haveNativeWindowsIPv6routines()) return (*getaddrinfo_ptr) (node, service, hintp, res); #endif if (hintp == NULL) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; } else memcpy(&hints, hintp, sizeof(hints)); if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) return EAI_FAMILY; if (hints.ai_socktype == 0) hints.ai_socktype = SOCK_STREAM; if (!node && !service) return EAI_NONAME; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; if (node) { if (node[0] == '\0') sin.sin_addr.s_addr = htonl(INADDR_ANY); else if (hints.ai_flags & AI_NUMERICHOST) { if (!inet_aton(node, &sin.sin_addr)) return EAI_FAIL; } else { struct hostent *hp; #ifdef FRONTEND struct hostent hpstr; char buf[BUFSIZ]; int herrno = 0; pqGethostbyname(node, &hpstr, buf, sizeof(buf), &hp, &herrno); #else hp = gethostbyname(node); #endif if (hp == NULL) { switch (h_errno) { case HOST_NOT_FOUND: case NO_DATA: return EAI_NONAME; case TRY_AGAIN: return EAI_AGAIN; case NO_RECOVERY: default: return EAI_FAIL; } } if (hp->h_addrtype != AF_INET) return EAI_FAIL; memcpy(&(sin.sin_addr), hp->h_addr, hp->h_length); } } else { if (hints.ai_flags & AI_PASSIVE) sin.sin_addr.s_addr = htonl(INADDR_ANY); else sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } if (service) sin.sin_port = htons((unsigned short) atoi(service)); #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_LEN sin.sin_len = sizeof(sin); #endif ai = malloc(sizeof(*ai)); if (!ai) return EAI_MEMORY; psin = malloc(sizeof(*psin)); if (!psin) { free(ai); return EAI_MEMORY; } memcpy(psin, &sin, sizeof(*psin)); ai->ai_flags = 0; ai->ai_family = AF_INET; ai->ai_socktype = hints.ai_socktype; ai->ai_protocol = hints.ai_protocol; ai->ai_addrlen = sizeof(*psin); ai->ai_addr = (struct sockaddr *) psin; ai->ai_canonname = NULL; ai->ai_next = NULL; *res = ai; return 0; }
/* * Verify that common name resolves to peer. */ static int verify_peer(PGconn *conn) { struct hostent *h = NULL; struct sockaddr addr; struct sockaddr_in *sin; ACCEPT_TYPE_ARG3 len; char **s; unsigned long l; /* get the address on the other side of the socket */ len = sizeof(addr); if (getpeername(conn->sock, &addr, &len) == -1) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("error querying socket: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return -1; } /* weird, but legal case */ if (addr.sa_family == AF_UNIX) return 0; { struct hostent hpstr; char buf[BUFSIZ]; int herrno = 0; /* * Currently, pqGethostbyname() is used only on platforms that don't * have getaddrinfo(). If you enable this function, you should * convert the pqGethostbyname() function call to use getaddrinfo(). */ pqGethostbyname(conn->peer_cn, &hpstr, buf, sizeof(buf), &h, &herrno); } /* what do we know about the peer's common name? */ if (h == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get information about host \"%s\": %s\n"), conn->peer_cn, hstrerror(h_errno)); return -1; } /* does the address match? */ switch (addr.sa_family) { case AF_INET: sin = (struct sockaddr_in *) & addr; for (s = h->h_addr_list; *s != NULL; s++) { if (!memcmp(&sin->sin_addr.s_addr, *s, h->h_length)) return 0; } break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unsupported protocol\n")); return -1; } /* * the prior test should be definitive, but in practice it sometimes * fails. So we also check the aliases. */ for (s = h->h_aliases; *s != NULL; s++) { if (pg_strcasecmp(conn->peer_cn, *s) == 0) return 0; } /* generate protocol-aware error message */ switch (addr.sa_family) { case AF_INET: sin = (struct sockaddr_in *) & addr; l = ntohl(sin->sin_addr.s_addr); printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server common name \"%s\" does not resolve to %ld.%ld.%ld.%ld\n"), conn->peer_cn, (l >> 24) % 0x100, (l >> 16) % 0x100, (l >> 8) % 0x100, l % 0x100); break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server common name \"%s\" does not resolve to peer address\n"), conn->peer_cn); } return -1; }