By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,778 Members | 1,318 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,778 IT Pros & Developers. It's quick & easy.

How to determine origin of incoming message (uincast/multicast/broadcast)

Plater
Expert 5K+
P: 7,872
(Sorry about the title, i'm not sure how to explain this)

I am wondering if it is possible to tell on socket, HOW the incoming data was sent.
Now, what I mean by that is, I have a UDP socket just reading messages in a loop that come in on a port and pumping out a msg such like "Data from [IP Addy] arrived".
But if I "send" data to it, I want to know if it came from unicast, broadcast, or multicast.
Is that possible? It seems like it should be, but maybe I need to be in RAW mode and examine the bytes in the various headers?
Any thoughts?
Nov 2 '10 #1
Share this Question
Share on Google+
17 Replies


Oralloy
Expert 100+
P: 983
Do you mean you want to know if it was sent to a unicast, broadcast, or multicast address, or it was sent from such an address?

I think the answer is that you need to inspect the address to determine its status.

Here is the wikipedia on IP Multicast addressing.

Here are the pertinent bits from the article:

Unicast: The most common concept of an IP address is in unicast addressing, available in both IPv4 and IPv6. It normally refers to a single sender or a single receiver, and can be used for both sending and receiving. Usually, a unicast address is associated with a single device or host, but it is not a one-to-one correspondence. Some individual PCs have several distinct unicast addresses, each for its own distinct purpose. Sending the same data to multiple unicast addresses requires the sender to send all the data many times over, once for each recipient.

Broadcast: In IPv4 it is possible to send data to all possible destinations ("all-hosts broadcast"), which permits the sender to send the data only once, and all receivers receive a copy of it. In the IPv4 protocol, the address 255.255.255.255 is used for local broadcast. In addition, a directed (limited) broadcast can be made by combining the network prefix with a host suffix composed entirely of binary 1s. For example, the destination address used for a directed broadcast to devices on the 192.0.2.0/24 network is 192.0.2.255. IPv6 does not implement broadcast addressing and replaces it with multicast to the specially-defined all-nodes multicast address.

Multicast: A multicast address is associated with a group of interested receivers. In IPv4, addresses 224.0.0.0 through 239.255.255.255 (the former Class D addresses) are designated as multicast addresses.[2] The sender sends a single datagram from its unicast address to the multicast group address and the intermediary routers take care of making copies and sending them to all receivers that have joined the corresponding multicast group. IPv6 uses the address block with the prefix ff00::/8 for multicast applications.

Anycast (here for completeness): Like broadcast and multicast, anycast is a one-to-many routing topology. However, the data stream is not transmitted to all receivers, just the one which the router decides is the "closest" in the network.[Note 1] Anycast is useful for global load balancing and is commonly used in DNS communications.

I don't remember if there are macros available to check addresses or not, though.

Good luck!
Nov 2 '10 #2

Plater
Expert 5K+
P: 7,872
I guess who it was going TO is my question.

For instance with that UDP socket spitting out packets it sees (call it the "server"), I did the following:
*Had a client software on the same system send a UDP message to 255.255.255.255 (broadcast) on the port and my "server" saw the message and said "message from 127.0.0.1"
*Had a client software on the same system send to a multicast ip and my "server" saw the message and said "message from 192.168.1.7" (which is the IP of the machine the code was running on)

I was wondering if on the server I could tell the difference between those two messages (and a unicast to 192.168.1.7).
Would I change my server to have sockets be bound to a specific address (one to 192.168.1.7 and one to the multicast address) would that allow me to tell them apart?

While it is not crucial to the design that i know how the messages were received by my server, it would make things a bit easier on me.

(For what it is worth, I am playing with UPNP and listening for traffic on 1900. Messages from the multicast address are going to be general discover/announce payloads, messages sent to ME(unicast) are directed responses)
Nov 2 '10 #3

Oralloy
Expert 100+
P: 983
It looks like you're doing local loop-back for your testing, from what I read, correct?

If I recall correctly, sockets can bind to multiple addresses on a system. This is especially important for listening sockets, as they'll listen on 127.0.0.1 (loopback) as well the systems "normal" addresses. If you want to mask out localhost-loopback messages from your testing, you'll need to be careful about that. The problem is exacerbated with each IP address you add to your system, of course.

Alternately, you can drain off all recieved messages, expecting to recieve multiples. I happen to think that this is the better option.

Remember that it's the recipient's IP address that determines how a message is moved around the network. Which means that you can sent to a multi-cast address from a unicast address, right? That is, I can send a message from my local (unicast) IP of 10.1.2.3 to the multicast IP 224.1.2.3, right?

So, the address you recieved the message at determines how the message was sent.

The address the message was sent from determines how the reply will be handled. [as an aside, this is how SMURF and other attacks are crafted using raw sockets].

Since I don't know what your application is, I'm not sure what else to tell you which will help. Hopefully I'm not confusing you here.

Cheers!
Nov 2 '10 #4

Plater
Expert 5K+
P: 7,872
Well the end result would be the packets would be coming from other computers on my network, it is just in testing that i happened to be using the same machine for it.
I am thinking there is no good way to tell (outside of being in raw mode) I may have to look into that method
Nov 2 '10 #5

Oralloy
Expert 100+
P: 983
I guess I'm confused.

If you're listening on a UDP socket, you'll get the sender's address attached to your message. You already know the recieving address, if you set up your sockets correctly. Nothing prevents you from opening multiple listening sockets in parallel.

As for a TCP socket, you also get the sender's address as part of the connection request. Once listen() returns, you'll be able to get the address.
Nov 2 '10 #6

Plater
Expert 5K+
P: 7,872
I know I can get the senders address, what i want is the address the sender SENT to.

If my server UDP socket is listening (IPANY, PORT 1900)
Has IP 192.168.1.7
Subscribed to multicast IP 239.255.255.250

If the client software:
Has IP 192.168.1.4
Sends one message unicast to 192.168.1.7:1900
Sends one message multicast to 239.255.255.250:1900
Sends one message to broadcast 255.255.255.255:1900

My server UDP will see all 3 messages, all will say they came from 192.168.1.4. Is there a way to tell on the SERVER which message was sent out in what manor (which one was sent to 239.255.255.250 and etc)?
Nov 3 '10 #7

Oralloy
Expert 100+
P: 983
Ok, I did some quick research, and it's not clear how to extract the recieving address from a conversation.

BTW, are you trying to build a network sniffer of some sort?

Regardless, I'm surprised that you're able to see multicast messages that you haven't registered in the multicast group for. That seems to be how the newer sockets protocol specification wants software to behave.

At this point, I'd start actively consider using raw sockets, just to make sure that I got all the requisite information from the incoming UDP packets. I can't think of any other way of extracting all requisite information, although we might have someone else here who is more knowledgable than I am.

Sorry I can't give you better information than that.

Good luck!
Nov 3 '10 #8

Plater
Expert 5K+
P: 7,872
Just trying to implememnt UPNP "by hand" so to speak.
And sorry, yes I have subscribed to the multicast group with the IP_ADD_MEMBERSHIP.

I was hoping there was some sort of API to read the extra data from the packet, but i can see why there isn't.
Raw socket it is probably going to be.
Nov 4 '10 #9

Oralloy
Expert 100+
P: 983
Plater - you, Sir, are an ambitious man.

Good luck with your home-brew UPnP. I hope it works out well for you.

When you get done, let us know what your implementation is, would you, please?

Cheers!
Oralloy
Nov 4 '10 #10

Plater
Expert 5K+
P: 7,872
It really was not so bad. I had notes from a few years ago when I tried to do raw sockets and failed.
Now it makes a lot more sense to me (and it works)

Expand|Select|Wrap|Line Numbers
  1. int s_sock =socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
  2. //SOCK_RAW             so you can get extra data in the recv packet
  3. //IPPROTO_UDP        sets the proto field to 0x11(UDP) in packets (expects 8byte UDP header before payload data)
  4. //this will make more sense later
  5.  
  6. //I do not need to call a bind(), all it does is allow sockaddr_in to be filled-in from the recvfrom call
  7. //You could use recv() and ignore the sockaddr_in stuff altogether I think.
  8. //Since I want to get messages on a multicast address, I *DO* still need to join it it would seem
  9. struct ip_mreq imreq;
  10. imreq.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
  11. imreq.imr_interface.s_addr = INADDR_ANY; // use DEFAULT interface
  12. // JOIN multicast group on default interface
  13. int status = setsockopt(s_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,(const void *)&imreq, sizeof(struct ip_mreq));
  14. if ( status < 0 )
  15. {//failure!
  16.      perror("Trying to join multicast group");//this will print a nice message about ERRNO
  17.      return 0;
  18. }
  19.  
  20. struct sockaddr_in from;//This will never fill in correctly if you don't do a BIND
  21. socklen_t fromlen = sizeof(struct sockaddr_in);
  22. char buf[1024];
  23. memset(buf,0x00,1024);
  24. int n = recvfrom(s_sock,buf,1024,0,(struct sockaddr *)&from,&fromlen);
  25. /* //the first 20bytes [0-19] are the basic header
  26. buf[0]=         (Version 4 and header length=20bytes)
  27. buf[1]=         (diferentiated service field)
  28. buf[2-3]=        (total length)
  29. buf[4-5]=        (identification)
  30. buf[6-7]=        (Flags(0x04)+fragment offset=0)
  31. buf[8]=         (TTL)
  32. buf[9]=         (protocol)
  33. buf[10-11]=    (header checksum)
  34. buf[12-15]= (source ip)
  35. buf[16-19]= (dest ip)
  36. */
  37.  
  38. //You are going to get all data on the interface it would seem, so I narrow down to UDP with buf[9] 
  39. if (buf[9] == IPPROTO_UDP)//buf[9] is the idx for the protocol field and I only want UDP messages
  40. {
  41.     /* //UDP messages have another 8 byte header
  42.     buf[20-21]=    2byte source
  43.     buf[22-23]=    2byte dest
  44.     buf[24-25]=    2byte length
  45.     buf[26-27]=    2byte checksum
  46.     */
  47.     int sourceport=htons(buf[20]+(buf[21]<<8));
  48.     int destport=htons(buf[22]+(buf[23]<<8));
  49.     //Narrowing it down again, I only want data sent to MY port 1900 (which would be destport in the udp header) using buf[22-23]
  50.     if(destport==1900)
  51.     {
  52.         printf("FromIP: %u.%u.%u.%u:%u\n", (unsigned char) buf[12],(unsigned char) buf[13], (unsigned char) buf[14],(unsigned char) buf[15],sourceport);
  53.         printf("ToIP: %u.%u.%u.%u:%u\n",(unsigned char)buf[16],(unsigned char)buf[17],(unsigned char)buf[18],(unsigned char)buf[19],destport);
  54.         //payload data starts at buf[28]
  55.         //for me it is string data (HTTP-UDP), anyone else could be anything
  56.     }
  57. }
  58.  
Nov 5 '10 #11

Oralloy
Expert 100+
P: 983
Plater,

Thanks for posting your solution. I learned something!

Cheers!
Oralloy
Nov 8 '10 #12

Oralloy
Expert 100+
P: 983
@Plater,

It looks like you might have a bug in lines 47 and 48:
Expand|Select|Wrap|Line Numbers
  1. //--original
  2.     int sourceport=htons(buf[20]+(buf[21]<<8)); 
  3.     int destport=htons(buf[22]+(buf[23]<<8)); 
  4. //--modified
  5.     int sourceport=ntohs(*(short *)(buf + 20)); 
  6.     int destport=ntohs(*(short *)(buf + 22)); 
You probably aren't seeing anything, as the network byte order is little-endian, and your computer matches it - thus rendering the functions htons() and ntohs() as identity transforms.

Cheers!
Nov 8 '10 #13

Plater
Expert 5K+
P: 7,872
Good catch, I stole that from somewhere else. Normally I wouldn't even use those functions at all and would hand assemble those bytes in the correct order. (Which isn't very robust)
Could you not also do:
ntohs(*(short *)(&buf[20]));
Nov 9 '10 #14

