简体   繁体   English

从struct addrinfo提取十六进制IP

[英]extract hex IP from struct addrinfo

I have populated my structure struct addrinfo **res with data: 我已经用数据填充了结构struct addrinfo **res

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

if I want to print the IP address, I could use 如果我想打印IP地址,可以使用

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 . 这将打印例如10.111.1.11 But I need the IP in hex format, ie 0A6F010B . 但是我需要十六进制格式的IP,即0A6F010B I came up with following, which will indeed print the IP in hex format: 我想到了以下内容,这些内容的确会以十六进制格式打印IP:

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). 如果可能的话,我想简化我的代码,并直接从res->ai_addr->sa_data打印十六进制IP(而不必addr.s_addr数据存储在addr.s_addr )。

I know that the data is there in res->ai_addr->sa_data . 我知道数据在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 ): 我得到以下输出(对应于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: 例如对于172.25.0.31我得到以下输出:

00-842503100000000

Thus my question: 因此,我的问题是:

How can I convert this gibberish into hex IP adress? 如何将这些乱码转换为十六进制IP地址?

According to the linked question and this description of sockaddr , you need to do some dynamic type mangling. 根据链接的问题sockaddr描述 ,您需要进行一些动态类型处理。 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 : 这里查看inet_ntoa的实现:

#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. 要使其具有线程安全性,请更改该函数以使用输出缓冲区,并要求该缓冲区至少包含9个字符(十六进制输出为8个字符,空终止符为1个字符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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