如何在C中获取我的非环回网络IP地址?

发布于 2024-09-28 03:27:13 字数 1084 浏览 6 评论 0 原文

对于两台主机之间的通信,我需要将主机的 IP 地址发送到另一个站点。问题是,如果我请求我的 IP 地址,我可能会得到我的本地环回 IP 地址 (127.xxx) ,而不是网络(以太网)IP 地址。

我使用以下代码:

char myhostname[32];


gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);

if( (my_ip % 256) == 127) {
  /* Wrong IP adress as it's 127.x.x.x */
  printf("Error, local IP address!");
  return;
}

解决这个问题的唯一方法是确保 /etc/hosts 中的主机名位于真实网络地址后面,而不是本地环回(例如 Ubuntu 的默认值)。

有没有办法不依赖/etc/hosts的内容来解决这个问题?

编辑:我更改了上面的代码,以便它使用 getaddrinfo,但我仍然得到环回设备的号码 (127.0,0,1) 而不是真实的 IP 地址:(

struct addrinfo hint = {0};
struct addrinfo *aip = NULL;
unsigned ip = 0;
struct sockaddr_in *sinp = NULL;

hint.ai_family = AF_INET; /* IPv4 */
hint.ai_socktype = SOCK_STREAM;

if(getaddrinfo(hostname, NULL, &hint, &aip) != 0) {
    return 0;
}
sinp = (struct sockaddr_in *) aip->ai_addr;
ip   = *(unsigned *) &sinp->sin_addr;

我曾经得到过3个addrinfo的列表,其中包含三个SOCK_STREAM、SOCK_DGRAM和SOCK_RAW,但提示阻止了这一点)

所以我的问题仍然存在......

For a communication between two hosts, I need to send the IP address of my host to the other site. The problem is that if I request my IP address, it might be that I get back my local loopback IP addres (127.x.x.x) , not the network (ethernet) IP address.

I use the following code:

char myhostname[32];


gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);

if( (my_ip % 256) == 127) {
  /* Wrong IP adress as it's 127.x.x.x */
  printf("Error, local IP address!");
  return;
}

The only way to solve it is to make sure my hostname in /etc/hosts is behind the real network address, not the local loopback (the default for e.g. Ubuntu).

Is there a way to solve this without relying on the content of /etc/hosts?

Edit: I changed the above code so it makes use of getaddrinfo, but I still get back the loopback device's number (127.0,0,1) instead of the real IP address:

struct addrinfo hint = {0};
struct addrinfo *aip = NULL;
unsigned ip = 0;
struct sockaddr_in *sinp = NULL;

hint.ai_family = AF_INET; /* IPv4 */
hint.ai_socktype = SOCK_STREAM;

if(getaddrinfo(hostname, NULL, &hint, &aip) != 0) {
    return 0;
}
sinp = (struct sockaddr_in *) aip->ai_addr;
ip   = *(unsigned *) &sinp->sin_addr;

