How to ignore your own broadcast udp packets
Asked Answered
G

5

12

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.

Grammalogue answered 19/11, 2009 at 9:49 Comment(2)
Why aren't you leveraging existing solutions such as mDNS (Multicast-DNS) ?Commutate
mDNS is too complicated for my needs.Grammalogue
P
9

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.

Pretonic answered 19/11, 2009 at 9:54 Comment(3)
That's a pretty good idea but it is a bit hackish - the information is readily available (ipconfig/ifconfig) so I should be able to extract it somehowGrammalogue
true, you could change it to be a parameter of your application, and then make a scripting issue. I agree it's very hackishPretonic
Accepting this because, although hacky, is the only way to do it without specific API calls. Plus, I am already transmitting a tracked value, so I just need to add an extra line of code.Grammalogue
S
2

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.

Souther answered 19/11, 2009 at 19:53 Comment(0)
A
1

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.

Appreciative answered 19/11, 2009 at 15:25 Comment(1)
Returns 0.0.0.0 on Windows, some strange gibberish on linux.Grammalogue
O
0

Search for scoket options and see whether these works: IP_MULTICAST_LOOP,IP_BLOCK_SOURCE

Overstay answered 19/11, 2009 at 9:57 Comment(1)
These are multicast options. Nothing to do with broadcast.Forecastle
G
0

(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!)

Gyasi answered 1/9, 2017 at 14:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.