Привязать сокет к сетевому интерфейсу
Как связать сокет с определенным сетевым интерфейсом? Я попытался использовать setsockopt
на стороне сервера, но клиенты все равно могут получить доступ к службе через оба интерфейса eth0 и lo.
Я могу добиться этого, установив конкретный IP-адрес, используя serv_addr.sin_addr.s_addr
.
Но я подозреваю, что мы можем привязываться к интерфейсу, используя только setsockopt
(без упоминания IP-адреса).
Ответы
Ответ 1
Вы можете привязываться к определенному интерфейсу, установив опцию сокета SO_BINDTODEVICE
.
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth0");
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
... error handling ...
}
Предупреждение. Чтобы использовать эту опцию, вы должны быть root и иметь возможность CAP_NET_RAW
.
Второй способ заключается в том, что вы можете разрешить IP-адрес, привязанный к интерфейсу, с помощью getifaddrs().
Следуйте последней ссылке для исчерпывающего примера.
Ответ 2
Единственный способ сделать это - как вы упомянули -
установив конкретный IP-адрес, используя serv_addr.sin_addr.s_addr
Вы не можете сделать это, не зная адрес для привязки.
Вы можете использовать ioctl
, чтобы определить текущий IP-адрес, если вам нужно, хотя в наши дни может быть более умный способ сделать это - я не много сделал в современных дистрибутивах Linux в последнее время.
Ответ 3
Может быть, кто-то найдет это полезным, поэтому я делюсь решением, которое работало для меня (Linux, C++):
uint32_t interfaceIndex = if_nametoindex(interfaceName);
Где "interfaceName" - это имя интерфейса, к которому мы хотим привязать, например, "eth0" (см.: https://linux.die.net/man/3/if_nametoindex). Теперь мы можем указать этот интерфейс в структуре адреса сокета через "sin6_scope_id" (в случае, если мы используем IPv6):
struct sockaddr_in6 socketAddress;
socketAddress.sin6_scope_id = interfaceIndex;
Теперь мы можем привязать сокет к интерфейсу как обычно.