2016-12-20 2 views
0

OpenFlow 1.3を使用してDHCPパケットを解析するMininetでOpen vSwitchを使用するRyu SDNコントローラを使用しています。オンラインの例とRyuのリソースに従って、DHCPパケットパーサーを実装しました。しかし、私はそれが期待されたように動作しません、なぜ私の最初の解決策が機能しないのか誰かが洞察力を持っているのだろうか?Ryuのget_protocol(dhcp.dhcp)でDHCPパケットを解析できません

DHCPパケットを解析するためのコードスニペットの例は以下の通りです:

from ryu.lib.packet import dhcp 
... 
... 
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 
def _packet_in_handler(self, ev): 
    msg = ev.msg 
    datapath = msg.datapath 
    pkt = packet.Packet(msg.data) 
    dhcpPacket = pkt.get_protocol(dhcp.dhcp) 

私のコードは、同様の静脈を、次のとおりです。私はこの正確な配列を、次の午前として

from ryu.lib.packet import dhcp 
... 
... 
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) 
def _packet_in_handler(self, ev): 
    pkt = {} 
    pkt['msg'] = ev.msg 
    pkt['dp'] = pkt['msg'].datapath 
    pkt['pkt'] = packet.Packet(pkt['msg'].data) 
    pkt['dhcp'] = pkt['pkt'].get_protocol(dhcp.dhcp) 

これは合理的なようですARP、ICMP、IPなどの他のプロトコル。以下の例。

pkt['arp'] = pkt['pkt'].get_protocol(arp.arp) 
pkt['ip'] = pkt['pkt'].get_protocol(ipv4.ipv4) 
pkt['icmp'] = pkt['pkt'].get_protocol(icmp.icmp) 

唯一の問題は、DHCPのためGET_PROTOCOLが一貫Noneを返しながら、私は上記のリスト3つのパーサーは、実際に、データを返すということです。私はすでに私のスイッチを通してDHCPパケットを送信することでこれをテストしました。

以下は、3つ以上の値を持つパケットリストを識別するコードスニペットです。インデックス3の値を保存し、それを私のDHCPパケットとして設定します。 DHCPパケットでは、私は、私が興味のデータが含まれているインデックス2で文字列を解析の濃縮

# pkt['dhcp'] = pkt['pkt'].get_protocol(dhcp.dhcp) 
# Check if pkt['pkt]] > 3 elements, if so, parse DHCP string 
#Standard pkt['dhcp'] = (None, None, String) 
if len(pkt['pkt']) > 3: 
    pkt['dhcp'] = dhcp.dhcp.parser(pkt['pkt'][3]) 
    pkt['op'] = hex(ord(dhcp_p[2][0])) 
    pkt['htype'] = hex(ord(dhcp_p[2][1])) 
    pkt['hlen'] = hex(ord(dhcp_p[2][2])) 
    pkt['hops'] = hex(ord(dhcp_p[2][3])) 

    def parseDHCP(pkt_d,start,stop): 
     s_value = '' 
     stop += 1 
     for val in range(start,stop): 
     s_value += str(hex(ord(pkt_d[val]))) 
     return s_value 

    pkt['xid'] = parseDHCP(dhcp_p[2],4,7) 
    pkt['secs'] = parseDHCP(dhcp_p[2],8,9) 
    pkt['flags'] = parseDHCP(dhcp_p[2],10,11) 
    pkt['ciaddr'] = parseDHCP(dhcp_p[2],12,15) 
    pkt['yiaddr'] = parseDHCP(dhcp_p[2],16,19) 
    pkt['siaddr'] = parseDHCP(dhcp_p[2],20,23) 
    pkt['giaddr'] = parseDHCP(dhcp_p[2],24,27) 
    pkt['chaddr'] = parseDHCP(dhcp_p[2],28,33) 
    pkt['pad'] = parseDHCP(dhcp_p[2],34,43) 

これらの値のうち印刷がそうのようになります。

0x1 
0x1 
0x6 
0x0 
0x440x30x980x11 
0x00x0 
0x00x0 
0x00x00x00x0 
0x00x00x00x0 
0x00x00x00x0 
0x00x00x00x0 
0x7e0x1d0xcc0xe70xee0x4f 
0x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x0 

上記のコードはDHCPパケットの内容を見ることができますが、pkt ['pkt']。get_protocol(dhcp.dhcp)メソッドを使って同様の結果が得られないのはなぜですか?

答えて

0

