face: bugfix of MulticastUdpFace receiving packets from all available NICs on Linux

Now on Linux the creation of MulticastUdpFace requires
CAP_NET_RAW capability if the name of the interface is specified

Change-Id: Iff53035371fb26c6ee40e1065a0935e5ed16dc60
Refs: #1475
diff --git a/daemon/face/udp-factory.cpp b/daemon/face/udp-factory.cpp
index cac94a2..e97e9bb 100644
--- a/daemon/face/udp-factory.cpp
+++ b/daemon/face/udp-factory.cpp
@@ -27,6 +27,10 @@
 #include "core/resolver.hpp"
 #include "core/network-interface.hpp"
 
+#if defined(__linux__)
+#include <sys/socket.h>
+#endif
+
 namespace nfd {
 
 using namespace boost::asio;
@@ -163,9 +167,10 @@
 
 shared_ptr<MulticastUdpFace>
 UdpFactory::createMulticastFace(const udp::Endpoint& localEndpoint,
-                                const udp::Endpoint& multicastEndpoint)
+                                const udp::Endpoint& multicastEndpoint,
+                                const std::string& networkInterfaceName /* "" */)
 {
-  //checking if the local and musticast endpoint are already in use for a multicast face
+  //checking if the local and multicast endpoint are already in use for a multicast face
   shared_ptr<MulticastUdpFace> multicastFace = findMulticastFace(localEndpoint);
   if (static_cast<bool>(multicastFace)) {
     if (multicastFace->getMulticastGroup() == multicastEndpoint)
@@ -224,6 +229,24 @@
     throw Error(msg.str());
   }
 
+#if defined(__linux__)
+  //On linux system, if there are more than one MulticastUdpFace for the same multicast group but
+  //bound on different network interfaces, the socket has to be bound with the specific interface
+  //using SO_BINDTODEVICE, otherwise the face will receive packets also from other interfaces.
+  //Without SO_BINDTODEVICE every MulticastUdpFace that have joined the same multicast group
+  //on different interfaces will receive the same packet.
+  //This applies only on linux, for OS X the ip::multicast::join_group is enough to get
+  //the desired behaviour
+  if (!networkInterfaceName.empty()) {
+    if (::setsockopt(clientSocket->native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
+                     networkInterfaceName.c_str(), networkInterfaceName.size()+1) == -1){
+      throw Error("Cannot bind multicast face to " + networkInterfaceName
+                  + " make sure you have CAP_NET_RAW capability" );
+    }
+  }
+
+#endif
+
   clientSocket->set_option(ip::multicast::enable_loopback(false));
 
   multicastFace = make_shared<MulticastUdpFace>(boost::cref(clientSocket), localEndpoint);
@@ -237,13 +260,15 @@
 shared_ptr<MulticastUdpFace>
 UdpFactory::createMulticastFace(const std::string& localIp,
                                 const std::string& multicastIp,
-                                const std::string& multicastPort)
+                                const std::string& multicastPort,
+                                const std::string& networkInterfaceName /* "" */)
 {
 
   return createMulticastFace(UdpResolver::syncResolve(localIp,
                                                       multicastPort),
                              UdpResolver::syncResolve(multicastIp,
-                                                      multicastPort));
+                                                      multicastPort),
+                             networkInterfaceName);
 }
 
 void