マルチキャストプログラミング
- 1 はじめに
- 2 検証環境
- 3 マルチキャストアドレスのマッピング方法
- 4 サンプルプログラム
- 5 IGMP Join/Leaveメッセージ送信契機
- 6 マルチキャストアドレスの確認
- 7 マルチキャストパケットの送受信確認
- Z 参考図書
1 はじめに
マルチキャストパケットの送受信プログラムを作成して、次のことを確認してみます。
・マルチキャストIPv4アドレスとマルチキャストMACアドレスの関係
・IGMP Join/Leaveメッセージ送信契機
・マルチキャストアドレスの確認方法(ipコマンド)
・マルチキャストパケットのフォーマット(Wiresharkで確認)
2 検証環境
2.1 ネットワーク構成
サーバとクライアントの2台構成です。図中のeth0はNICの名前です。
192.168.122.0/24
client(eth0) ------------------------------------------(eth0) server
.181 .225
3 マルチキャストアドレスのマッピング方法
マルチキャストアドレスは、マルチキャストIPv4アドレスとマルチキャストMACアドレスがあります。マルチキャストIPv4アドレスは、以下のようにマルチキャストMACアドレスにマッピングされます。
224 10 1 1
+----------+-----------+----------+----------+
| 11100000 |0 000 1010 | 00000001 | 00000001 | マルチキャストIPv4アドレス
+----------+-----------+----------+----------+
| |
下位23ビットをそのままマッピング
| |
V V
+----------+----------+----------+-----------+----------+----------+
| 00000001 | 00000000 | 01011110 |0 000 1010 | 00000001 | 00000001 | マルチキャストMACアドレス
+----------+----------+----------+-----------+----------+----------+
01 00 5E A
|
|
0固定
4 サンプルプログラム
サーバとクライアントでそれぞれプログラムを作成します。
4.1 サーバプログラム
サーバプログラムは以下になります。サーバプログラムを実行すると、UDPの11111番ポートでパケットの受信待ちをします。また、宛先IPv4マルチキャストアドレスが239.0.0.100のパケットを受信します。
[root@server ~]# cat sv.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in addr;
struct ip_mreq mreq;
char buf[2048];
sock = socket(AF_INET, SOCK_DGRAM, 0);
addr.sin_family = AF_INET;
addr.sin_port = htons(11111);
addr.sin_addr.s_addr = INADDR_ANY;
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
memset(&mreq, 0, sizeof(mreq));
mreq.imr_interface.s_addr = inet_addr("192.168.122.225");
mreq.imr_multiaddr.s_addr = inet_addr("239.0.0.100");
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) != 0) {
perror("setsockopt");
return 1;
}
memset(buf, 0, sizeof(buf));
recv(sock, buf, sizeof(buf), 0);
printf("%s\n", buf);
close(sock);
return 0;
}サーバプログラムをコンパイルします。
[root@server ~]# gcc -Wall -o sv sv.c
4.2 クライアントプログラム
クライアントプログラムは、宛先が239.0.0.100のマルチキャストパケットを送信します。
[root@client ~]# cat cl.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in addr;
struct sockaddr_in src_addr;
in_addr_t ipaddr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(11111);
addr.sin_addr.s_addr = inet_addr("239.0.0.100");
src_addr.sin_addr.s_addr = inet_addr("192.168.122.181");
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&src_addr.sin_addr.s_addr, sizeof(ipaddr)) != 0) {
perror("setsockopt");
return 1;
}
if(sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr)) == -1){
perror("sendto");
return 1;
}
close(sock);
return 0;
}クライアントプログラムをコンパイルします。
[root@client ~]# gcc -Wall -o cl cl.c
5 IGMP Join/Leaveメッセージ送信契機
サーバプログラムを実行すると、setsockoptシステムコールが実行されます。setsockoptシステムコールを実行すると、IGMP Joinパケットが送信されます。また、サーバプログラムが終了すると、IGMP Leaveパケットが送信されます。この時、サーバで採取したWiresharkを以下に示します。なぜか、2つずつパケットが送信されています。現時点で原因はわかりません。

6 マルチキャストアドレスの確認
サーバプログラムを実行すると、インタフェースにマルチキャストMACアドレスが設定されます。ipコマンドを使うと、マルチキャストアドレスを確認することができます。
まず、サーバプログラムを実行する前のインタフェースの状態を確認します。
[root@server ~]# ip maddress show dev eth0
1: lo
inet 224.0.0.1
2: eth0
link 01:00:5e:00:00:01
link 33:33:00:00:00:01
link 33:33:ff:84:02:b1
inet 224.0.0.1
inet6 ff02::1:ff84:2b1
inet6 ff02::1
inet6 ff01::1サーバプログラムを実行します
[root@server ~]# ./sv
サーバプログラムを実行したあとのインタフェース(eth0)を確認します。マルチキャストMACアドレス01:00:5e:00:00:64(●)がインタフェースに追加されたことがわかります。このアドレスは、239.0.0.100(★)に対応したマルチキャストMACアドレスです。
[root@server ~]# ip maddress show dev eth0
1: lo
inet 224.0.0.1
2: eth0
link 01:00:5e:00:00:01
link 33:33:00:00:00:01
link 33:33:ff:84:02:b1
link 01:00:5e:00:00:64 ●
inet 239.0.0.100 ★
inet 224.0.0.1
inet6 ff02::1:ff84:2b1
inet6 ff02::1
inet6 ff01::1
7 マルチキャストパケットの送受信確認
サーバプログラムは、UDPの11111番ポートで受信パケットを待ち受けるので、11111番ポートを解放します。なお、firewall-cmdコマンドの使い方は、firewall-cmdの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# firewall-cmd --add-port=11111/udp success
ポート番号を確認します。UDPの11111番ポートが解放されたことがわかります。
[root@server ~]# firewall-cmd --list-ports 11111/udp
サーバでtcpdumpを実行します。なお、tcpdumpの使い方は、tcpdumpの使い方(基本編) - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# tcpdump -i eth0 port 11111 or igmp -w igmp.pcap
サーバプログラムを実行します。
[root@server ~]# ./sv
サーバプログラムが受信パケットを待ち受けているポートを確認します。UDPの11111番ポートで受信パケットを待ち受けていることがわかります。なお、lsofコマンドの使い方は、lsofコマンドの使い方 - hana_shinのLinux技術ブログを参照してください。
[root@server ~]# lsof -c sv -a -i -a -nP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME sv 1886 root 3u IPv4 23521 0t0 UDP *:11111
クライアントプログラムを実行します。
[root@client ~]# ./cl [root@client ~]#
クライアントプログラムが送信した文字列(HELLO)がサーバプログラムで受信できたことがわかります。
[root@server ~]# ./sv HELLO [root@server ~]#
Ctrl+Cを押下してtcpdumpを終了します。
[root@server ~]# tcpdump -i eth0 port 11111 or igmp -w igmp1.pcap tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes ^C5 packets captured 5 packets received by filter 0 packets dropped by kernel
サーバで採取したtcpdumpを確認します。クライアントプログラムが送信したマルチキャストパケットの宛先IPアドレスは239.0.0.100であることがわかります。また、その時の宛先マルチキャストMACアドレスは、01:00:5e:00:00:64であることがわかります。01:00:5e:00:00:64は、サーバプログラムがNICに設定したマルチキャストMACアドレスになります。

Z 参考図書
私が業務や記事執筆で参考にした書籍を以下のページに記載します。
Linux技術のスキルアップをしよう! - hana_shinのLinux技術ブログ

