特定のプロセスのバックアップインターネット接続

Aug 17 2020

Linuxサーバーにセカンダリバックアップインターネット接続を追加したいのですが。この目的のためにUSBLTEモデムを使用する予定です。

このセルラー接続は計測されるため、消費できるデータの量を必要最小限に制限したいと思います。

変更を加えることができるカスタムサーバーアプリケーションがあります。中断のない接続が重要ないくつかのタスクと、ダウンタイムが実際には問題にならない他のタスクがあります。

私はこのようなものを想像しています:

  • サーバーは外部HTTPAPIリクエストを行う必要があります。最初の試行は、システムのデフォルトルート(つまり、プライマリインターネット接続であるeth0)を介して行われます。
  • リクエストが失敗またはタイムアウトした場合は、LTEインターフェイスを介してリクエストを再試行してください。

サーバープロセスが明示的にLTE経由で送信したいトラフィックのみをLTE経由で送信する必要があります。システムのどの部分からのその他のトラフィックもLTEを経由してはなりません。

  • 具体的には、ノードのlocalAddressソケットオプションを使用して、LTE経由でリクエストを行うように指定します。
  • (eth0がダウンしている場合でも)他のトラフィックがLTEインターフェイスを介してルーティングされないようにするにはどうすればよいですか?
  • DNS解決はどうですか?

回答

josh3736 Sep 01 2020 at 03:53

最終的に、バックアップインターフェイスの送信元アドレスに代替ルートテーブルとルーティングポリシールールを設定することで、これを実現しました。

私が持っているUSBLTEモデムはNDISデバイスとして存在するためeth1、IPが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[デフォルト]ルーティングテーブルで構成されているものは何でも)。

使用可能なすべてのIPを列挙し、それらからトラフィックを送信しようとするものがある可能性があります。これにより、バックアップ接続を介して予期しないトラフィックが発生する可能性がありますが、それはほとんどありません。私はそのようなトラフィックを観察していません。

これはDNS解決に対応していないことに注意してください。プライマリ接続がオフラインの状況では、運が良ければキャッシュからルックアップを取得できるかもしれませんが、それを信頼するのは良くありません。LTEインターフェースを介してリクエストを送信するようにシステム全体のリゾルバーを構成することもしません。代わりに、アプリはバックアップリクエストを行うときにDNS解決を手動で処理できます。


ノードを使用すると、特定の送信元アドレスから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) { … });