openssh+tapデバイスでイーサネットレベルの仮想ネットワークを作成し、さらに接続先の向こうへルーティングする。

sshの接続両端に、トンネリングデバイス(今回はtap)を作成してつなぐ。基本的な事は、「OpenSSH を使った簡易 VPN の構築」(Yusuke Shinyamaさん)にわかりやすく説明されている。

以下、設定例

トンネルデバイスを作成するため、sshのクライアント・サーバともrootとする。

サーバー側 /etc/ssh/sshd.config

PermitTunnel ethernet

クライアント側 /root/.ssh/config

host <サーバ>
  user root
  Tunnel  ethernet
  TunnelDevice 9:9  # ローカルのtap9 とリモートのtap9を作成

いったんtapデバイス2つ一組が作成されると、それらは:

  • 同一のイーサネットセグメントにあるのと等価
  • sshクライアント側/サーバー側に対応するような方向性はない

とはいえ、手元のホストから、接続相手のホストが属するネットワークへアクセスする使い方が多いと思うので、以後2つのホストを「手元」と「接続相手」と記す。

tapネットワークを超えてルーティング

sshの接続相手と共にファイヤウォールの中に設置されたサーバなどへアクセスできる。

条件

  • 接続相手から、特定のipアドレスやネットワークへ到達可能で、
  • かつmasquerade/SNATされていて、tapの使用にあたりルーティングテーブルの変更は必要ない。

方針

インターフェース設定は、systemd-networkd に任せる。masquerading も簡単に指定できる。 ssh接続してtapデバイスが作成されると、自動で設定適用してくれるので便利。 手元側のネットワーク設定に、接続相手経由のルートを記す。

接続相手側(192.168.10.2 /24)

  • iptables

    VPNの向こう側へ出てゆくパケットのソースアドレスを書き換えて、戻りを可能に。

    -A POSTROUTING -s 192.168.10.0/24 ! -o tap9 -j MASQUERADE
    
  • /etc/systemd/network/tap9.network

    [Match]
    Name=tap9
    
    [Network]
    Address=192.168.10.2/24
    IPForward=yes
    IPMasquerade=yes
    

手元(192.168.10.1 /24)

  • /etc/systemd/network/tap9.network

    [Match]
    Name=tap9
    
    [Network]
        Address=192.168.10.1/24
    # 手元がLANのデフォルトゲートウェイである場合、こうすればLAN上のホストもこの接続を利用できる
    IPMasquerade=yes
    
    [Route]
    Destination=<到達したいIP>  とか <サブネット/len>
    Source=192.168.10.1  # tap9@自分のipアドレス
    Gateway=192.168.10.2  # tap9@接続相手のipアドレス
    
    [Route]
     : 必要なだけ置く