Подтвердить что ты не робот

Привязать сокет к сетевому интерфейсу

Как связать сокет с определенным сетевым интерфейсом? Я попытался использовать setsockopt на стороне сервера, но клиенты все равно могут получить доступ к службе через оба интерфейса eth0 и lo.

Я могу добиться этого, установив конкретный IP-адрес, используя serv_addr.sin_addr.s_addr.

Но я подозреваю, что мы можем привязываться к интерфейсу, используя только setsockopt (без упоминания IP-адреса).

4b9b3361

Ответ 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;

Теперь мы можем привязать сокет к интерфейсу как обычно.