Tuesday, January 29, 2013

Socket Option: Multicast Interface


Disclaimer: this is a short description of a code snippet primarily for myself because I had failed to find corresponding details in MSDN as well as on Google about SocketOptionName.MulticastInterface parameter values. Feel free to use it if you're experiencing the same lack of luck.

Multicasts... You have to learn them right after generic sockets (aka unicasts) and massive spam-like broascasts. According to their nature, multicasts gather one-shot-to-many strength of broadcasting and can pass boundaries of nested networks like unicasts. The only weak side is knowledge "how to tune the socket".

How many networks?

In old good days, main question for network-oriented code was: do you have a connection? In quite advanced cases you had to be interested about "is it LAN connection or dial-up modem?". What a happy times! Nova days, you have to be extremely worry about "how many possible connections are available" and "which of them are really up and running". Reason is simple:

  • VPN connections (half-joke: dear Cisco, could you been so kind to fix your "Cisco VPN Client" software, even in XXI century?)
  • Wi-Fi cards and dongles
  • Two-LAN motherboards
  • Virtual machines and other "virtual" network devices
Why this can be a problem?
In ideal world, network is automatically routed so every data packet will be sent most eficient way to the destination point. In practice, there are inevitable ambiguities and conflicts. Especially for multicasts.

Default all-hearing ear

Sending a multicast means you use special IP address to use as a destination point, that's it. Other staff is trivial: create an UDP socket, use SendTo() function, read back every answer. It works? Yes, it works... works again and again... Oh, no, this time it stopped! Let me guess why: you opened a VPN connection to your workplace few moments ago...
By default, most operating systems use one and only one network interface to listen for multicast traffic. If you got another interface activated, there is a chance that your OS can decide new interface is more "important" in terms of multicasts so new multicast listener been elected. In most cases, VPN connections are treated as "more important" than generic ones, so you have all your multicast traffic passed to wrong wire. And with 99% probability, your admin is smart enough to cut off any optional data exchange via VPN due security restrictions (and traffic bills optimization as well). As long as multicasts are non-reliable UDP packets, there are no retransmits nor timeouts... So, you send multicast request and have no idea could you expect any response (and VPN gate will cut it off silently). To cure such "black hole" scenario, you need to set socket option "I want given interface as multicast ear" instead of default auto-election.

Cure is known. Any pill for C#?

Despite big differences in operating systems and programming languages, network layer shares the same ideas on Windows and Linux, C++ and Python etc. So it's easy to find out that sockets provide such option as IP_MULTICAST_IF at IP_PROTO layer so you can put any of your local IP addresses as "multicast ear" with setsockopt() call.
At C#, there are the same ingredients:
  my_sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  ...
  my_sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, ???);
Wait, but what we have to place as a last param?
MSDN does very common description for SetSocketOption last param "optionValue: A value of the option". SocketOptionName enumeration also stay away from answering anything other than "MulticastInterface: Set the interface for outgoing multicast packets". Not good... Help me, Google!

Unfortunately, Google results provide a lot of forum discussions finally refering to KB318911. Full oh hope, you click it just to see this:

When you use MulticastInterface as the value for the SocketOptionName enumeration, the optionValue expects an Index value of the particular Network Adapter or Interface. Note that there is currently no API in the .NET Framework to determine the index of a particular adapter. Therefore, the user must input the index value.

The article was published at February 11, 2004 as Revision: 1.1 and nothing new since then...

Network adapter index is here

Once found that article, I got big anger. "Arrrgh! Impossible! It can't be true!" idea stuck in my mind. And, scratching the head during few days, step by step I composed the following snippet:

  NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
  foreach (NetworkInterface adapter in nics)
  {
    IPInterfaceProperties ip_properties = adapter.GetIPProperties();
    if (!adapter.GetIPProperties().MulticastAddresses.Any())
      continue; // most of VPN adapters will be skipped
    if (!adapter.SupportsMulticast)
      continue; // multicast is meaningless for this type of connection
    if (OperationalStatus.Up != adapter.OperationalStatus)
      continue; // this adapter is off or not connected
    IPv4InterfaceProperties p = adapter.GetIPProperties().GetIPv4Properties();
    if (null == p)
      continue; // IPv4 is not configured on this adapter
    my_sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)IPAddress.HostToNetworkOrder(p.Index));
  }


Looking back, the idea is simple: enumerate all network interfaces, skip every inapplicable, then get IP interface properties, get this "undocumented" adapter index. And don't forget about this low-level staff, HostToNetworkOrder() bytes swapper!

Happy coding!

4 comments:

  1. I could not find a property MulticastAddresses.Any() what are we trying to do with this line

    ReplyDelete
  2. Hi bipinkrishna,

    This is extensions methods feature, namely Linq.
    Just add the following at the beginning of your .cs file:
    ...
    using System.Linq;
    ...

    Learn more about extension methods here http://msdn.microsoft.com/en-us/library/vstudio/bb383977.aspx

    ReplyDelete
    Replies
    1. Hello Yury, Thank you.
      The UDP multicast doesn't seem to work while I'm connected to a VPN. However if I disconnect my VPN and try to multicast then the other clients are receiving the message. I tried to send the message through my LAN interface using the above technique, but still no luck. Could you advice?
      Thanks in advance

      Delete
    2. Hi bipinkrishna,

      First question: what kind of VPN do you use? If this is Cisco VPN Client software, I afraid it can switch your network interface to exclusive tunnel on kernel level, as a side-effect of enormous security model, so we can say that VPN is actually VPN + firewall + antivirus + bugs (so I used to remove manually some Cisco DLL files to make it work with my local intranet resources).

      Anyway, could you try to observe the traffic with Wireshark as it will advise you what is actually posted on wire (so you will get a clue: do you have modified traffic or have no traffic wired at all). Yep, I know, Wireshark is not "welcome-tool-for-everyone" but if you learn it it will return your time investments with gross profit in future as it is ultimate network-cracking tool (and I wonder why it is free).

      Delete