🐋

Podman のネットワークから外に出たい ~プライマリ→セカンダリへの通信~

2024/10/24に公開

背景

Podman や Docker 内にサブネット設定ありの network を作成し、組み込み機器達のテスト環境があるとします。

その中から一つだけ、実際に物理的に外にある機器にしたい場合、どうすれば簡単にできるでしょうか?という問題にぶち当たりました。

以下の図の状態です。

今回はセカンダリ機器だけを物理的なデバイスにして外に出る場合です。

Netfilter でアドレスのエイリアスを張る

面倒くさいのは、内部のネットワークを 192.168.1.0/24 で繋いでいるため、外部にある本物の機器D (仮に 192.168.1.3) につなげることが出来ない点です。

特権を持っているコンテナの場合は ip route add などの設定で 192.168.1.3 だけルーティングを変えられる場合もありますが、今回は Podman のルートレス環境で行っており、それも難しいとします。

というわけで、まずはホスト側の Netfilter で 192.168.100.3 への通信を 192.168.1.3 への通信だとみなし、宛先を書き換えてしまいます。

sudo iptables -t nat -A OUTPUT -p tcp -d 192.168.100.3 -j DNAT --to-destination 192.168.1.3
sudo iptables -t nat -A OUTPUT -p udp -d 192.168.100.3 -j DNAT --to-destination 192.168.1.3

こうすることで、podman network (デフォルト設定のブリッジ) などをコンテナに繋いでおけば、 192.168.100.3 で Aコンテナは 機器D に接続できることになります。

※ 画像を小さくするために コンテナ Bは省略

192.168.1.3 を無理やり 192.168.100.3 に書き換える

Netfilter の OUTPUT で DNAT によりアドレスを書き換えることで 192.168.1.0/24 のサブネットの外側にエイリアスを張りました。これにより、コンテナA は機器 D に接続できるようになりました。

しかし、接続するには 192.168.1.3 を 192.168.100.3 にしなくてはいけません。そんなん、できるわけないですね。

192.168.1.3 を 192.168.1.3 のままに、かつ、Netfilter とか特権が必要なものは無しに 192.168.100.3 に書き換える手段はないでしょうか?

というわけで、Netfilter よりも前、connect の呼び出し前に無理やり書き換えてしまいます。

redirect.c
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <dlfcn.h>
#include <netinet/in.h>
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
  typedef int (*fun)(int, const struct sockaddr *, socklen_t);
  fun real_connect = dlsym(RTLD_NEXT, "connect");

  if (addr->sa_family == AF_INET &&
      ((struct sockaddr_in *)addr)->sin_addr.s_addr == inet_addr("192.168.1.3")) {
        ((struct sockaddr_in *)addr)->sin_addr.s_addr = inet_addr("192.168.100.3");
  }
  return real_connect(sockfd, addr, addrlen);
}

これを以下の様にコンテナ内でビルドし、 export PRE_LOAD=/redirect.so とすることで、 connect の呼び出しに割り込んで 192.168.100.3 に無理やり書き換えてしまいます。

gcc -shared -fPIC redirect.c -o /redirect.so -ldl
export PRE_LOAD=/redirect.so

まとめ

今回は Netfilter でアドレスにエイリアスを張り、ついでに PRE_LOADconnect を変更することでコンテナ内からはあたかもアドレスを変えずにコンテナ A から機器 D にアクセスする方法について考えました。

ただし、この方法はA→Dへのアクセスについてのみの方法です。

D→A と外側の機器が能動的にコンテナにアクセスしたい場合、しかもアドレスは変えたくない場合………はまだどうしようか考え中。

誰かいい方法あったら教えてください。

Discussion