1-1.Packet、アドレスの定義
今回は、本誌で出てきたPacketとアドレスを、WebAssembly化していきます。
- イーサネットフレーム
- MACアドレス
- IPv4アドレス
- IPv6アドレス
- ARP Packet
がありましたね。これらを順番にRustでWebAssembly化していきましょう。
イーサーネットフレーム
まずは、「イーサーネットフレーム」からみていきましょう。 イーサネットフレームのPacketの形はこういう形でした。
イーサーネットフレームは、一番最下層にある基本のPacket構造になります。
本誌vol.1では詳細に解説していますが、簡単にここでもご紹介しておきます。 実はネットワークを流れるPacketの「どこから」「どこへ」というのはMACアドレスで指定するきまりになっています。 宛先MACアドレスと送信元MACアドレスがこの部分にあたります。
「Type」は、ネットワーク機器がフレームを受信したときに、そのDataをどのように解釈し、 「どの上位層プロトコルに渡すべきか」を決定するために使用されます。 例えば、IPv4でウェブブラウジングの場合、典型的なイーサネットフレームは以下のような構成になります。
Ether Type: 0x0800 (IPv4)
Data: IPv4ヘッダ + TCPヘッダ + HTTPヘッダー + HTTPデータ
「Data」の部分に、上位層から送られてきたPacketが入っています。このような感じで入っています。
上位層という言葉が出てきましたが、ネットワークにデータを送り出すには、幾つもの階層があり、それぞれの階層でそれぞれの処理がされて、送り出されています。送り出す時は下にくだっていき、電気信号になって、イーサーネットケーブルの中を流れていきます。電気信号を受けた側では、逆に階層を上に、あがっていきながら、各層で処理されて、最終的にデータとして取り出されます。大事なデータはどんどん包装されて、箱に入れられて送られるというイメージですね。
このようにしてデータが作られて、「イーサーネットフレーム」としてネットワークの中をPacketは流れていきます。
データリンク層(Layer 2)では、「宛先MACアドレス〜FCS」のフィールド構成になっています。 物理層(Layer 1)で、イーサーネットコントローラーがプリアンブルとSFDをつけて0,1の電気信号に変換してネットワークに送り出されます。 「プリアンブル」とは、ネットワーク上に実際にデータを送り出す際に、「これから送り出すよー」と合図を出すための信号を作り出しているもの。 「SFD」はここからデータがはじまりますよ。という合図のようなフィールドです。
ここの部分については、本誌P.102~P.103で詳細に書かれていますので参照してください。
今回、この内容に基づいて、データリンク層(L2)でのイーサネットフレームと物理層(L1)でのイーサーネットフレームを明確に分けて、EthernetFrame
とPhysicalLayerFrame
という名前をつけて定義してみました。
// データリンク層のイーサネットフレームの定義(Layer 2)
pub struct EthernetFrame {
pub dst_mac: [u8; 6], // 宛先MACアドレス (6バイト)
pub src_mac: [u8; 6], // 送信元MACアドレス (6バイト)
pub ethertype: u16, // イーサータイプ (2バイト)
pub data: Vec<u8>, // データリンク層のペイロード
}
// 物理層のイーサネットフレームの定義(Layer 1)
pub struct PhysicalLayerFrame {
pub preamble: [u8; 7], // プリアンブル (7バイト)
pub sfd: u8, // スタートフレームデリミタ (1バイト)
pub ethernet_frame: EthernetFrame, // データリンク層のイーサネットフレーム
}
これで、物理層(L1)で、プリアンブルとSFDをつけて、ビット列にして、信号化してイーサーネットケーブルに流す。 という一連の処理をあらわせると思ったからです。
アドレス
アドレスも階層ごとに決められた表現があります。
- 「データリンク層(L2)のアドレス」 MACアドレス ・6バイトで表現するデータリンク層のアドレス
- 「ネットワーク層(L3)のアドレス」 IPv4アドレス ・4バイトで表現するネットワーク層のアドレス。Version4。 IPv6アドレス ・16バイトで表現するネットワーク層のアドレス。Version6。
これをRustで表現すると、
pub struct MacAddress(pub [u8; 6]);
pub struct IPv4Address(pub [u8; 4]);
pub struct IPv6Address(pub [u8; 16]);
このようになります。
そういえば、イーサーネットフレームでも、MACアドレス使っていましたね。
[u8; 6]
という風に表現されていましたが、これをMacAddress
という形で定義し直してみます。
// データリンク層のイーサネットフレームの定義(Layer 2)
pub struct EthernetFrame {
pub dst_mac: MacAddress, // 宛先MACアドレス (6バイト)
pub src_mac: MacAddress, // 送信元MACアドレス (6バイト)
pub ethertype: u16, // イーサータイプ (2バイト)
pub data: Vec<u8>, // データリンク層のペイロード
}
ARPのパケット
さて最後に、ARPのPacketを定義してみましょう。
ARPのPacketは、こういう構造になっていました。
それぞれのフィールドは、
- ハードウェアタイプ
・1=Ethernet - プロトコルタイプ
・0x0800=IPv4 ・0x0806=ARP - ハードウェアアドレス長(バイト単位)
・通常、MACアドレスになるので「6」 - プロトコルアドレス長(バイト単位)
・通常、IPv4アドレスになるので「4」 - Operation Code
・1=ARP-request(問い合わせ)
・2=ARP-reply(応答) - 送信元のハードウェアアドレス
・データリンク層のアドレス。通常はMACアドレス - 送信元のプロトコルアドレス
・ネットワーク層のアドレス。通常はIPv4アドレス - 宛先のハードウェアアドレス
・ARP-requestの場合は全て「0」
・ARP-replyの場合は実際の「MACアドレス」 - 宛先のプロトコルアドレス
・問い合わせ対象のIPアドレス
長いですが、1個ずつ忘れずに定義していきましょう。
pub struct ARPPacket {
pub hardware_type: u16,
pub protocol_type: u16,
pub hardware_addr_len: u8,
pub protocol_addr_len: u8,
pub operation: u16,
pub sender_hardware_addr: MacAddress,
pub sender_protocol_addr: [u8; 4],
pub target_hardware_addr: MacAddress,
pub target_protocol_addr: [u8; 4],
}
このPacketが、イーサーネットフレームの「Data」フィールドにスポッと入ります。
ARPパケットは28バイトしかありません。でもイーサーネットフレームのデーターフィールドは、最小が46バイトと決められていますので、足りない分46-28=18バイトは0で埋められて、ネットワークに送り出されます。
これで、全ての構造体の定義が終わりました。 でも、これだけでは、つまらないので、次は、WebAssembly化するにあたり、各構造体の定義だけではなく、Javascript側で、確認のために、それぞれ今どういうデータ内容になっているか?が見えるような機構にしていこうと思います。
その前に、この辺りのネットワークのこと、Packet、アドレスのことについてわからないことがある場合は、本誌Vol.1で復習しておいてくだださい。
ネットワークを流れるPacketをプログラムから操作できるようになりたいという人には必見のマガジンです。