C - 获取外部 IP 地址

Posted

技术标签:

【中文标题】C - 获取外部 IP 地址【英文标题】:C - Get External IP Address 【发布时间】:2020-12-17 20:51:45 【问题描述】:

我需要通过 C/C++ 调用获取我的公共 IP 地址。我知道作为替代方案,我可以从“http://whatismyip.akamai.com”等外部链接获得

我编写了一个示例来获取外部 IP 地址。但是我的程序没有返回外部 IP 地址。我正在获取内部 IP 地址。我在这里有什么遗漏吗?

如果不能通过这种方式,我可以读取DNS并获取IP地址吗?或者有什么方法可以使用 C API 以编程方式获取外部 IP 地址(不是通过访问某些网站)?

#include <stdio.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>

int main (int argc, const char * argv[]) 
    struct ifaddrs * ifAddrStruct=NULL;
    struct ifaddrs * ifa=NULL;
    void * tmpAddrPtr=NULL;

    getifaddrs(&ifAddrStruct);

    for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) 
        if (!ifa->ifa_addr) 
            continue;
        
        if (ifa->ifa_addr->sa_family == AF_INET) 

            tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
            char addressBuffer[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
            printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
         else if (ifa->ifa_addr->sa_family == AF_INET6) 

            tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
            char addressBuffer[INET6_ADDRSTRLEN];
            inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
            printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
        
    
    if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
    return 0;


注意:我确实有外部 IP 地址,我可以在运行时获取它 卷曲http://whatismyip.akamai.com

【问题讨论】:

几乎别无选择,只能求助于一些外部资源。典型的家用路由器会进行网络地址转换 (NAT),以便房子中的所有计算机共享一个向外的 IP 地址。相当多的 ISP 会自己进行二级网络地址转换,因此仅从路由器获取外向地址也不一定能给出正确答案。 你需要在路由器上运行这个程序 :) 【参考方案1】:

“外部IP”是网络的属性;不是连接到网络的计算机的财产。因此,您无法调用任何函数来从标准库或操作系统中获取此类信息,因为系统不知道这些信息。

我写了一个示例来获取外部 IP 地址。

您编写了一个获取网络接口 IP 地址的程序。如果接口连接到公共网络,则 IP 是外部的。如果接口连接到专用网络,则 IP 是内部的。


通过专用网络获取外部 IP 的一种解决方案是连接到外部服务,该服务可以查看请求来自的 IP。你似乎已经知道了。

不需要外部连接的更高级的方法是在路由器系统上运行类似的服务。正如评论中所指出的,UPnP 或更具体地说,IGD 是路由器可能提供的此类服务。没有 C++ 标准和 POSIX 提供的标准 UPnP 客户端。

【讨论】:

如果网络路由器支持 uPNP 并已启用,您可以直接查询路由器的属性并发现面向公众的 WAN IP。但是,正如 Jerry Coffin 评论的那样,这可能还不够好。因此,最好查询外部来源。 @RemyLebeau 感谢您的指出。我在答案中添加了一些额外的信息。【参考方案2】:

如果您获得的是内部 IP 地址,那么公共 IP 地址可能不是您计算机的财产。

大多数计算机都在进行网络地址转换的路由器后面,因此它们没有公共 IP。

UPNP 是路由器可以向 NAT 客户端提供公共 IP 地址的一种方法。您可能可以使用 UPNP 来获取您的公共 IP。

一些 IPV6 路由器会提供 IPV6 地址,您的计算机可以通过公共互联网访问。

查询外部来源将为您提供请求似乎来自的地址,这可能是您的公共地址(或者您可能在代理或 *** 后面)

哪个最好取决于你想用它做什么。

【讨论】:

【参考方案3】:

您编写的代码获取本地计算机上网络接口的 IP 地址。它们与您的外部 IP 地址无关,如果您位于一层或多层 NAT 之后,它实际上驻留在具有直接 Internet 连接的路由器上。

您提到的服务的工作方式是因为当您与它们建立连接时,它们可以看到您的外部 IP 是什么,然后可以将其发送回给您。

这是连接到您列出的服务以取回 IP 的快速而肮脏的方法:

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

int main(void)

    struct addrinfo hints = 0, *addrs;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;

    int rval = getaddrinfo("whatismyip.akamai.com", "80", &hints, &addrs);
    if (rval != 0) 
        fprintf(stderr,"getaddrinfo failed: %s\n", gai_strerror(rval));
        return 1;
    

    int s = socket(addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
    if (s == -1) 
        perror("socket failed");
        return 1;
    
    rval = connect(s, addrs->ai_addr, addrs->ai_addrlen);
    if (rval == -1) 
        perror("connect failed");
        return 1;
    

    char cmd[] = "GET / HTTP/1.1\nHost: whatismyip.akamai.com\n\n";
    rval = send(s, cmd, strlen(cmd), 0);
    if (rval == -1) 
        perror("send failed");
        return 1;
    

    char buf[1000] = 0;
    rval = recv(s, buf, sizeof(buf), 0);
    if (rval == -1) 
        perror("recv failed");
        return 1;
    
    printf("response: %s\n", buf);

    char *start = buf, *end;
    end = strchr(start, '\n');
    if (!strncmp(start, "HTTP/1.1 200 OK", end - start - 1)) 
        while (!(end[1] == '\r' && end[2] == '\n')) 
            start = end + 2;
            end = strchr(start, '\n');
        
        start = end + 3;
        end = strchr(start, '\n');
        if (end) *end = 0;
        printf("my IP: %s\n", start);
     else 
        printf("request failed\n");
    

    close(s);
    freeaddrinfo(addrs);
    return 0;

请注意,这并没有实现完整的 HTTP 客户端,并对响应的外观做了一些假设,但足以让您入门。

另一种选择是,您可以改用 int fd = popen("curl http://whatismyip.akamai.com", "r"); 在单独的进程中运行 curl 并通过管道读取其输出。

【讨论】:

以上是关于C - 获取外部 IP 地址的主要内容,如果未能解决你的问题,请参考以下文章

在 Java 中获取“外部”IP 地址

Qt 使用 QNetworkReply 获取外部 IP 地址

获取公共/外部 IP 地址?

您可以从 Google Compute VM 实例中获取外部 IP 地址吗?

python 获取您的外部IP地址

以编程方式在Android中的外部IP地址