简体   繁体   中英

extract hex IP from struct addrinfo

I have populated my structure struct addrinfo **res with data:

err = getaddrinfo(argv[1], NULL, &hints, &res);

if I want to print the IP address, I could use

addr.s_addr = ((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr;
printf("ip address : %s\n", inet_ntoa(addr));

and that would print for example 10.111.1.11 . But I need the IP in hex format, ie 0A6F010B . I came up with following, which will indeed print the IP in hex format:

for (i=0; i<32; i=i+8)
    printf("%02X",(addr.s_addr>>i) % 256) ;

But it seems to me that my approach is needlessly complicated. I need two steps (two conversions). I would like to simplify my code, if possible, and print the hex IP directly from res->ai_addr->sa_data (without having to store the data in addr.s_addr first).

I know that the data is there in res->ai_addr->sa_data . I can print it with:

for (i=0; i<14; i++)
    printf("%d", res->ai_addr->sa_data[i]);
printf("\n");

and I get following output (which corresponds to 10.111.1.11 ):

001011111100000000

But the format is not as straightforward as in the previous example. For example for 172.25.0.31 I get this output:

00-842503100000000

Thus my question:

How can I convert this gibberish into hex IP adress?

According to the linked question and this description of sockaddr , you need to do some dynamic type mangling. With the correct types, it might look something like so:

struct addrinfo * res;
err = getaddrinfo(argv[1], NULL, &hints, &res);

// check that the operation succeeded
assert(err == 0);

// check that the dynamic type is AF_INET
assert(res->ai_addr->sa_family == AF_INET);

// downcast
struct sockaddr_in * p = (struct sockaddr_in *)(res->ai_addr);

// done
printf("Address: %08X (%s)\n", p->sin_addr.s_addr, inet_ntoa(p->sin_addr));

A more complete example that performs a proper dynamic type selection might look like this:

char str[128];

switch (res->ai_addr->sa_family)
{
  case AF_INET:
  {
      struct sockaddr_in * p = (struct sockaddr_in *)(res->ai_addr);
      if (inet_ntop(p->sin_family, &p->sin_addr, str, sizeof str) == NULL)
          fprintf(stderr, "Error in inet_ntop: %s\n", strerror(errno));
      else
          printf("Address: %08X (%s)\n", p->sin_addr.s_addr, str);
      break;
  }
  case AF_INET6:
  {
      struct sockaddr_in6 * p = (struct sockaddr_in6 *)(res->ai_addr);
      if (inet_ntop(p->sin6_family, &p->sin6_addr, str, sizeof str) == NULL)
          fprintf(stderr, "Error in inet_ntop: %s\n", strerror(errno));
      else
          printf("Address: %s\n", str);
      break;
  }
  default:
  {
      fprintf(stderr, "Unrecogized address family, skipping.\n");
  }
}

Take a look at an implementation of inet_ntoa here :

#define UC(b)   (((int)b)&0xff)

char* net_ntoa(struct in_addr in) {
    static char b[18];
    register char *p;
    p = (char *)&in;
    snprintf(b, sizeof(b), "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
    return (b);
}

You can change their implementation to suit your needs simply by swapping in the desired format, ie hex:

snprintf(b, sizeof(b), "%02X%02X%02X%02X", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));

Note that their solution is not thread-safe, because it uses a function-static buffer for the output. To make it thread-safe, change the function to take an output buffer, and require the buffer to have at least nine characters (eight for the hex output plus one for the null terminator.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM