Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert IP address from sockaddr to in_addr

I need to convert socket address that is placed in structure sockaddr to structure in_addr. I was trying to understand how IP is stored in these structures:

struct sockaddr
{
    u_short sa_family;      /* address family */
    char    sa_data[14];    /* up to 14 bytes of direct address */
};


struct in_addr 
{
    union
    {
        struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
        struct { u_short s_w1,s_w2; } S_un_w;
        u_long S_addr;
    }
    S_un;
};

I got stuck with question how 127.0.0.1 is stored in 14 characters of sa_data. What is the best way to convert sockaddr to in_addr?

like image 899
vico Avatar asked Jan 06 '15 14:01

vico


1 Answers

sockaddr is a generic struct, which is shared by different types of sockets. For TCP/IP sockets this struct becomes sockaddr_in (IPv4) or sockaddr_in6 (IPv6). For unix sockets it becomes sockaddr_un.

Ideally you would use sockaddr_in instead of sockaddr.

But given sockaddr, you could do this to extract IP address from it:

sockaddr foo;
in_addr ip_address = ((sockaddr_in)foo).sin_addr;
or
in_addr_t ip_address = ((sockaddr_in)foo).sin_addr.s_addr;

If you look inside sockaddr_in you will see that the first 2 bytes of sa_data are the port number. And the next 4 bytes are the IP address.

PS: Please note that the IP address is stored in network byte order, so you will probably need to use ntohl (network-to-host) and htonl (host-to-network) to convert to/from host byte order.

UPDATE

For IPv6 things are similar:

sockaddr foo;
in_addr6 ip_address = ((sockaddr_in6)foo).sin6_addr;

To access individual bytes, use ip_address[0] ... ip_address[15].

Inside the sockaddr_in6 struct the first 2 bytes of sa_data are the port number, next 4 bytes are flow info and after that the next 16 bytes are the IPv6 address.

Bewares, however, that sockaddr_in6 is larger than sockaddr, so when casting from sockaddr to sockaddr_in6, make sure that the address is indeed an IPv6 address by checking the address family foo.sa_family == AF_INET6.

like image 146
Innocent Bystander Avatar answered Sep 26 '22 00:09

Innocent Bystander