对于两台主机之间的通信,我需要将主机的 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...
发布评论
评论(10)
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
.不是答案,而是相关评论:请注意,一旦开始发送数据包内容中的寻址信息,您就面临着使应用程序无法跨 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.
原始地址将包含在发送的数据包中...无需重复此信息。它是在接受来自远程主机的通信时获得的(请参阅 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())
我刚刚遇到一种情况,当只有 /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.
看看这个:
以编程方式发现公共 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.
即使计算机只有一个物理网络接口(这一假设可能成立,也可能不成立,即使上网本也有两个 - 以太网和 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.
使用
getaddrinfo()
Use
getaddrinfo()
你快到了。我不确定您如何从
hp
获取my_ip
。gethostbyname()
返回一个指向hostent
结构的指针,该结构具有h_addr_list
字段。h_addr_list
字段是绑定到该主机的所有 IP 地址的以 null 结尾的列表。我认为您正在获取环回地址,因为它是
h_addr_list
中的第一个条目。编辑:它应该像这样工作:
You're almost there. I'm not sure how you're getting
my_ip
fromhp
.gethostbyname()
returns a pointer to ahostent
structure which has anh_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:
如果 /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.
您的新代码硬连线了 IPv4 的使用(在hint.ai_family 字段中),这是一个糟糕的主意。
除此之外,您已经很接近了,您只需循环遍历 getaddrinfo 的结果即可。您的代码仅获取第一个 IP 地址,但后面有一个 aip->ai_next 字段...
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...