Oralloy
Expert 100+
P: 983
Actually, that's the code form I considered before I settled on the offset-addition form.

Either form should work just fine, at least until we run into a system where a short is something other than 16 bits, in which case we'll have to provide new networking primitives to handle byte ordering.

Good Luck!
Nov 9 '10 #15

Plater
Expert 5K+
P: 7,872
I found the function recvmsg() that claims it would expose the interface/ip/port data, but so far i've found it to be convuluted way to get the same data as i did above. (It filled in a buffer with the same bytes as buf had, at the same indexes too)
Also, it only seemed to get any messages when i'm in RAW mode anyway.
So unless there is a better way to use it in a non-RAW socket, it is not useful.
Nov 10 '10 #16

Oralloy
Expert 100+
P: 983
Well recvmsg() seems to do about what you need, but if you're already cracking the raw bytes of the message - just run with what you have.
Nov 10 '10 #17

Plater
Expert 5K+
P: 7,872
Well the points really were:
*recvmsg only worked on a raw socket.
*recvmsg through convulted means, populated a char[] with the bytes that came in
*Using either method, i still had to interpret what bytes belonged to what field.

I would say it is actually MORE difficult to use recvmsg then to just use recv
Nov 11 '10 #18

Post your reply

Sign in to post your reply or Sign up for a free account.