RAWソケットプログラミング(イーサフレーム基本編)
ソケットプログラミング
通常ソケットプログラミングにおいて、送信元MACアドレスや送信元IPアドレスの設定などはカーネルが処理を行います。しかしソケットプログラミングでは文字通り無制約で任意のパケットを作成することが可能です。
この特徴を用いてL2からL7までパケットを1バイトづつ作成してみます。普段意識しないプロトコルの詳細まで設定できるので大変勉強になります!使い方次第ではMACアドレスやIPアドレスの偽装となるため、注意してください。
イーサフレーム
イーサフレームのフォーマットとして4種類ほどあるそうですが、今回はもっとも普及しているイーサネットver2(DXI規格)を扱います。構造としては以下のようになります。
1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | DESTINATION_ADDR | | (6 bytes) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SOURCE_ADDR | | (6 bytes) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ETHER_TYPE (2 bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ~ ~ ~ payload ~ ~ ~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | CHECKSUM | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
RAWソケットでのプログラミング例
Pythonでのプログラミングは非常に簡単です。以下のようにrawSocket.sendにバイト列を直接書き込みます。非常に直観的でわかりやすいです。
ここでは送信元MACアドレスを11:11:11:11:11:11、宛先MACアドレスを22:22:22:22:22:22というイーサフレームのみのパケットを作成してみました。
#!/usr/bin/env python from socket import * rawSocket = socket(AF_PACKET, SOCK_RAW) rawSocket.bind(("eth1", 0)) class ether_flame: def __init__(self,src_mac_addr, dst_mac_addr, ethertype): self.src_mac_addr = src_mac_addr self.dst_mac_addr = dst_mac_addr self.ethertype = ethertype def string(self): return self.dst_mac_addr + self.src_mac_addr + self.ethertype SRC_MAC_ADDR = "\x11\x11\x11\x11\x11\x11" DST_MAC_ADDR = "\x22\x22\x22\x22\x22\x22" ETHER_TYPE = "\x08\x00" flame = ether_flame(SRC_MAC_ADDR, DST_MAC_ADDR, ETHER_TYPE) rawSocket.send(flame.string())
実行結果
tcpdumpコマンドでキャプチャすると、確かに設定した通りになっています。
13:47:59.002437 11:11:11:11:11:11 (oui Unknown) > 22:22:22:22:22:22 (oui Unknown), ethertype IPv4 (0x0800), length 14: IP0 [|ip]