Get peer IP address and DNS name from OpenSSL BIO
Daniel Nashed – 21 November 2021 14:29:19
This took me a while to figure out today.
I needed the IP address for OpenSSL BIO holding the TLS session for an incoming server connection.
Find finding the right function was already an adventure. Stack overflow and friends have not been a big help here.
But once you know that the file descriptor connected to the BIO is used to get information about the peer's (client) IP address, the next challenge is how to get the IP address from it.
The function getpeername() is the key, but requires always a buffer of sufficient size also for a IPv6 address -- Even you might just want to support only IPv4 addresses.
Once you know how it works, adding full IPv6 support isn't much extra effort knowing which structures to fill and read ..
It's not obvious and maybe this can safe the next developer googling it some time.
Combining it with a DNS dual IP stack aware lookup routine, adds support for IPv4, IPv6 and hybrid mode to my current project.
See the code below.. for Linux and Windows.
-- Daniel
int GetHostFromBio (BIO *pBio, char *pszHostName, int MaxLenHostName)
{
int ret = 0;
int sock_fd = -1;
const char *p = NULL;
/* Ensure size is sufficient also for IPv6 */
struct sockaddr_in6 addr_in6 = {0};
/* Use a pointer to access the IPv4 structure */
struct sockaddr *pAddr = (struct sockaddr *)&addr_in6;
/* addr_len is input and output parameter for getpeername() */
socklen_t addr_len = sizeof (addr_in6);
ret = BIO_get_fd (pBio, &sock_fd);
if (-1 == ret)
{
LogError ("Cannot get hostname - Invalid FD from BIO\n");
goto Done;
}
ret = getpeername (sock_fd, pAddr, &addr_len);
if (0 != ret)
{
LogError ("Cannot get hostname - Invalid peer name returned\n");
goto Done;
}
if (AF_INET == pAddr->sa_family)
{
p = inet_ntop (AF_INET, &((struct sockaddr_in *)pAddr)->sin_addr, pszHostName, MaxLenHostName);
}
else if (AF_INET6 == pAddr->sa_family)
{
p = inet_ntop (AF_INET6, &((struct sockaddr_in6 *)pAddr)->sin6_addr, pszHostName, MaxLenHostName);
}
else
{
LogError ("Cannot get hostname - Unknown address family\n");
goto Done;
}
if (NULL == p)
{
LogError ("Cannot get hostname - Error converting address\n");
ret = 1;
}
Done:
return ret;
}
int GetDnsName (char *IpAddress, char *HostName, int HostNameLen)
{
int socket_error = 0;
char error_string[128] = {0};
struct sockaddr_in sin = {0};
struct sockaddr_in6 sin6 = {0};
strcpy (HostName, "");
strcpy (error_string, "");
if (strstr (IpAddress, ":"))
{
/* IPv6 */
sin6.sin6_family = AF_INET6;
inet_pton (AF_INET6, IpAddress, &sin6.sin6_addr);
sin6.sin6_port = htons (0);
socket_error = getnameinfo ((struct sockaddr *) &sin6, sizeof (sin6), HostName, HostNameLen, NULL, 0, NI_NAMEREQD);
}
else
{
/* IPv4 */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr (IpAddress);
sin.sin_port = htons (0);
socket_error = getnameinfo ((struct sockaddr *) &sin, sizeof (sin), HostName, HostNameLen, NULL, 0, NI_NAMEREQD);
}
if (socket_error)
{
strcpy (HostName, "");
goto Done;
}
Done:
return socket_error;
}
- Comments [0]