Резервное интернет-соединение для определенного процесса

Резервное интернет-соединение для определенного процесса

Я хотел бы добавить второе резервное интернет-подключение к моему серверу Linux. Я планирую использовать для этой цели USB LTE-модем.

Поскольку это сотовое соединение будет тарифицироваться, я хочу ограничить объем потребляемых данных до абсолютно необходимого минимума.

У меня есть пользовательское серверное приложение, в которое я могу вносить любые изменения. У него есть несколько задач, где бесперебойное подключение имеет решающее значение, и другие задачи, где время простоя не имеет особого значения.

Я представляю себе что-то вроде этого:

  • Серверу необходимо сделать внешний запрос HTTP API. Первая попытка выполняется по маршруту системы по умолчанию (т. е. eth0, первичное интернет-подключение).
  • Если запрос не выполнен или истекло время ожидания, повторите запрос через интерфейс LTE.

Только трафик, который мой серверный процесс явно хочет отправить через LTE, должен быть отправлен через LTE. Никакой другой трафик из любой части системы не должен проходить через LTE.

  • В частности, я буду использовать узелlocalAddressопция сокета, указывающая, что запрос должен быть выполнен через LTE.
  • Как гарантировать, что остальной трафик не будет маршрутизироваться через интерфейс LTE (даже если eth0 не работает)?
  • А как насчет разрешения DNS?

решение1

Я в конечном итоге добился этого, настроивальтернативная таблица маршрутови аправило политики маршрутизациидля исходного адреса резервного интерфейса.

Мой USB LTE-модем представлен как устройство NDIS, поэтому он просто отображается как eth1IP 192.168.0.190 и выполняет внутреннюю маршрутизацию NAT. Я настроил eth1статический IP и вручную настроил маршруты.

  1. В конфигурации по умолчанию используется DHCP, поэтому отключите интерфейс и убедитесь, что все автоматически добавленные маршруты удалены.

  2. Добавьте статическую IP-конфигурацию для интерфейса и включите ее.

  3. Добавьте записи в альтернативную таблицу маршрутизации (я выбрал 1) для подсети и шлюза по умолчанию.

    # ip route add 192.168.0.0/24 dev eth1 src 192.168.1.190 table 1
    # ip route add default via 192.168.0.1 table 1
    
  4. Установите правила политики маршрутизации таким образом, чтобы приложения, явно использующие 192.168.1.190 в качестве исходного адреса, использовали таблицу маршрутизации 1 вместо таблицы маршрутизации по умолчанию.

    # ip rule add from 192.168.0.190/32 table 1
    # ip rule add to 192.168.0.190/32 table 1
    

На этом этапе вы сможете проверить свое подключение.

$ curl https://wtfismyip.com/text
1.2.3.4  # primary ISP external IP
$ curl --interface 192.168.0.190 https://wtfismyip.com/text
5.6.7.8  # backup LTE external IP

Если все выглядит хорошо, сделайте конфигурацию постоянной. Я добавил в /etc/network/interfaces:

iface eth1 inet static
        address 192.168.0.190
        netmask 255.255.255.0
        post-up ip route add 192.168.0.0/24 dev eth1 src 192.168.0.190 table 1
        post-up ip route add default via 192.168.0.1 table 1
        post-up ip rule add from 192.168.0.190/32 table 1
        post-up ip rule add to 192.168.0.190/32 table 1

Теперь только приложения, которые явно привязаны к 192.168.0.190 при создании исходящих подключений, будут маршрутизироваться через резервное подключение. Весь остальной трафик будет маршрутизироваться через eth0(или через то, что настроено в mainтаблице маршрутизации [default]).

Этовозможныйчто у вас есть что-то, что перечисляет все доступные IP и пытается отправить трафик с них, что может привести к неожиданному трафику через резервное соединение, но это маловероятно. Я не наблюдал такого трафика.

Обратите внимание, что это не касается разрешения DNS. В ситуации, когда основное соединение находится в автономном режиме, вам может повезти, и вы получите поиск из кэша, но на это не стоит полагаться. Я бы также не настраивал системный резолвер для отправки запросов через интерфейс LTE. Вместо этого ваше приложение может вручную обрабатывать разрешение DNS при выполнении запросов на резервное копирование.


С помощью node легко делать HTTP-запросы (или любое TCP-соединение) с определенного исходного адреса. Просто укажитеlocalAddressвариант, например:

https.get('https://wtfismyip.com/text', { localAddress: '192.168.0.190' }, …);

Решение DNS-поиска немного сложнее. lookupТакже доступна опция, которая позволяет переопределить процесс разрешения DNS по умолчанию. Вы можете использовать пользовательскийdns.Resolverдля выполнения поиска. К сожалению, у узла не было возможности указать исходный адрес для поиска DNS,поэтому я добавил это. После этого вы можете собрать все части воедино:

const resolver = new dns.Resolver();
resolver.setServers(['8.8.8.8']);
resolver.setLocalAddress('192.168.0.190'); // requires node > v15.0.0

https.get('https://wtfismyip.com/text', {
  localAddress: '192.168.0.190',
  lookup: function(hostname, opts, cb) {
    resolver.resolve(hostname, function(err, records) {
      if (err) cb(err);
      else if (!records[0]) cb(new Error('Missing DNS record'));
      else cb(null, records[0], 4);
    });
  }
}, function(res) { … });

Связанный контент