简体   繁体   中英

how to specify which interface to use for a socket in linux

Is it possible to bind a udp socket to a specific interface so it sends data through that interface? I have an application that uses several Udp Sockets to send data and it is running on a machine with several interfaces. I know it's possible to do this by specifying the interface name by using this code:

int UdpSocket::open(const char *interface)
{
   send_fd_ = ::socket(AF_INET, SOCK_DGRAM, 0);
   if (send_fd_ < 0)
   {
      perror("socket");
      return -1;
   }

   int val = 1;
   int rc = ::setsockopt(send_fd_, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
   if (rc < 0)
   {
      perror("sesockopt");
      close();
      return -1;
   }

   unsigned char ttl = 16;
   rc = ::setsockopt(send_fd_, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
   if (rc < 0)
   {
      perror("sesockopt_ttl");
      close();
      return -1;
   }

   if (interface != NULL)
   {
      struct ifreq ifr;

      memset(&ifr, 0, sizeof(ifr));
      snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), interface);
      rc = ::setsockopt(send_fd_, SOL_SOCKET, SO_BINDTODEVICE, (void*)&ifr, sizeof(ifr));

      if (rc < 0)
      {
         perror("sesockopt");
         close();
         return -1;
      }
   }

   const int flags = ::fcntl(send_fd_, F_GETFL, 0);
   ::fcntl(send_fd_, F_SETFL, flags | O_NONBLOCK);

   return 0;
}

But this requires that the app is run with root privileges, otherwise it it will throw an error saying the "operation not permitted."

The easiest, and by far the most sane, approach is to add route (s) matching your multicast destinations:

~# route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0

since OS network stack selects outbound interface for multicast packets based on the routing table. This also works for listening - you just bind to group address and kernel would pick correct interface for you. You still have to join the group as usual.

From the manpage:

SO_BINDTODEVICE

Bind this socket to a particular device like “eth0”, as specified in the passed interface name. If the name is an empty string or the option length is zero, the socket device binding is removed. The passed option is a variable-length null-terminated interface name string with the maximum size of IFNAMSIZ. If a socket is bound to an interface, only packets received from that particular interface are processed by the socket. Note that this only works for some socket types, particularly AF_INET sockets. It is not supported for packet sockets (use normal bind(2) there).

This means you have to get the interface from the name yourself, possibly using getifaddrs, and then bind to that address.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM