SWEet

A Software Engineer Is Eating Technologies

Vagrantで仮想的なWANみたいなのを作る

研究の検証用環境として以下のような環境をVMのみで一つのホストPC上に構築したかった. Vagrantで一応できたので手順とかをメモしておく.

f:id:kk_river108:20190502181820p:plain

ストーリー

それぞれ 192.168.10.100 (Node A) と 172.168.10.100 (Node B) のVMはネットワークのセグメントが異なるので直接アクセスできない. Node AがNode Bにアクセスしたい場合はNode BのGlobal IPを指定してアクセスするようにさせる.

Node Aは100.100.100.100にNATで変換され,Node Bは100.100.100.200に変更されるとする.

Node AがNode BのGlobal IPである100.100.100.200にパケットを投げるとデフォルトゲートウェイを介してRouter VMに届き,Router VMiptablesを用いてパケットの送信元,宛先IPを変換することでNode Bにパケットを転送したい.

Vagrantfile

まず各VMの設定をVagrantfileに書いておく

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://vagrantcloud.com/search.
  config.vm.box = "bento/ubuntu-18.04"

  # Network A
  config.vm.define :proxyA do |proxyA|
      proxyA.vm.hostname = "proxyA"
      proxyA.vm.network :private_network, ip: "192.168.10.100", virtual__intnet: "intnetA"
  end

  config.vm.define :peerA do |peerA|
      peerA.vm.hostname = "peerA"
      peerA.vm.network :private_network, ip: "192.168.10.101", virtual__intnet: "intnetA"
  end

  # Internal router
  config.vm.define "router" do |router|
    router.vm.hostname = "router"
    router.vm.network :private_network, ip: "192.168.10.10", virtua__intnet: "intnetA"
    router.vm.network :private_network, ip: "172.168.10.10", virtua__intnet: "intnetB"
  end  
  
  # Network B
  config.vm.define :proxyB do |proxyB|
      proxyB.vm.hostname = "proxyB"
      proxyB.vm.network :private_network, ip: "172.168.10.100", virtual__intnet: "intnetB"
  end

  config.vm.define :peerB do |peerB|
      peerB.vm.hostname = "peerB"
      peerB.vm.network :private_network, ip: "172.168.10.101", virtual__intnet: "intnetB"
  end
  
end

名前は変わっているが Proxy A, Proxy BがそれぞれNode A, Node Bにあたる. 今回はPeer* のマシンは関係ないので無視

各Nodeでデフォルトゲートウェイを設定

VMを立ち上げたら vagrant ssh で各NodeのVMにログインしてデフォルトゲートウェイを設定しておく

# Node A
sudo route add default gw 192.168.10.10 dev eth1

# Node B
sudo route add default gw 172.168.10.10 dev eth1

各NodeのVMには上記のVagrantfileで割り当てた静的なIPがeth1に割り当てられているはずなのでそれに合わせてデフォルトゲートウェイを設定する 設定した後に 各NodeのVMから ping 100.100.100.200 のような存在しない,アクセスできないはずのアドレスにpingを打ち,

Router側で sudo tcpdump -i any icmp と叩くことで各VMからのpingを観測できるはず

Router VM上でiptablesを設定する

まずパケットの転送を許可する設定を行う

vi /etc/sysctl.conf

でファイルを開き

#net.ipv4.ip_forward=1

コメントアウトを外す. その後に sudo sysctl -p で有効化する.これでVMを再起動してもパケットの転送設定はOnのまま

次に iptables に変換テーブルを追加する

sudo iptables -t nat -A PREROUTING -d 100.100.100.200 -i eth1 -j DNAT --to-destination 172.168.10.100
sudo iptables -t nat -A POSTROUTING -o eth1 -s 192.168.10.100  -j MASQUERADE
sudo iptables -t nat -A PREROUTING -d 100.100.100.100 -i eth2 -j DNAT --to-destination 192.168.10.100
sudo iptables -t nat -A POSTROUTING -o eth2 -s 172.168.10.100  -j MASQUERADE

1行目はeth1に流れてくる100.100.100.200が宛先となっているパケットを172.168.10.100に変換する. 2行目はNode Aへの返信のパケットを逆変換して届けるための設定 3, 4行目はそれぞれNode Bからのパケット用に書き換えたもの.

これで上記の図のパケット転送がうまくいくはず