Round-robin default gateway ломает маршрутизацию от источника для OpenVPN
На Linux (Debian 8) шлюзе настроена маршрутизация от источника (multipath) при помощи iproute2. Корректно маршрутизируются как forward пакеты, так и input\output. Но после включения round-robin default gateway стали возникать проблемы при подключении OpenVPN клиентов
Round-robin gateway был включен следующей командой:
ip route add default scope global nexthop via $GW1 dev $IF1 weight 1 nexthop via $GW2 dev $IF2 weight 1 nexthop via $GW3 dev $IF3 weight 1
В реальности с маршрутизацией все немного сложнее, но эти частности не сильно влияют на конечный вывод, поэтому их можно опустить. Как видно, попеременно используется три шлюза с одинаковым весом. OpenVPN сервер настроен так, что слушает все интерфейсы и работает по UDP протоколу, полный конфиг приведен в данной статье. По идее, OpenVPN должен работать при таких настройках, но нет, клиенты перестали подключаться к данному серверу. Хотя тот же SSH продолжал работать при подключении по любому из интерфейсов. Можно предположить, что причина в UDP протоколе, но тест на DNS сервере показал, что ответы на UDP запросы возвращаются с нужных интерфейсов. Таким образом, при включении Round-robin gateway, маршрутизация от источника сломалась только для OpenVPN и причину надо искать в нем.
При коннекте, перед началом рукопожатия, запрашивается логин с паролем и авторизация проходит успешно, дальнейшее подключение не происходит, лог неудачного подключения клиента не говорит ровным счетом ни чего полезного:
TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity) TLS Error: TLS handshake failed SIGUSR1[soft,tls-error] received, process restarting MANAGEMENT: >STATE:1451454269,RECONNECTING,tls-error Restart pause, 2 second(s)
Интересно то, что у некоторых клиентов (по факту, было только на одном) в логах прилетало кое-что интересное. При подключении на первый интерфейс $GW1 лог выдавал следующее:
Incoming packet rejected from [AF_INET]$GW1:1194[2], expected peer address: [AF_INET]$GW2:1194 (allow this incoming source address/port by removing --remote or adding --float) Incoming packet rejected from [AF_INET]$GW1:1194[2], expected peer address: [AF_INET]$GW3:1194 (allow this incoming source address/port by removing --remote or adding --float)
И так по кругу. При чем, если на клиенте заменить IP адрес сервера на $GW2, то ответные пакеты будут приходить с $GW1 и $GW3, но не с $GW2. Т.е. к какому бы IP не подключался клиент, ответ никогда не приходит с того же интерфейса. Достаточно странное поведение. Повторю, в этот же момент маршрутизация от источника по другим подключениям работает исправно.
В поисках причин такого поведения выяснилось, что при настроенном OpenVPN на TCP протокол соединение все же происходит, таким образом причина в реализации OpenVPN при работе по UDP протоколу. Как причина стала ясна быстро нагуглилось решение - параметр multihome
на стороне сервера OpenVPN. Man openvpn параметра multihome:
--multihome Configure a multi-homed UDP server. This option needs to be used when a server has more than one IP address (e.g. multiple interfaces, or secondary IP addresses), and is not using --local to force binding to one specific address only. This option will add some extra lookups to the packet path to ensure that the UDP reply packets are always sent from the address that the client is talking to. This is not supported on all platforms, and it adds more processing, so it's not enabled by default. Note: this option is only relevant for UDP servers. Note 2: if you do an IPv6+IPv4 dual-stack bind on a Linux machine with multiple IPv4 address, connections to IPv4 addresses will not work right on kernels before 3.15, due to missing kernel support for the IPv4-mapped case (some distributions have ported this to earlier kernel versions, though).
Теперь понятно, причина кроется в работе самого OpenVPN по UDP протоколу. А опция multihome
добавляет какие-то дополнительной обработки к udp пакетам, которые гарантируют отсылку ответных пакетов с адреса на который пришел запрос. Конкретно же что происходит можно сказать после изучения исходников OpenVPN.