Широковещательные пакеты не распространяются через veth-туннель Linux

Я разрабатываю сетевое приложение, использующее широковещательную передачу в подсети. Я решил настроить контролируемую среду для тестирования и разработки на своей локальной машине с использованием виртуальных интерфейсов Ethernet (veth). Настройка проста:

ip link add veth0 type veth peer name veth1
ifconfig veth0 192.168.241.1 netmask 255.255.255.0 up
ifconfig veth1 192.168.241.2 netmask 255.255.255.0 up

ip link подтверждает, что интерфейсы включены и установлены флаги широковещания:

8: veth1@veth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 46:29:76:81:27:af brd ff:ff:ff:ff:ff:ff
9: veth0@veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 3a:ad:f9:cb:28:a8 brd ff:ff:ff:ff:ff:ff

Тривиальный тест в Python REPL показывает, что интерфейсы работают. Это приемник:

>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.bind(('192.168.241.2', 48469))
>>> s.recvfrom(1000)
(b'abc', ('192.168.241.1', 45560))

А это отправитель:

>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.connect(('192.168.241.2', 48469))
>>> s.send(b'abc')
3

Хорошо работает для одноадресных пакетов. Однако широковещательные пакеты отбрасываются незаметно. Для воспроизведения проблемы можно использовать следующий REPL на стороне отправителя:

>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
>>> s.connect(('192.168.241.255', 48469))
>>> s.send(b'abc')
3
>>> s  # For diagnostic purposes
<socket.socket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('192.168.241.1', 48065), raddr=('192.168.241.255', 48469)>

Сокет настроен успешно, но отправленные широковещательные пакеты никогда не попадают на другую сторону туннеля. Это не то поведение, которого я ожидал, особенно с учетом того, что флаги интерфейса указывают на то, что интерфейсы поддерживают широковещательную передачу. Я запускаю эти тесты на Linux Mint 18 со стандартным ядром. Что мне не хватает?

1 ответ

Решение

Туннель в порядке.

Проблема заключалась в том, что Linux отбрасывает весь входящий широковещательный трафик, если сокет не привязан к INADDR_ANY. Если REPL на стороне получателя обновляется следующим образом, все работает:

>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
>>> s.bind(('', 48469))  # Bind to INADDR_ANY to accept broadcast packets
>>> s.recvfrom(1000)
(b'abc', ('192.168.241.1', 45560))

В Windows поведение другое (независимо от туннеля): привязка сокета к определенному интерфейсу не отклоняет широковещательный трафик.

Man 7 IP говорит, что SO_BROADCASTдолжен быть установлен для приема широковещательных дейтаграмм; однако поведение, которое я наблюдаю на принимающей стороне, похоже, не соответствует описанию:

Дейтаграммы на широковещательные адреса могут быть отправлены или получены, только если установлен флаг сокета SO_BROADCAST.

Широковещательные дейтаграммы всегда можно получить с INADDR_ANY; никогда, если сокет привязан к определенному интерфейсу. Оба утверждения верны независимо отs.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1).

Другие вопросы по тегам