わかりました。問題が見つかりました。 dhcp.pyの200〜218行目にtry except文があります。私はそれをスローし、私はこの取得エラー参照しようと外にcls._parserを引っ張っ:だから

Ryuretic_coupler: Exception occurred during handler processing. Backtrace  
from offending handler [initial_event] servicing event [EventOFPPacketIn] follows. 
Traceback (most recent call last): 
    File "/home/ubuntu/ryu/ryu/base/app_manager.py", line 290, in _event_loop 
    handler(ev) 
    File "/home/ubuntu/ryu/ryu/app/Ryuretic/Ryuretic.py", line 72, in initial_event 
    pkt = parsPkt.handle_pkt(ev) 
    File "/home/ubuntu/ryu/ryu/app/Ryuretic/Pkt_Parse13.py", line 81, in handle_pkt 
    dhcp_p = pkt['dhcp'] = dhcp.dhcp.parser(pkt['pkt'][3]) 
    File "/home/ubuntu/ryu/ryu/lib/packet/dhcp.py", line 212, in parser 
    return cls._parser(buf) 
    File "/home/ubuntu/ryu/ryu/lib/packet/dhcp.py", line 192, in _parser 
    ) = struct.unpack_from(unpack_str, buf) 
error: unpack_from requires a buffer of at least 233 bytes 

を、dhcp.pyは、それが必要とする233のバイトを受信して​​いません。残念ながら、私はSDNハブが提供するVM上でOpen vSwitchを使用しており、128バイトが限界に見えます。だから、私はRyuのdhcp.pyファイルと競合しています。私のソリューションはdhcp.pyを変更することでした。それがどのように行われたのか。

コードを変更する前に、まずRyuコントローラを更新することをお勧めします。手順は次のとおりです。

手順1:VMを使用している場合。ちょっとした写真を撮ったり、今すぐクローンしたりしてください。

ステップ2:アップデート龍

cd ryu 
git pull 

私がいたようにあなたは、古いバージョンを実行していた場合は、次のようなエラーがあなたの龍コントローラを実行するときに次の試みを発生する可能性があります。

Traceback (most recent call last): 
File "./bin/ryu-manager", line 18, in <module> 
    from ryu.cmd.manager import main 
File "/home/ubuntu/ryu/ryu/cmd/manager.py", line 31, in <module> 
    from ryu.base.app_manager import AppManager 
File "/home/ubuntu/ryu/ryu/base/app_manager.py", line 37, in <module> 
    from ryu.controller.controller import Datapath 
File "/home/ubuntu/ryu/ryu/controller/controller.py", line 74, in <module> 
    help='Maximum number of unreplied echo requests before datapath is disconnected.') 
File "/usr/local/lib/python2.7/dist-packages/oslo_config/cfg.py", line 1033, in __init__ 
    super(IntOpt, self).__init__(name, type=types.Integer(), **kwargs) 
TypeError: __init__() got an unexpected keyword argument 'min' 

ステップ3:oslo_configファイルを更新する

sudo pip install oslo.config --upgrade 

ステップ2からのTypeErrorをresにする必要がありますolived。 (うまくいけば、ちょうどあなたのVMをクローンしました。)

ステップ3:リュウ/リュウ/ LIB /パケット/位置変更リュのdhcp.pyファイル

リュのdhcp.pyファイル()より235バイトのバッファを受信することを期待します。それ以外の場合は、スローしてエラーを返し、コントローラに何も返しません。私のバッファは約81バイトのバッファサイズしか受け取らないので。 Ryu dhcp.pyファイルを次のように変更しました。

dhcp.pyが '!BBBBIHH4s4s4s4s16s64s128s'という文字列形式を指定しているため、エラーが発生します。 #1では、私は2番目のオプションを作成しました。そうすることで、100バイトよりも小さいパケットが到着した場合、パケットを別の方法で処理するif文をいくつか挿入することができます。同様に、パケットが235バイトより大きい場合、dhcp.pyはパケットを通常通り処理し、余分な値を返します。

