ルーターの自作:さらに続き
なぜか意外とアクセスがある、ルーターの自作ネタに気をよくして、さらに書きます!
・ルーターを作ってみた
・ルーターの自作:つづき
今回は、実際にルーターはどんなことをすれば良いかを書いてみましょう。
まず、ルーターが扱うパケットは、IPパケットです。イーサーネットでのIPパケットは、
「
イーサヘッダ
IPヘッダ
データ:UDP/TCPなど
」
という感じになっています。
ルーターは2つ以上のセグメントを中継するためのものですので、最低でも2つのネットワークインターフェースを使います。あるインターフェースからパケットを受信し、宛先がインターフェースのセグメントと一致しなければ、もう片方のインターフェースから送信します。その際に、そちらのインターフェースのセグメントと同じであれば、宛先IPアドレスからMACアドレスを調べて、そのMACアドレス宛に送ります。そうでなければ次のルーター宛に送ります。
受信データも送信データもMACアドレスの情報まで必要なので、リンクレイヤーでパケット送受信しなければなりません。パケットを受信したら、ルータとして扱う対象のIPパケットかどうかを確認し、IPチェックサムを確認したり、必要であればUDP/TCPのチェックサムも確認します。IPヘッダのTTLが1だった場合にはそれ以上転送してはいけません。TTLが1だった場合は、ICMPのTime Exceededを送信元に通知します。
パケットを別のインターフェースから送出する際には、MACアドレスの書き換えが必要になります。MACアドレスはイーサヘッダにあるデータです。イーサヘッダの宛先MACアドレスを、送り先のMACアドレスに、送信元MACアドレスを、送出インターフェースのMACアドレスに書き換えます。
さらに、IPヘッダのTTLをカウントダウンします。TTLはルーターを通過するたびに1つ減算し、1だったらそれ以上転送しない、という仕組みになっています。IPヘッダを書き換えた場合、IPチェックサムを再計算して更新しておきます。
これで転送用のパケットが完成した状態になり、次の宛先に送信します。
言葉で書くと複雑そうですが、ソースにすれば大したことではありません。意外と面倒なのはこれまでにも書いたように、ARPを使って宛先IPアドレスから宛先MACアドレスを得ることです。
なお、リンクレイヤーでパケットを扱うためには、OS毎に少々やり方が異なり、
・Linux:SOCK_RAWでsocket()
・BSD:BPFを使用
・Solaris:DLPIを使用
・Windows:libpcapとかを使う?
となります。個人的に簡単なのはLinuxで、次にBSD、SolarisのDLPIは情報が少なく面倒で、Windowsは私の専門外、という感じです。
興味がわいてきた方は、是非自作してみましょう!