Getting IPV4 address from a sockaddr structure
Solution 1:
Just cast the entire sockaddr
structure to a sockaddr_in. Then you can use:
char *ip = inet_ntoa(their_addr.sin_addr)
To retrieve the standard ip representation.
Solution 2:
inet_ntoa()
works for IPv4; inet_ntop()
works for both IPv4 and IPv6.
Given an input struct sockaddr *res
, here are two snippets of code (tested on macOS):
Using inet_ntoa()
#include <arpa/inet.h>
struct sockaddr_in *addr_in = (struct sockaddr_in *)res;
char *s = inet_ntoa(addr_in->sin_addr);
printf("IP address: %s\n", s);
Using inet_ntop()
#include <arpa/inet.h>
#include <stdlib.h>
// obviously INET6_ADDRSTRLEN is expected to be larger
// than INET_ADDRSTRLEN, but this may be required in case
// if for some unexpected reason IPv6 is not supported, and
// INET6_ADDRSTRLEN is defined as 0
// but this is not very likely and I am aware of no cases of
// this in practice (editor)
char s[INET6_ADDRSTRLEN > INET_ADDRSTRLEN ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN]
= '\0';
switch(res->sa_family) {
case AF_INET: {
struct sockaddr_in *addr_in = (struct sockaddr_in *)res;
////char s[INET_ADDRSTRLEN] = '\0';
// this is large enough to include terminating null
inet_ntop(AF_INET, &(addr_in->sin_addr), s, INET_ADDRSTRLEN);
break;
}
case AF_INET6: {
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)res;
////char s[INET6_ADDRSTRLEN] = '\0';
// not sure if large enough to include terminating null?
inet_ntop(AF_INET6, &(addr_in6->sin6_addr), s, INET6_ADDRSTRLEN);
break;
}
default:
break;
}
printf("IP address: %s\n", s);
Solution 3:
Emil's answer is correct, but it's my understanding that inet_ntoa
is deprecated and that instead you should use inet_ntop
. If you are using IPv4, cast your struct sockaddr
to sockaddr_in
. Your code will look something like this:
struct addrinfo *res; // populated elsewhere in your code
struct sockaddr_in *ipv4 = (struct sockaddr_in *)res->ai_addr;
char ipAddress[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(ipv4->sin_addr), ipAddress, INET_ADDRSTRLEN);
printf("The IP address is: %s\n", ipAddress);
Take a look at this great resource for more explanation, including how to do this for IPv6 addresses.
Solution 4:
Once sockaddr
cast to sockaddr_in
, it becomes this:
struct sockaddr_in {
u_short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
Solution 5:
You can use getnameinfo
for Windows and for Linux.
Assuming you have a good (i.e. it's members have appropriate values) sockaddr*
called pSockaddr
:
char clienthost[NI_MAXHOST]; //The clienthost will hold the IP address.
char clientservice[NI_MAXSERV];
int theErrorCode = getnameinfo(pSockaddr, sizeof(*pSockaddr), clienthost, sizeof(clienthost), clientservice, sizeof(clientservice), NI_NUMERICHOST|NI_NUMERICSERV);
if( theErrorCode != 0 )
{
//There was an error.
cout << gai_strerror(e1) << endl;
}else{
//Print the info.
cout << "The ip address is = " << clienthost << endl;
cout << "The clientservice = " << clientservice << endl;
}