class dhcp(packet_base.PacketBase): 
    """DHCP (RFC 2131) header encoder/decoder class. 
       ....deleted.... 
    """ 
    _MIN_LEN = 236 
    _HLEN_UNPACK_STR = '!BBB' 
    _HLEN_UNPACK_LEN = struct.calcsize(_HLEN_UNPACK_STR) 
    _DHCP_UNPACK_STR = '!BIHH4s4s4s4s%ds%ds64s128s' 
    ################################################## 
    #1(mod) Created second option for unpacking string 
    _DHCP_UNPACK_STR2 = '!BIHH4s4s4s4s%ds%ds40s' 
    _DHCP_PACK_STR = '!BBBBIHH4s4s4s4s16s64s128s' 
    ################################################# 
    _DHCP_CHADDR_LEN = 16 
    _HARDWARE_TYPE_ETHERNET = 1 
    _class_prefixes = ['options'] 
    _TYPE = { 
     'ascii': [ 
      'ciaddr', 'yiaddr', 'siaddr', 'giaddr', 'chaddr', 'sname' 
     ] 
    } 

    def __init__(self, op, chaddr, options, htype=_HARDWARE_TYPE_ETHERNET, 
       hlen=0, hops=0, xid=None, secs=0, flags=0, 
       ciaddr='0.0.0.0', yiaddr='0.0.0.0', siaddr='0.0.0.0', 
       giaddr='0.0.0.0', sname='', boot_file=b''): 
     super(dhcp, self).__init__() 
     #...Deleted No Changes made to init. 

    @classmethod 
    def _parser(cls, buf): 
     (op, htype, hlen) = struct.unpack_from(cls._HLEN_UNPACK_STR, buf) 
     buf = buf[cls._HLEN_UNPACK_LEN:] 
     #################################################### 
     #2(mod) provided option for smaller packet sizes 
     if len(buf) < 100: 
      unpack_str = cls._DHCP_UNPACK_STR2 % (hlen, 
              (cls._DHCP_CHADDR_LEN - hlen)) 
     else: 
      unpack_str = cls._DHCP_UNPACK_STR % (hlen, 
              (cls._DHCP_CHADDR_LEN - hlen))    
     ##################################################### 
     min_len = struct.calcsize(unpack_str) 
     ###################################################### 
     #3(mod) provided option for smaller packets, set bootfile to b'' 
     if min_len > 233: 
      (hops, xid, secs, flags, ciaddr, yiaddr, siaddr, giaddr, 
      chaddr, dummy, sname, boot_file 
      ) = struct.unpack_from(unpack_str, buf) 
     else: 
      boot_file=b'' 
      (hops, xid, secs, flags, ciaddr, yiaddr, siaddr, giaddr, 
      chaddr, dummy, sname, boot_file 
      ) = struct.unpack_from(unpack_str, buf)+(boot_file,) 
     ########################################################  
     length = min_len 
     ######################################################## 
     # (mod) provided option for smaller packet sizes, no parse_opt 
     if len(buf) > 233: 
      parse_opt = options.parser(buf[min_len:]) 
      length += parse_opt.options_len 
     else: 
      parse_opt = None 
      length = min_len 
     ######################################################### 
     return (cls(op, addrconv.mac.bin_to_text(chaddr), parse_opt, 
        htype, hlen, hops, xid, secs, flags, 
        addrconv.ipv4.bin_to_text(ciaddr), 
        addrconv.ipv4.bin_to_text(yiaddr), 
        addrconv.ipv4.bin_to_text(siaddr), 
        addrconv.ipv4.bin_to_text(giaddr), 
        sname.decode('ascii'), boot_file), 
       None, buf[length:]) 

完全なファイルはすぐにhttps://github.com/Ryuretic/RyureticLabs/tree/master/ryu/ryu/app/Ryuretic/Support_Filesになります。

あなたはdhcp.pyファイルにこれらのadjustementsを作る場合、あなたは以下のヘッダフィールドへのアクセスを獲得します:

============== ==================== 
Attribute  Description 
============== ==================== 
op    Message op code/message type.\ 
       1 = BOOTREQUEST, 2 = BOOTREPLY 
htype   Hardware address type (e.g. '1' = 10mb ethernet). 
hlen   Hardware address length (e.g. '6' = 10mb ethernet). 
hops   Client sets to zero, optionally used by relay agent\ 
       when booting via a relay agent. 
xid   Transaction ID, a random number chosen by the client,\ 
       used by the client and serverto associate messages\ 
       and responses between a client and a server. 
secs   Filled in by client, seconds elapsed since client\ 
       began address acquisition or renewal process. 
flags   Flags. 
ciaddr   Client IP address; only filled in if client is in\ 
       BOUND, RENEW or REBINDING state and can respond\ 
       to ARP requests. 
yiaddr   'your' (client) IP address. 
siaddr   IP address of next server to use in bootstrap;\ 
       returned in DHCPOFFER, DHserver. 
giaddr   Relay agent IP address, used in booting via a\ 
       relay agent. 
chaddr   Client hardware address. 
sname(partial) Optional server host name, null terminated string. 
関連する問題