【Ruby】IP over UDPトンネリングを実現する

2 min read読了の目安(約2300字

はじめに

以下を目的にRubyで簡単なIP over UDPトンネリングを実装してみました。

  • トンネリングの仕組みの理解を深めること
  • Rubyのネットワークプログラミングの練習

トンネリングの仕組みは事前に参考(4)(5)等で調べましたので、本記事では仕組みの概要の記載は省略します。

実装の難しかったポイントとして、RubyではTUN/TAPデバイスの取り扱いがなかなか難しそうだったので(Cの既存の構造体をRubyでは文字列で扱う必要があるところや、それら関連のデバッグ等。ただし参考(1)の通りRubyだけで似たようなことを実現している方もいるようなので不可能ではない)、その部分は参考(3)のツールを利用させてもらいました。このツールでも低レイヤ周りの処理はNative Extensionとして実装しているようです。

色々試していたら以下のコードでとりあえず動いたので、一旦記事にまとめます。
IOに関する処理(read と read_nonblock の違いや、それらとTUNデバイスを使う時の影響とか)がイマイチ理解しきれていないので今後の課題としています。

コード

以下のコードを実行すると、TUNデバイスが作成&アドレス付与&アップされ、実NWインターフェースで、UDP/9876でリッスンされます。TUNデバイスにBINDするアプリケーションを実行することで、そのアプリケーションをトンネルの先に配置できます。

トンネリングの仕組みは参考(5)に記載しています。
下記コードは参考(2)にも記載しています。

rb_simpletun.rb
require "socket"
require "rb_tuntap"

PEER = "[IP Address of PEER]"
PORT = 9876

tun = RbTunTap::TunDevice.new("tun0")
tun.open(false)
tun.addr = "192.168.0.1" # or 192.168.0.2, ノードでかぶらないようにする
tun.netmask = "255.255.255.0"
tun.up
tun_io = tun.to_io

sock = UDPSocket.open
sock.bind("0.0.0.0", 9876)
peer = Socket.pack_sockaddr_in(PORT, PEER)

while true
  ret = IO::select([sock, tun_io])
  ret[0].each do |d|
    if d == tun_io
      # TUNデバイスで受信した場合
      data = tun_io.sysread(65535)
      sock.send(data, 0, peer)
    else
      # 実NWで受信した場合
      data = sock.recv(65535)
      tun_io.syswrite(data)
    end
  end
end

実行手順

トンネルの先のアプリケーションとしてWebサーバ(Webrick)を用いる場合。
事前に rb_tuntap をインストールしておきます。

サーバ側

% sudo ruby rb_simpletun.rb
[別のターミナル]
% sudo ruby -rwebrick -e 'WEBrick::HTTPServer.new(:DocumentRoot => "./", :Port => 80, :BindAddress => "192.168.0.1").start'

クライアント側

% sudo ruby rb_simpletun.rb
% wget 192.168.0.1

パケットキャプチャ

WireSharkで実NWインターフェースとトンネルインターフェースでキャプチャしました。

実NWインターフェース

実NWインターフェースから見るとUDPパケットですが、データ部にHTTPのデータのようなものが乗っかっているのが分かります。

トンネルインターフェース

トンネルインターフェースでは素のHTTPのみが見えています。

参考

(1)

http://syuu1228.hatenablog.com/entry/20140322/1395442800

(2)

https://gist.github.com/kuredev/077244b441d4c5be5194fcae3920260d

(3)

https://github.com/amoghe/rb_tuntap

(4)

https://github.com/gregnietsky/simpletun

参考(自分の過去記事)

(5)

https://qiita.com/kure/items/d8fe5de2348532cc7604

(6)

https://kure.hatenablog.jp/entry/2021/05/31/123841