For the following I'm assuming one network card.
I have a component of my program which is designed to let others in the subnet know of its existence. For this, I've implemented a solution where whenever the program starts up (and periodically afterwards) it sends a broadcast to INADDR_BROADCAST
- whoever listens on the required port will remember where it came from for later use.
The problem with this is that I don't want to remember my own broadcasts. I thought that in theory this would be easy to do - simply find out the local ip and compare to what you get in recvfrom
.
However, I've found it difficult to get the local IP: getaddrinfo
with NULL returns 127.0.0.1
, getaddrinfo
with the hostname returns the public ip. Can anyone point me in the direction of finding the actual subnet ip ? I think I must be missing something very obvious here but well... I'm still missing it :)
Note: I've read other SO questions on broadcasts, in particular this one: UDP-Broadcast on all interfaces but I haven't gotten round to the multiple interface issue yet.
Well at start-up you could broadcast a different message with random (but tracked) value, then wait for that message, to discover your own address, from then on, you can send normal messages, ignoring your sourced messages.
getsockname
(function documentation) can discover the local IP address associated with a particular socket. If you call this on the socket you're using to send the broadcast, you should see the same IP address you'll see returned by recvfrom
.
On linux, you can get the IP address of a given interface using ioctl with the SIOCGIFADDR
option. I don't think this works for Windows, though. For that, you'll have to do something goofy like this.
Search for scoket options and see whether these works: IP_MULTICAST_LOOP,IP_BLOCK_SOURCE
(I am presuming you are working on Windows)
GetIpAddrTable does exactly that! It returns data about all your network interfaces, the IP address is among them. There is some trickery in getting them, but not more than in the rest of Winsocks.
Here is a ready to compile 54 lines example that prints all your network interfaces with IP and Network masks, and also filters for your local callback (127.0.0.1) since you most likely don't want that, and it is always there, so you can't just ignore it:
(worked with msvc 19, windows 10, link against Iphlpapi.lib and Ws2_32.lib)
#include "stdio.h"
#include "Winsock2.h"
#include "Iphlpapi.h"
int main(){
int error;
ULONG size = 0;
MIB_IPADDRTABLE* meta_table = nullptr;
error = GetIpAddrTable(meta_table, &size, false);
if(error != ERROR_INSUFFICIENT_BUFFER)
return -1;
meta_table = (MIB_IPADDRTABLE*)malloc(size);
error = GetIpAddrTable(meta_table, &size, false);
if(error != NO_ERROR)
return -1;
int os_interface_count = meta_table->dwNumEntries;
for(int i = 0; i < os_interface_count; i++){
printf("interface:\n");
{
in_addr mask;
in_addr address;
address.S_un.S_addr = meta_table->table[i].dwAddr;
mask.S_un.S_addr = meta_table->table[i].dwMask;
printf("index: %d\n", meta_table->table[i].dwIndex);
printf("address: %s\n", inet_ntoa(address));
printf("mask: %s\n", inet_ntoa(mask));
}
{
in_addr callback_address;
callback_address.S_un.S_un_b.s_b1 = 127;
callback_address.S_un.S_un_b.s_b2 = 0;
callback_address.S_un.S_un_b.s_b3 = 0;
callback_address.S_un.S_un_b.s_b4 = 1;
if(meta_table->table[i].dwAddr == callback_address.S_un.S_addr)
printf("local callback!\n");
}
}
free(meta_table);
return 0;
}
producing this output on my machine:
interface:
index: 7
address: 192.168.56.1
mask: 255.255.255.0
interface:
index: 1
address: 127.0.0.1
mask: 255.0.0.0
local callback!
interface:
index: 11
address: 192.168.178.181
mask: 255.255.255.0
The only really weird thing is the first call to GetIpAddrTable
, which just gives you the size you need to allocate for the buffer. I think the rest of the code is pretty self explanatory, if not I'm here for questions. (I don't hav 50 Rep, so I don't know if I will be able to reply to questions, Thanks Stackoverflow!)
来源:https://stackoverflow.com/questions/1762101/how-to-ignore-your-own-broadcast-udp-packets