2016-12-20 1 views
0

Ich verwende den Ryu SDN-Controller mit einem offenen vSwitch auf Mininet mit OpenFlow 1.3, um DHCP-Pakete zu parsen. Nach den Online-Beispielen und den Ryu-Ressourcen habe ich einen DHCP-Paket-Parser implementiert. Es funktioniert jedoch nicht so, wie ich es erwartet hatte, und ich frage mich, ob jemand einen Einblick hat, warum meine erste Lösung nicht funktioniert?Kann DHCP-Pakete mit Ryus get_protocol (dhcp.dhcp) nicht analysieren

Ein Beispiel für einen Code-Snippet für eine DHCP-Paketanalyse ist unter:

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) 

Mein Code eine ähnliche Ader folgt:

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) 

Dies scheint vernünftig, da ich diese genaue Reihenfolge folgende bin mit andere Protokolle wie ARP, ICMP, IP usw. Beispiele unten.

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

Das einzige Problem ist, dass die drei Parser ich oben tatsächlich Daten zurückgeben Liste, während die get_protocol für DHCP konsequent None zurückgibt. Ich habe das bereits getestet, indem ich DHCP-Pakete über meinen Switch gesendet habe.

Was ist Arbeit ist das folgende Code-Snippet, wo ich Paketlisten mit mehr als drei Werte identifizieren. Ich speichere den Wert bei Index drei und setze das als mein DHCP-Paket. . Im DHCP-Paket, konzentriere ich den String mit dem Index der Parsen 2. dass die Daten enthält, die mich interessieren

# 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) 

Ein Druck aus diesen Werten sieht so aus:

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

Die Mit dem obigen Code kann ich den Inhalt von DHCP-Paketen beobachten, aber ich versuche wirklich herauszufinden, warum ich mit der Methode pkt ['pkt']. get_protocol (dhcp.dhcp) keine ähnlichen Ergebnisse erziele.

Antwort

0

Ok, ich habe das Problem gefunden. In den Zeilen 200 - 218 von dhcp.py gibt es eine try except-Anweisung. Ich zog den cls._parser aus dem Versuch, den Fehler zu sehen, es wirft und ich bekomme diese:

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 

So dhcp.py nicht den 233 Bytes empfängt, die sie benötigen. Leider verwende ich einen offenen vSwitch auf der VM, die vom SDN-Hub bereitgestellt wird, und 128 Bytes scheinen ein Limit zu sein. Also, ich habe einen Konflikt mit Ryu's dhcp.py Datei. Meine Lösung war, dhcp.py zu modifizieren. Wie das gemacht wurde, folgt.

Bevor Sie den Code ändern, empfehle ich Ihnen, zuerst Ihren Ryu-Controller zu aktualisieren. Die Verfahren lauten wie folgt:

Schritt 1: Wenn Sie eine VM verwenden. Machen Sie einen Schnappschuss oder klonen Sie ihn jetzt.

Schritt 2: Update Ryu

cd ryu 
git pull 

Wenn Sie eine ältere Version ausgeführt wurden, wie ich war, dann wird der folgende Fehler kann auftreten, wenn Sie nächsten Versuch Ihre Ryu Controller auszuführen:

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' 

Schritt 3: Aktualisieren Sie Ihre oslo_config-Datei

Der TypeError von Schritt 2 sollte jetzt res sein olved. (Hoffentlich klonten Sie Ihre VM nur für den Fall.)

Schritt 3: dhcp.py Datei

Ryu dhcp.py Datei (die sich auf/Ryu/Ryu/lib/Pakets Modify Ryu) erwartet, einen Puffer von mehr als 235 Bytes zu empfangen. Andernfalls werden Fehler und Fehler ausgegeben und nichts an den Controller zurückgegeben. Da mein Puffer nur eine Puffergröße von ca. 81 Bytes erhält. Ich habe die Ryu dhcp.py-Datei wie folgt geändert.

Der Fehler tritt auf, weil dhcp.py ein Zeichenfolgenformat von "! BBBBIHH4s4s4s4s16s64s128s" angibt. In # 1 habe ich eine zweite Option erstellt. Tun Sie dies, erlaubt mir, ein paar if-Anweisungen einzufügen, um das Paket anders zu behandeln, wenn ein Paket ankommt, das kleiner als 100 Bytes ist. Wenn das Paket größer als 235 Byte ist, verarbeitet dhcp.py das Paket normal und gibt die zusätzlichen Werte zurück.

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:]) 

Die vollständige Datei wird bald auf https://github.com/Ryuretic/RyureticLabs/tree/master/ryu/ryu/app/Ryuretic/Support_Files sein.

Wenn Sie diese adjustements zum dhcp.py Datei machen, dann werden Sie Zugriff auf die folgenden Header-Felder gewinnen:

============== ==================== 
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. 
Verwandte Themen