【问题标题】:Tell whether a text string is an IPv6 address or IPv4 address using standard C sockets API使用标准 C 套接字 API 判断文本字符串是 IPv6 地址还是 IPv4 地址
【发布时间】:2010-09-17 14:42:17
【问题描述】:

我有一个程序,其中一个外部组件向我传递了一个包含 IP 地址的字符串。然后我需要把它变成一个URI。对于 IPv4,这很容易;我在前面加上 http:// 并附加 /。但是,对于 IPv6,我还需要将其括在括号 [] 中。

是否有标准的套接字 API 调用来确定地址的地址族?

【问题讨论】:

  • 我知道它不是套接字 API 的一部分,但如果 IP4 和 IP6 是唯一的可能性,你不能用strlen 来做这件事吗? ;-)
  • @Steve Jessop 考虑例如ff02::2 和 8.8.8.8
  • @nos:很公平,没有意识到前者是一个有效的地址。更一般地说,是否有某种方法可以检查字符串,这是比使用套接字 API 更简单的代码?在这种情况下,不需要包含解析地址的结构。
  • 如果您知道该字符串是 ipv4 或 ipv6 地址,则查找 .或 : 可能就足够了。根据您需要的验证级别,解析 ipv4 地址相当简单,而 ipv6 地址则更糟。
  • 考虑到这一点;决定如果我们想支持 IPv4 和 IPv6 以外的东西,它会太hacky并且可能不会扩展(不太可能,但根据我的经验,我会通过编写不支持它的代码来大大增加它的可能性)。

标签: c sockets network-programming


【解决方案1】:

有点。您可以使用inet_pton() 尝试先将字符串解析为 IPv4 (AF_INET),然后再解析为 IPv6 (AF_INET6)。返回码会让你知道函数是否成功,因此字符串包含尝试类型的地址。

例如:

#include <arpa/inet.h>
#include <stdio.h>

static int
ip_version(const char *src) {
    char buf[16];
    if (inet_pton(AF_INET, src, buf)) {
        return 4;
    } else if (inet_pton(AF_INET6, src, buf)) {
        return 6;
    }
    return -1;
}

int
main(int argc, char *argv[]) {
    for (int i = 1; i < argc; ++i) {
        printf("%s\t%d\n", argv[i], ip_version(argv[i]));
    }

    return 0;
}

【讨论】:

  • getaddrinfo() 有很多开销,但基本上也调用 inet_pton()。 inet_pton() 确实是您所需要的,恕我直言,这是这个问题的最佳答案。它也不需要清理功能。
【解决方案2】:

使用getaddrinfo() 并将提示标志AI_NUMERICHOST, family 设置为AF_UNSPEC,从getaddrinfo 成功返回后,生成的struct addrinfo .ai_family 成员将是AF_INET 或AF_INET6。

编辑,小例子

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>

int main(int argc, char *argv[])
{
    struct addrinfo hint, *res = NULL;
    int ret;

    memset(&hint, '\0', sizeof hint);

    hint.ai_family = PF_UNSPEC;
    hint.ai_flags = AI_NUMERICHOST;

    ret = getaddrinfo(argv[1], NULL, &hint, &res);
    if (ret) {
        puts("Invalid address");
        puts(gai_strerror(ret));
        return 1;
    }
    if(res->ai_family == AF_INET) {
        printf("%s is an ipv4 address\n",argv[1]);
    } else if (res->ai_family == AF_INET6) {
        printf("%s is an ipv6 address\n",argv[1]);
    } else {
        printf("%s is an is unknown address format %d\n",argv[1],res->ai_family);
    }

   freeaddrinfo(res);
   return 0;
}

$ ./a.out 127.0.0.1
127.0.0.1 is an ipv4 address
$ ./a.out ff01::01
ff01::01 is an ipv6 address

【讨论】:

    猜你喜欢
    • 2010-10-22
    • 2011-12-26
    • 2013-05-25
    • 2015-12-25
    • 2013-11-07
    • 2011-03-28
    • 2021-05-16
    • 2010-10-21
    • 1970-01-01
    相关资源
    最近更新 更多