63

How can I extract an IP address into a string? I can't find a reference that tells me how char sa_data[14] is encoded.

Jon Seigel
  • 12,251
  • 8
  • 58
  • 92
Felipe Salazar
  • 814
  • 1
  • 7
  • 10

7 Answers7

70

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.

Emil H
  • 39,840
  • 10
  • 78
  • 97
  • 17
    +1. Depending on platform, remember to check the family first. There may not be an IPV4 address to extract... – Steve Jessop Aug 14 '09 at 10:40
  • @SteveJessop How do we do the check btw? Is there any example code or something to look for? – Fatih Arslan Jul 13 '12 at 13:42
  • 7
    `if (their_sockaddr_ptr->sa_family == AF_INET) { struct sockaddr_in *their_inaddr_ptr = (struct sockaddr_in *)their_sockaddr_ptr; } else { /* not an IPv4 address */ }`, or similar. – Steve Jessop Jul 13 '12 at 14:32
  • @Emil How do you cast the entire sockaddr structure to sockaddr_in? Able to give an example? :D – mister Jul 27 '12 at 08:11
  • @mister If you have a question, start question, that's what SO is here for. Questions are first class citizen on SO. And the answer is, just cast it! `sockaddr` is only an "abstract" address, no address really ever is of that type, it just defines the common fields all socketaddr structs must have. `struct sockaddr * saddr = ...; if (saddr->sa_family == AF_INET) { struct sockaddr_in * saddr_in = (sockaddr_in *)saddr; ... }` – Mecki Aug 10 '16 at 10:35
43

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);
FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
jrc
  • 20,354
  • 10
  • 69
  • 64
37

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.

uchuugaka
  • 12,679
  • 6
  • 37
  • 55
John
  • 3,430
  • 2
  • 31
  • 44
27

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];
};
gomons
  • 1,946
  • 14
  • 25
Amber
  • 507,862
  • 82
  • 626
  • 550
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;
}
user3731622
  • 4,844
  • 8
  • 45
  • 84
1

The following program resolves a given domain:

$ gcc a.c

$ ./a.out google.com
AF_INET: 216.58.214.238
AF_INET6: 2a00:1450:400d:803::200e

$ ./a.out google.com af_inet
AF_INET: 216.58.214.238

a.c:

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>

int
main(int argc, char *argv[])
{
    struct addrinfo hints, *res, *cres;
    int r;
    char s[INET6_ADDRSTRLEN];

    memset(&hints, 0, sizeof(hints));
    if (argc > 2)
        hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;

    r = getaddrinfo(argv[1], NULL, &hints, &res);
    if (r) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(r));
        exit(EXIT_FAILURE);
    }

    for (cres = res; cres; cres = cres->ai_next) {
        switch (cres->ai_family) {
        case AF_INET:
            inet_ntop(AF_INET, &((struct sockaddr_in *)cres->ai_addr)->sin_addr, s, INET6_ADDRSTRLEN);
            printf("AF_INET: %s\n", s);
            break;
        case AF_INET6:
            inet_ntop(AF_INET6, &((struct sockaddr_in6 *)cres->ai_addr)->sin6_addr, s, INET6_ADDRSTRLEN);
            printf("AF_INET6: %s\n", s);
            break;
        }
    }

    freeaddrinfo(res);
}

Another example can be found here.

x-yuri
  • 16,722
  • 15
  • 114
  • 161
0

Type casting of sockaddr to sockaddr_in and retrieval of ipv4 using inet_ntoa

char * ip = inet_ntoa(((struct sockaddr_in *)sockaddr)->sin_addr);
Aamir
  • 16,329
  • 10
  • 59
  • 65