EC2-VPCでIPマルチキャスト/ブロードキャストを実現する(後編)
少し期間が開いてしまいましたが、前編では、クラウド上でのIPマルチキャスト/ブロードキャストを取り巻く現状と、ワークアラウンドについて考えてきました。
今回の後編では、実際にワークアラウンドを試して、EC2上でマルチキャスト/ブロードキャストで通信してみましょう。
環境
今回は下記の構成で検証します。
送信元:Amazon Linux 2014.3 (64bit)
# ifconfig eth0 Link encap:Ethernet HWaddr 06:A7:CE:8A:4F:13 inet addr:172.31.4.93 Bcast:172.31.15.255 Mask:255.255.240.0 inet6 addr: fe80::4a7:ceff:fe8a:4f13/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:4856911 errors:0 dropped:0 overruns:0 frame:0 TX packets:4546714 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:776876067 (740.8 MiB) TX bytes:728166952 (694.4 MiB) Interrupt:26
宛先A:Amazon Linux 2014.3 (64bit)
# ifconfig eth0 Link encap:Ethernet HWaddr 06:01:B8:62:20:C0 inet addr:172.31.3.135 Bcast:172.31.15.255 Mask:255.255.240.0 inet6 addr: fe80::401:b8ff:fe62:20c0/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:83196 errors:0 dropped:0 overruns:0 frame:0 TX packets:55395 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:97004828 (92.5 MiB) TX bytes:7290779 (6.9 MiB) Interrupt:26
宛先B:Amazon Linux 2014.3 (64bit)
# ifconfig eth0 Link encap:Ethernet HWaddr 06:52:D3:DC:8A:4A inet addr:172.31.4.105 Bcast:172.31.15.255 Mask:255.255.240.0 inet6 addr: fe80::452:d3ff:fedc:8a4a/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:19285 errors:0 dropped:0 overruns:0 frame:0 TX packets:11453 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:27533244 (26.2 MiB) TX bytes:775892 (757.7 KiB) Interrupt:26
セットアップ
あらかじめ、送信元インスタンス、宛先インスタンスの間のICMPをセキュリティグループで許可しておきます。
宛先インスタンスのセットアップ
宛先インスタンスをセットアップします。
マネジメントコンソールやAPIから、宛先インスタンスのSource/Dest. CheckをDisabledにします。
Amazon LinuxはデフォルトでIPのブロードキャストアドレスに対するICMPに応答しない設定となっているので、宛先インスタンスがICMPに応答できるように設定変更します。
echo "0" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
送信元インスタンスのセットアップ
次に、送信元インスタンスをセットアップしていきます。
今回作成するスクリプトにはlibpcap-develが必要となるので、あらかじめインストールしておきます。
ちなみに、libpcapはAmazon Linuxにはデフォルトで入っています。
yum install libpcap-devel
Rubyをインストールします。
今回はRVMを使うので、まずRVMをインストール。
\curl -sSL https://get.rvm.io | bash
.bash_profileを編集してRVMを読み込むようにします。
vim ~/.bash_profile
下記を追記します。
[ -s ${HOME}/.rvm/scripts/rvm ] && source ${HOME}/.rvm/scripts/rvm
初回は手で読ませます。
source ~/.bash_profile
後述のPacketFuはRuby 2.0以降に対応していないため、Ruby 1.9をインストールします。
rvm install ruby-1.9.3-p484 rvm use ruby-1.9.3-p484
pcaprub, packetfuをインストールします。
gem install pcaprub gem install packetfu
これで送信元インスタンス、宛先インスタンスの準備ができました。
ソースコード
送信元インスタンスでパケットをキャプチャし、イーサネットフレームの宛先MACアドレスのI/Gビットが1の場合にUnicastに書き換えます。
スクリプト自体は、@thekentiest さんのソースコードを流用させていただきます。
#!/usr/bin/ruby require 'rubygems' require 'packetfu' dev = ARGV[0] mac=`ip link show #{dev} | awk '/ether/ {print $2}'`.chomp ARGV.shift dests = ARGV cap = PacketFu::Capture.new( :timeout => 4000, :iface => dev, :start => true, :filter => "ether src #{mac} and ether[0] & 1 = 1") loop do cap.stream.each do |pkt| frame = PacketFu::IPPacket.parse(pkt) i = 0 dests.each do |dest| frame.eth_daddr = dest frame.ip_header.ip_id = frame.ip_header.ip_id + i frame.ip_header.ip_sum = frame.ip_header.ip_calc_sum() frame.to_w(dev) i = i + 1 end end end
動作確認(IPブロードキャスト)
まずはIPブロードキャストを試してみます。
そのまま試した場合
何も仕込まない状態でEC2上でのIPブロードキャストが通らないことを確認します。
#ping -b 172.31.15.255 WARNING: pinging broadcast address PING 172.31.15.255 (172.31.15.255) 56(84) bytes of data. ^C --- 172.31.15.255 ping statistics --- 7 packets transmitted, 0 received, 100% packet loss, time 6788ms
通りません。
Multi-unicastingを使用した場合
送信元インスタンスで、上記のソースコードを動作させます。
ruby mcast.rb eth0 06:01:b8:62:20:c0 06:52:d3:dc:8a:4a
では、IPのブロードキャストアドレスである172.31.15.255に対してpingを実行してみます。
# ping -b 172.31.15.255 WARNING: pinging broadcast address PING 172.31.15.255 (172.31.15.255) 56(84) bytes of data. 64 bytes from 172.31.3.135: icmp_seq=1 ttl=64 time=112 ms 64 bytes from 172.31.4.105: icmp_seq=1 ttl=64 time=114 ms (DUP!) 64 bytes from 172.31.3.135: icmp_seq=2 ttl=64 time=5.55 ms 64 bytes from 172.31.4.105: icmp_seq=2 ttl=64 time=8.03 ms (DUP!) 64 bytes from 172.31.3.135: icmp_seq=3 ttl=64 time=4.37 ms 64 bytes from 172.31.4.105: icmp_seq=3 ttl=64 time=122 ms (DUP!) 64 bytes from 172.31.3.135: icmp_seq=4 ttl=64 time=3.20 ms 64 bytes from 172.31.4.105: icmp_seq=4 ttl=64 time=7.19 ms (DUP!) 64 bytes from 172.31.3.135: icmp_seq=5 ttl=64 time=4.19 ms 64 bytes from 172.31.4.105: icmp_seq=5 ttl=64 time=7.83 ms (DUP!) ^C --- 172.31.15.255 ping statistics --- 5 packets transmitted, 5 received, +5 duplicates, 0% packet loss, time 4911ms rtt min/avg/max/mdev = 3.201/39.026/122.603/50.877 ms
通りました。
動作確認(IPマルチキャスト)
次にIPマルチキャストを試してみます。
マルチキャストの送受信用のスクリプトには、下記のソースコードを流用します。
UDPでマルチキャストを使う(マルチキャストを送信する) – Geekなページ
UDPでマルチキャストを使う(マルチキャストを受信する) – Geekなページ
そのまま試した場合
何も仕込まない状態でEC2上でのIPブロードキャストが通らないことを確認します。
宛先インスタンス側で、マルチキャスト受信用スクリプトを動作させておきます。
このスクリプトは、マルチキャストパケットを受信すると、受信したメッセージを標準出力に出力して終了します。
ruby ./mcast_recv.rb
上記のスクリプトを動かした状態で netstat -g を実行すると、マルチキャストグループ(239.192.1.2)に所属できていることがわかります。
# netstat -g IPv6/IPv4 Group Memberships Interface RefCnt Group --------------- ------ --------------------- lo 1 all-systems.mcast.net eth0 1 239.192.1.2 eth0 1 all-systems.mcast.net lo 1 ff02::1 lo 1 ff01::1 eth0 1 ff02::1:ffdc:8a4a eth0 1 ff02::1 eth0 1 ff01::1
では、送信元インスタンスから、マルチキャスト送信用スクリプトを実行させます。
ruby ./mcast_send.rb
宛先インスタンス側で、スクリプトが何も出力しておらず、終了していません。
これは、マルチキャストパケットを受信できていないことを意味しています。
Multi-unicastingを使用した場合
IPブロードキャストのときと同様、送信元インスタンスで、上記のソースコードを動作させます。
ruby mcast.rb eth0 06:01:b8:62:20:c0 06:52:d3:dc:8a:4a
宛先インスタンス側で、マルチキャスト受信用スクリプトを動作させておきます。
ruby ./mcast_recv.rb
では、送信元インスタンスから、マルチキャスト送信用スクリプトを実行させます。
ruby ./mcast_send.rb
宛先インスタンスのコンソールを見ると、”Hello”と出力されています。
"HELLO"
以上の通り、IPマルチキャストのパケットが宛先インスタンスに到達したことを確認できました。
おわりに
今回、前編・後編の2回に分けて、EC2-VPCでのマルチキャスト/ブロードキャストを考えてきました。
マルチキャストがサポートされていないEC2-VPCでも、ユースケースによってはこれらのワークアラウンドが使えるかと思います。
トラックバックはまだありません。