(I used to get back a list of 3 addrinfo's with the three SOCK_STREAM,SOCK_DGRAM and SOCK_RAW, but the hint prevents that)

So my question still stands...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

秋日私语 2024-10-05 03:27:13

POSIX 函数 getaddrinfo() 可以返回给定主机名的地址链接列表,因此您只需浏览该列表并找到非环回地址。

请参阅man getaddrinfo

There is POSIX function getaddrinfo() that returns linked list of addresses for given hostname, so you just need to go through that list and find non-loopback address.

See man getaddrinfo.

你是我的挚爱i 2024-10-05 03:27:13

不是答案,而是相关评论:请注意,一旦开始发送数据包内容中的寻址信息,您就面临着使应用程序无法跨 NAT:ing 路由器和/或通过防火墙。

这些技术依赖于 IP 数据包标头中的信息来跟踪流量,如果应用程序在数据包内交换寻址信息(在这种检查中它们仍然不可见),它们可能会崩溃。

当然,这可能与您的应用程序完全无关,但我认为在这种情况下值得指出。

Not an answer, but a relevant comment: be aware that as soon as you start sending addressing information in the content of packets, you run the risk of making your application unable to work across NAT:ing routers and/or through firewalls.

These technologies rely on the information in IP packet headers to keep track of the traffic, and if applications exchange addressing information inside packets, where they remain invisible to this inspection, they might break.

Of course, this might be totally irrelevant to your application, but I thought it worth pointing out in this context.

停顿的约定 2024-10-05 03:27:13

原始地址将包含在发送的数据包中...无需重复此信息。它是在接受来自远程主机的通信时获得的(请参阅 beej 的网络指南,特别是 接受())

The originating address will be included in the packet sent... there's no need to duplicate this information. It's obtained when accepting the communication from the remote host (see beej's guide to networking, specifically the part on accept())

待天淡蓝洁白时 2024-10-05 03:27:13

我刚刚遇到一种情况,当只有 /etc/hosts 中有信息时,当我使用 getaddrinfo 获取 IP 地址列表时,它每次都返回 127.0.0.1。事实证明,主机名被别名为 localhost……这往往很容易被忽视。发生了什么:

/etc/hosts 文件:
127.0.0.1 localhost.localdomain localhost foo
::1 localhost6.localdomain6 localhost6
172.16.1.248 富
172.16.1.249 比
172.16.1.250 bletch

所以,现在,当您使用 host="foo" 调用 getaddrinfo 时,它会返回 127.0.0.1 3 次。这里的错误是 foo 同时出现在“127.0.0.1”和“172.16.1.248”行上。一旦我从“127.0.0.1”行中删除 foo ,一切就正常了。

希望这对某人有帮助。

I just ran into a situation where when only /etc/hosts has information in it and when I used getaddrinfo to get the IP address list, it returned 127.0.0.1 each time. As it turned out, the hostname was aliased to localhost...something often easy to overlook. Here's what happened:

The /etc/hosts file:
127.0.0.1 localhost.localdomain localhost foo
::1 localhost6.localdomain6 localhost6
172.16.1.248 foo
172.16.1.249 bie
172.16.1.250 bletch

So, now, when you call getaddrinfo with host="foo", it returns 127.0.0.1 3 times. The error here, is that foo appears both on the line with "127.0.0.1" and "172.16.1.248". Once I removed foo from the line with "127.0.0.1" things worked fine.

Hope this helps someone.

穿越时光隧道 2024-10-05 03:27:13

看看这个:
以编程方式发现公共 IP

请注意,在某些情况下,一台计算机可以拥有多个非环回 IP地址,在这种情况下,该问题的答案会告诉您如何获取暴露在互联网上的地址。

Look at this:
Discovering public IP programmatically

Note that in some cases a computer can have more than one non-loopback IP address, and in that case the answers to that question tell you how to get the one that is exposed to the internet.

魔法唧唧 2024-10-05 03:27:13

即使计算机只有一个物理网络接口(这一假设可能成立,也可能不成立,即使上网本也有两个 - 以太网和 WLAN),VPN 也可以添加更多的 IP 地址。无论如何,另一端的主机应该能够确定您的主机用于联系它的 IP。

Even if the computer has only one physical network interface (an assumption that may or may not hold, even netbooks have two - ethernet and WLAN), VPNs can add even more IP adresses. Anyway, the host on the other side should be able to determine the IP your host used to contact it.

凉风有信 2024-10-05 03:27:13

你快到了。我不确定您如何从 hp 获取 my_ip

gethostbyname() 返回一个指向 hostent 结构的指针,该结构具有 h_addr_list 字段。

h_addr_list 字段是绑定到该主机的所有 IP 地址的以 null 结尾的列表。

我认为您正在获取环回地址,因为它是 h_addr_list 中的第一个条目。

编辑:它应该像这样工作:

gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);

for (int i = 0; hp->h_addr_list[i] != 0; ++i) {
  if (hp->h_addr_list[i] != INADDR_LOOPBACK) {
    // hp->addr_list[i] is a non-loopback address
  }
}
// no address found

You're almost there. I'm not sure how you're getting my_ip from hp.

gethostbyname() returns a pointer to a hostent structure which has an h_addr_list field.

The h_addr_list field is a null-terminated list of all the ip addresses bound to that host.

I think you're getting the loopback address because it's the first entry in h_addr_list.

EDIT: It should work something like this:

gethostname(myhostname, 32);
hp = gethostbyname(myhostname);
unsigned my_ip = *(unsigned*)(hp->h_addr);

for (int i = 0; hp->h_addr_list[i] != 0; ++i) {
  if (hp->h_addr_list[i] != INADDR_LOOPBACK) {
    // hp->addr_list[i] is a non-loopback address
  }
}
// no address found
西瑶 2024-10-05 03:27:13

如果 /etc/hosts 仍然存在并且仍然相同,则查找 h_addr_list 的所有条目将无济于事。

If /etc/hosts is still there and still the same, looking for all entries of h_addr_list won't help.

在风中等你 2024-10-05 03:27:13

您的新代码硬连线了 IPv4 的使用(在hint.ai_family 字段中),这是一个糟糕的主意。

除此之外,您已经很接近了,您只需循环遍历 getaddrinfo 的结果即可。您的代码仅获取第一个 IP 地址,但后面有一个 aip->ai_next 字段...

struct addrinfo {
       ...
       struct addrinfo *ai_next;       /* next structure in linked list */
};

Your new code hardwires the use of IPv4 (in the hint.ai_family field) which is a terrible idea.

Apart from that, you're close, you just should loop through the results of getaddrinfo. Your code just gets the first IP address but there is an aip->ai_next field to follow...

struct addrinfo {
       ...
       struct addrinfo *ai_next;       /* next structure in linked list */
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文