猫型エンジニアのブログ

プログラム/ネットワーク系の技術関連をまとめたページです 

Ryuのソースコードリーディング その2 パケットの解析

Packetクラス

 packet.pyのソースコードを読むと以下のことがわかります。

  1. パケットクラスは、パケットのデコード/エンコードを行う
  2. パケットクラスは、バイナリデータを引数に持つ
  3. インスタンスは、protocolsというリストがあり、リストの各要素はプロトコルインスタンス 

 そこで、ここでは以下の2つに挑戦してみます。

  1. バイナリデータからパケットのデコード
  2. パケットを作成してエンコード 

バイナリデータからパケットのデコード

 バイナリデータは、Wiresharkでキャプチャした以下のTCPのSYNパケットを用いました。

f:id:alexei-karamazov:20131223231115p:plain

 以下が、SYNパケットのバイナリ(実際には文字列)になります。

08002745b4a308002700187a080045000030239e40008006e50dc0a83865c0
a83866ed6d00162a94e8ad0000000070022000703d0000020405b401010402

 上の文字列(str)を一度バイナリ(bin)に変換してから、Packetクラスを作成しました。その後クラスメソッドのget_protocolを用いて、イーサフレーム(pkt_eth)とipv4(pkt_ip)とtcp(pkt_tcp)のヘッダを取り出しました。確かにデコードされた結果、Wiresharkの値と同じものが表示されていることがわかります。

>>> from ryu.lib.packet import *
>>> import binascii

>>> str = "08002745b4a308002700187a080045000030239e40008006e50dc0a83865c0a83866ed6d00162a94e8ad0000000070022000703d0000020405b401010402"
>>> bin = binascii.a2b_hex(str)
>>> bin
"\x08\x00'E\xb4\xa3\x08\x00'\x00\x18z\x08\x00E\x00\x000#\x9e@\x00\x80\x06\xe5\r\xc0\xa88e\xc0\xa88f\xedm\x00\x16*\x94\xe8\xad\x00\x00\x00\x00p\x02 \x00p=\x00\x00\x02\x04\x05\xb4\x01\x01\x04\x02"

>>> pkt = packet.Packet(data=bin)
>>> pkt
ethernet(dst='08:00:27:45:b4:a3',ethertype=2048,src='08:00:27:00:18:7a'), ipv4(csum=58637,dst='192.168.56.102',flags=2,header_length=5,identification=9118,offset=0,option=None,proto=6,src='192.168.56.101',tos=0,total_length=48,ttl=128,version=4), tcp(ack=0,bits=2,csum=28733,dst_port=22,offset=7,option='\x02\x04\x05\xb4\x01\x01\x04\x02',seq=714401965,src_port=60781,urgent=0,window_size=8192)

>>> pkt_eth = pkt.get_protocol(ethernet.ethernet)
>>> pkt_eth
ethernet(dst='08:00:27:45:b4:a3',ethertype=2048,src='08:00:27:00:18:7a')

>>> pkt_ip = pkt.get_protocol(ipv4.ipv4)
>>> pkt_ip
ipv4(csum=58637,dst='192.168.56.102',flags=2,header_length=5,identification=9118,offset=0,option=None,proto=6,src='192.168.56.101',tos=0,total_length=48,ttl=128,version=4)

>>> pkt_tcp = pkt.get_protocol(tcp.tcp)
>>> pkt_tcp
tcp(ack=0,bits=2,csum=28733,dst_port=22,offset=7,option='\x02\x04\x05\xb4\x01\x01\x04\x02',seq=714401965,src_port=60781,urgent=0,window_size=8192)

 以下の結果からパケットクラスの__init__の処理により、リストのprotocolsにプロトコルのヘッダがあり、文字列のdataに引数のバイナリがあることが確認できます。

>>> pkt.protocols
[ethernet(dst='08:00:27:45:b4:a3',ethertype=2048,src='08:00:27:00:18:7a'), ipv4(csum=58637,dst='192.168.56.102',flags=2,header_length=5,identification=9118,offset=0,option=None,proto=6,src='192.168.56.101',tos=0,total_length=48,ttl=128,version=4), tcp(ack=0,bits=2,csum=28733,dst_port=22,offset=7,option='\x02\x04\x05\xb4\x01\x01\x04\x02',seq=714401965,src_port=60781,urgent=0,window_size=8192)]
>>> type(pkt.protocols)
<type 'list'>

>>> pkt.data
"\x08\x00'E\xb4\xa3\x08\x00'\x00\x18z\x08\x00E\x00\x000#\x9e@\x00\x80\x06\xe5\r\xc0\xa88e\xc0\xa88f\xedm\x00\x16*\x94\xe8\xad\x00\x00\x00\x00p\x02 \x00p=\x00\x00\x02\x04\x05\xb4\x01\x01\x04\x02"
>>> type(pkt.data)
<type 'str'>