示例#1
0
/*
 * 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;
}
示例#2
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;
}