From efd8ba8991afb3bd2107dae5a640d9866c230227 Mon Sep 17 00:00:00 2001 From: sdn Date: Tue, 22 Dec 2015 11:55:45 -0500 Subject: [PATCH 01/88] 0.3 starting --- example_filter.json | 8 +- ofp_dissector_v13.py | 35 +++++++ ofp_parser_v13.py | 229 +++++++++++++++++++++++++++++++++++++++++++ ofp_prints_v10.py | 4 + ofp_prints_v13.py | 7 ++ ofp_sniffer.py | 38 ++++--- 6 files changed, 304 insertions(+), 17 deletions(-) create mode 100644 ofp_dissector_v13.py create mode 100644 ofp_parser_v13.py create mode 100644 ofp_prints_v13.py diff --git a/example_filter.json b/example_filter.json index b231b6e..dc8b14c 100644 --- a/example_filter.json +++ b/example_filter.json @@ -5,15 +5,13 @@ 2, 3, 10, - 13 + 13, + 16, + 17 ] }, "1.3": { "rejected_of_types": [ - 2, - 3, - 10, - 13 ] } }, diff --git a/ofp_dissector_v13.py b/ofp_dissector_v13.py new file mode 100644 index 0000000..d44015f --- /dev/null +++ b/ofp_dissector_v13.py @@ -0,0 +1,35 @@ +def get_ofp_type(of_type): + of_types = {0: 'Hello', + 1: 'Error', + 2: 'EchoReq', + 3: 'EchoRes', + 4: 'Experimenter', + 5: 'FeatureReq', + 6: 'FeatureRes', + 7: 'GetConfigReq', + 8: 'GetConfigRes', + 9: 'SetConfig', + 10: 'PacketIn', + 11: 'FlowRemoved', + 12: 'PortStatus', + 13: 'PacketOut', + 14: 'FlowMod', + 15: 'GroupMod', + 16: 'PortMod', + 17: 'TableMod', + 18: 'MultipartReq', + 19: 'MiltopartRes', + 20: 'BarrierReq', + 21: 'BarrierRes', + 22: 'QueueGetConfigReq', + 23: 'QueueGetConfigRes', + 24: 'RoleReq', + 25: 'RoleRes', + 26: 'GetAsyncReq', + 27: 'GetAsyncRes', + 28: 'SetAsync', + 29: 'MeterMod'} + try: + return of_types[of_type] + except: + return 'UnknownType(%s)' % of_type diff --git a/ofp_parser_v13.py b/ofp_parser_v13.py new file mode 100644 index 0000000..64f535c --- /dev/null +++ b/ofp_parser_v13.py @@ -0,0 +1,229 @@ +from struct import unpack +# import ofp_dissector_v13 +import ofp_prints_v13 +# import socket + + +def process_ofp_type13(of_type, packet, h_size, of_xid, print_options, + sanitizer): + if of_type == 0: + result = parse_Hello(packet, h_size, of_xid) + elif of_type == 1: + result = parse_Error(packet, h_size, of_xid) + elif of_type == 2: + result = parse_EchoReq(packet, h_size, of_xid) + elif of_type == 3: + result = parse_EchoRes(packet, h_size, of_xid) + elif of_type == 4: + result = parse_Experimenter(packet, h_size, of_xid) + elif of_type == 5: + result = parse_FeatureReq(packet, h_size, of_xid) + elif of_type == 6: + result = parse_FeatureRes(packet, h_size, of_xid) + elif of_type == 7: + result = parse_GetConfigReq(packet, h_size, of_xid) + elif of_type == 8: + result = parse_GetConfigRes(packet, h_size, of_xid) + elif of_type == 9: + result = parse_SetConfig(packet, h_size, of_xid) + elif of_type == 10: + result = parse_PacketIn(packet, h_size, of_xid, sanitizer) + elif of_type == 11: + result = parse_FlowRemoved(packet, h_size, of_xid) + elif of_type == 12: + result = parse_PortStatus(packet, h_size, of_xid) + elif of_type == 13: + result = parse_PacketOut(packet, h_size, of_xid, sanitizer, + print_options) + elif of_type == 14: + result = parse_FlowMod(packet, h_size, of_xid, print_options) + elif of_type == 15: + result = parse_GroupMod(packet, h_size, of_xid) + elif of_type == 16: + result = parse_PortMod(packet, h_size, of_xid) + elif of_type == 17: + result = parse_TableMod(packet, h_size, of_xid) + elif of_type == 18: + result = parse_MultipartReq(packet, h_size, of_xid) + elif of_type == 19: + result = parse_MultipartRes(packet, h_size, of_xid) + elif of_type == 20: + result = parse_BarrierReq(packet, h_size, of_xid) + elif of_type == 21: + result = parse_BarrierRes(packet, h_size, of_xid) + elif of_type == 22: + result = parse_QueueGetConfigReq(packet, h_size, of_xid) + elif of_type == 23: + result = parse_QueueGetConfigRes(packet, h_size, of_xid) + elif of_type == 24: + result = parse_RoleReq(packet, h_size, of_xid) + elif of_type == 25: + result = parse_RoleRes(packet, h_size, of_xid) + elif of_type == 26: + result = parse_GetAsyncReq(packet, h_size, of_xid) + elif of_type == 27: + result = parse_GetAsyncRes(packet, h_size, of_xid) + elif of_type == 28: + result = parse_SetAsync(packet, h_size, of_xid) + elif of_type == 29: + result = parse_MeterMod(packet, h_size, of_xid) + else: + return 0 + return result + + +# *************** Hello ***************** +def parse_Hello(packet, h_size, of_xid): + + def process_bitmap(of_xid, bitmap): + ofp_prints_v13.print_hello_bitmap(of_xid, bitmap) + + start = h_size + count = 0 + while len(packet[start:]) > 0: + # Get element[] + count += 1 + elem_raw = packet[start:start+4] + el_type, el_length = unpack('!HH', elem_raw) + ofp_prints_v13.print_hello_elememnts(of_xid, el_type, el_length, count) + + bitmaps = packet[start+4:start+el_length] + start_bit = 0 + + while len(bitmaps[start_bit:]) > 0: + bitmap_raw = packet[start_bit:start_bit+4] + bitmap = unpack('!L', bitmap_raw) + process_bitmap(of_xid, bitmap[0]) + start_bit = start_bit + 4 + + start = start + el_length + + return 1 + + +# ************** Error ***************** +def parse_Error(packet, h_size, of_xid): + # of_error = packet[h_size:h_size+4] + # ofe = unpack('!HH', of_error) + # ofe_type = ofe[0] + # ofe_code = ofe[1] + + # nameCode, typeCode = ofp_dissector_v10.get_ofp_error(ofe_type, ofe_code) + # ofp_prints_v10.print_of_error(of_xid, nameCode, typeCode) + return 0 + + +# ************ EchoReq ***************** +def parse_EchoReq(packet, h_size, of_xid): + # ofp_prints_v10.print_echoreq(of_xid) + return 0 + + +# ************ EchoRes ***************** +def parse_EchoRes(packet, h_size, of_xid): + # ofp_prints_v10.print_echores(of_xid) + return 0 + + +def parse_Experimenter(packet, h_size, of_xid): + return 0 + + +def parse_FeatureReq(packet, h_size, of_xid): + return 0 + + +def parse_FeatureRes(packet, h_size, of_xid): + return 0 + + +def parse_GetConfigReq(packet, h_size, of_xid): + return 0 + + +def parse_GetConfigRes(packet, h_size, of_xid): + return 0 + + +def parse_SetConfig(packet, h_size, of_xid): + return 0 + + +def parse_PacketIn(packet, h_size, of_xid, sanitizer): + return 0 + + +def parse_FlowRemoved(packet, h_size, of_xid): + return 0 + + +def parse_PortStatus(packet, h_size, of_xid): + return 0 + + +def parse_PacketOut(packet, h_size, of_xid, sanitizer, print_options): + return 0 + + +def parse_FlowMod(packet, h_size, of_xid, print_options): + return 0 + + +def parse_GroupMod(packet, h_size, of_xid): + return 0 + + +def parse_PortMod(packet, h_size, of_xid): + return 0 + + +def parse_TableMod(packet, h_size, of_xid): + return 0 + + +def parse_MultipartReq(packet, h_size, of_xid): + return 0 + + +def parse_MultipartRes(packet, h_size, of_xid): + return 0 + + +def parse_BarrierReq(packet, h_size, of_xid): + return 0 + + +def parse_BarrierRes(packet, h_size, of_xid): + return 0 + + +def parse_QueueGetConfigReq(packet, h_size, of_xid): + return 0 + + +def parse_QueueGetConfigRes(packet, h_size, of_xid): + return 0 + + +def parse_RoleReq(packet, h_size, of_xid): + return 0 + + +def parse_RoleRes(packet, h_size, of_xid): + return 0 + + +def parse_GetAsyncReq(packet, h_size, of_xid): + return 0 + + +def parse_GetAsyncRes(packet, h_size, of_xid): + return 0 + + +def parse_SetAsync(packet, h_size, of_xid): + return 0 + + +def parse_MeterMod(packet, h_size, of_xid): + return 0 diff --git a/ofp_prints_v10.py b/ofp_prints_v10.py index 3d58094..7ddb5de 100644 --- a/ofp_prints_v10.py +++ b/ofp_prints_v10.py @@ -1,5 +1,6 @@ from termcolor import colored import ofp_dissector_v10 +import ofp_dissector_v13 from ofp_parser_v10 import get_action, get_ip_from_long import ofp_cli # NO_COLOR variable import ofp_fsfw_v10 @@ -119,6 +120,9 @@ def print_openflow_header(of): if version == '1.0': name = ofp_dissector_v10.get_ofp_type(of['type']) name_type = '%s(%s)' % (name, of['type']) + elif version == '1.3': + name = ofp_dissector_v13.get_ofp_type(of['type']) + name_type = '%s(%s)' % (name, of['type']) else: name_type = '%s' % (of['type']) diff --git a/ofp_prints_v13.py b/ofp_prints_v13.py new file mode 100644 index 0000000..f895b4b --- /dev/null +++ b/ofp_prints_v13.py @@ -0,0 +1,7 @@ +def print_hello_elememnts(of_xid, el_type, el_length, count): + print ('%s Hello - Element: %s Type: %s Length: %s' % + (of_xid, count, el_type, el_length)) + + +def print_hello_bitmap(of_xid, bitmap): + print ('%s Hello - Bitmap: %s' % (of_xid, hex(bitmap))) diff --git a/ofp_sniffer.py b/ofp_sniffer.py index 5d06b1b..26e8acc 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -26,6 +26,7 @@ import ofp_cli import ofp_dissector_v10 import ofp_fsfw_v10 +from ofp_parser_v13 import process_ofp_type13 def main(argv): @@ -129,6 +130,10 @@ def parse_packet(packet, date, getlen, caplen, print_options, sanitizer): if result == 0: return + # If not OpenFlow version 1.0 or 1.3 return + if of_header['version'] not in [1, 4]: + return + # In case there are multiple flow_mods remaining_bytes = remaining_bytes - of_header['length'] @@ -143,27 +148,36 @@ def parse_packet(packet, date, getlen, caplen, print_options, sanitizer): print_options['device_ip'] = ip['d_addr'] print_options['device_port'] = tcp['dest_port'] + # Process and Print OF body + # OF_Header lenght = 8 + start = start + 8 + this_packet = packet[start:start+of_header['length'] - 8] + # If OpenFlow version is 1.0 - if of_header['version'] == int('1', 16): - # Process and Print OF body - # OF_Header lenght = 8 - start = start + 8 - this_packet = packet[start:start+of_header['length'] - 8] + if of_header['version'] is 1: if not process_ofp_type(of_header['type'], this_packet, 0, of_header['xid'], print_options, sanitizer): - print ('%s OpenFlow OFP_Type %s not dissected \n' % + + print ('%s OpenFlow OFP_Type %s unknown \n' % (of_header['xid'], of_header['type'])) return else: # Get next packet start = start + (of_header['length'] - 8) + # If OpenFlow version is 1.3 - elif of_header['version'] == int('4', 16): - print 'Coming soon...' - return - else: - print 'OpenFlow version %s not supported \n' % of_header['version'] - return + elif of_header['version'] is 4: + # Process and Print OF body + # OF_Header lenght = 8 + if not process_ofp_type13(of_header['type'], this_packet, 0, + of_header['xid'], print_options, + sanitizer): + print ('%s OpenFlow OFP_Type %s not dissected yet \n' % + (of_header['xid'], of_header['type'])) + return + else: + # Get next packet + start = start + (of_header['length'] - 8) # Do not process extra data from Hello and Error. # Maybe in the future. From 89efb887f6af4eb210f1b1388f2feae95d62af22 Mon Sep 17 00:00:00 2001 From: sdn Date: Tue, 22 Dec 2015 16:26:36 -0500 Subject: [PATCH 02/88] OF1.3: Hello, Echo, Barrier and Error added. Added directories --- TODO | 23 --- __init__.py | 17 +- gen/__init__.py | 12 ++ ofp_cli.py => gen/cli.py | 0 gen/prints.py | 136 +++++++++++++ ofp_fsfw_v10.py => gen/proxies.py | 0 ofp_tcpip_parser.py => gen/tcpip.py | 0 termcolor.py => gen/termcolor.py | 0 of10/__init__.py | 12 ++ ofp_dissector_v10.py => of10/dissector.py | 0 ofp_parser_v10.py => of10/parser.py | 182 +++++++++--------- ofp_prints_v10.py => of10/prints.py | 193 +++++-------------- ofp_vendors_v10.py => of10/vendors.py | 0 of13/__init__.py | 12 ++ of13/dissector.py | 223 ++++++++++++++++++++++ ofp_parser_v13.py => of13/parser.py | 35 ++-- of13/prints.py | 35 ++++ ofp_dissector_v13.py | 35 ---- ofp_prints_v13.py | 7 - ofp_sniffer.py | 21 +- 20 files changed, 608 insertions(+), 335 deletions(-) delete mode 100644 TODO create mode 100644 gen/__init__.py rename ofp_cli.py => gen/cli.py (100%) create mode 100644 gen/prints.py rename ofp_fsfw_v10.py => gen/proxies.py (100%) rename ofp_tcpip_parser.py => gen/tcpip.py (100%) rename termcolor.py => gen/termcolor.py (100%) create mode 100644 of10/__init__.py rename ofp_dissector_v10.py => of10/dissector.py (100%) rename ofp_parser_v10.py => of10/parser.py (82%) rename ofp_prints_v10.py => of10/prints.py (72%) rename ofp_vendors_v10.py => of10/vendors.py (100%) create mode 100644 of13/__init__.py create mode 100644 of13/dissector.py rename ofp_parser_v13.py => of13/parser.py (89%) create mode 100644 of13/prints.py delete mode 100644 ofp_dissector_v13.py delete mode 100644 ofp_prints_v13.py diff --git a/TODO b/TODO deleted file mode 100644 index 9e97cb7..0000000 --- a/TODO +++ /dev/null @@ -1,23 +0,0 @@ -TODO List: - -Version 0.2: - -- Dissects all OpenFlow 1.0 message types -- Reads from Libpcap files -- PacketIn filters -- Integrate with FlowSpace Firewall - -Version 0.3: - -- Dissects all OpenFlow 1.3 message types - -Version 0.4: - -- Topology Validator -- Labels outputs depending of Match and Action -- Full OpenVSwitch/NICIRA dissector -- Outputs as text and libcap to different files -- Reads SSL/TLS sessions -- Make TAR.GZ available (with Makefile) -- Create RPM and DEB packages - diff --git a/__init__.py b/__init__.py index 080b343..2c0e3c2 100644 --- a/__init__.py +++ b/__init__.py @@ -1,5 +1,12 @@ -import ofp_dissector_v10.py -import ofp_parser_v10.py -import ofp_prints_v10.py -import ofp_fsfw_v10.py -import termcolor +import gen.cli +import gen.prints +import gen.proxies +import gen.tcpip +import gen.termcolor +import of10.dissector +import of10.parser +import of10.prints +import of10.vendors +import of10.dissector +import of13.parser +import of13.prints diff --git a/gen/__init__.py b/gen/__init__.py new file mode 100644 index 0000000..2c0e3c2 --- /dev/null +++ b/gen/__init__.py @@ -0,0 +1,12 @@ +import gen.cli +import gen.prints +import gen.proxies +import gen.tcpip +import gen.termcolor +import of10.dissector +import of10.parser +import of10.prints +import of10.vendors +import of10.dissector +import of13.parser +import of13.prints diff --git a/ofp_cli.py b/gen/cli.py similarity index 100% rename from ofp_cli.py rename to gen/cli.py diff --git a/gen/prints.py b/gen/prints.py new file mode 100644 index 0000000..24a6b1f --- /dev/null +++ b/gen/prints.py @@ -0,0 +1,136 @@ +''' + Generic/Protocol-independent prints +''' + +from gen.termcolor import colored +import of10.dissector +import of13.dissector +from of10.parser import get_ip_from_long +import gen.cli # NO_COLOR variable +import gen.proxies + + +def red(string): + if gen.cli.NO_COLOR is True: + return string + return colored(string, 'red') + + +def green(string): + if gen.cli.NO_COLOR is True: + return string + return colored(string, 'green') + + +def blue(string): + if gen.cli.NO_COLOR is True: + return string + return colored(string, 'blue') + + +def yellow(string): + if gen.cli.NO_COLOR is True: + return string + return colored(string, 'yellow') + + +def cyan(string): + if gen.cli.NO_COLOR is True: + return string + return colored(string, 'cyan') + + +def eth_addr(a): + mac = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" % (ord(a[0]), ord(a[1]), ord(a[2]), + ord(a[3]), ord(a[4]), ord(a[5])) + return mac + + +def datapath_id(a): + dpid = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" % (ord(a[0]), ord(a[1]), + ord(a[2]), ord(a[3]), + ord(a[4]), ord(a[5]), + ord(a[6]), ord(a[7])) + return dpid + + +def print_headers(print_options, date, getlen, caplen, eth, ip, tcp): + if print_options['min'] == 1: + print_minimal(date, getlen, ip, tcp) + else: + print_layer1(date, getlen, caplen) + print_layer2(eth) + print_layer3(ip) + print_tcp(tcp) + + +def print_minimal(date, getlen, ip, tcp): + string = '%s %s:%s -> %s:%s Size: %s Bytes' + + source = gen.proxies.get_ip_name(ip['s_addr'], tcp['source_port']) + dest = gen.proxies.get_ip_name(ip['d_addr'], tcp['dest_port']) + + print string % (date, cyan(source), cyan(tcp['source_port']), + cyan(dest), cyan(tcp['dest_port']), getlen) + + +def print_layer1(date, getlen, caplen): + print ('%s: captured %d bytes, truncated to %d bytes' % + (date, getlen, caplen)) + + +def print_layer2(eth): + print ('Ethernet: Destination MAC: %s Source MAC: %s Protocol: %s' % + (eth_addr(eth['dst_mac']), eth_addr(eth['src_mac']), + red(hex(eth['protocol'])))) + + +def print_vlan(vlan): + print ('Prio: %s CFI: %s VID: %s' % + (vlan['prio'], vlan['cfi'], red(vlan['vid']))) + + +def print_arp(arp): + print ('ARP: Hardware Type: %s Protocol Type: %s ' + 'HW Length: %s Prot Length: %s Opcode: %s ' + '\nARP: Source MAC: %s Source IP: %s Destination MAC: %s ' + 'Destination IP: %s' + % (arp['hw_type'], arp['prot_type'], arp['hw_len'], arp['prot_len'], + arp['opcode'], + eth_addr(arp['src_mac']), get_ip_from_long(arp['src_ip']), + eth_addr(arp['dst_mac']), get_ip_from_long(arp['dst_ip']))) + + +def print_layer3(ip): + print (('IP Version: %d IP Header Length: %d TTL: %d Protocol: %d ' + 'Source Address: %s Destination Address: %s') % + (ip['version'], (ip['ihl'] * 4), ip['ttl'], ip['protocol'], + blue(ip['s_addr']), blue(ip['d_addr']))) + + +def print_tcp(tcp): + print ('TCP Source Port: %s Dest Port: %s Sequence Number: %s ' + 'Acknowledgement: %s TCP header length: %s Flags: (CWR: %s ' + 'ECE: %s URG: %s ACK: %s PSH: %s RST: %s SYN: %s FYN: %s' % + (tcp['source_port'], tcp['dest_port'], tcp['sequence'], + tcp['acknowledgement'], (tcp['length']), tcp['flag_cwr'], + tcp['flag_ece'], tcp['flag_urg'], tcp['flag_ack'], tcp['flag_psh'], + tcp['flag_rst'], tcp['flag_syn'], tcp['flag_fyn'])) + + +def print_openflow_header(of): + version = of10.dissector.get_ofp_version(of['version']) + name_version = '%s(%s)' % (version, of['version']) + if version == '1.0': + name = of10.dissector.get_ofp_type(of['type']) + name_type = '%s(%s)' % (name, of['type']) + elif version == '1.3': + name = of13.dissector.get_ofp_type(of['type']) + name_type = '%s(%s)' % (name, of['type']) + else: + name_type = '%s' % (of['type']) + + print ('OpenFlow Version: %s Type: %s Length: %s XID: %s' % + (name_version, yellow(name_type), of['length'], red(of['xid']))) + + diff --git a/ofp_fsfw_v10.py b/gen/proxies.py similarity index 100% rename from ofp_fsfw_v10.py rename to gen/proxies.py diff --git a/ofp_tcpip_parser.py b/gen/tcpip.py similarity index 100% rename from ofp_tcpip_parser.py rename to gen/tcpip.py diff --git a/termcolor.py b/gen/termcolor.py similarity index 100% rename from termcolor.py rename to gen/termcolor.py diff --git a/of10/__init__.py b/of10/__init__.py new file mode 100644 index 0000000..2c0e3c2 --- /dev/null +++ b/of10/__init__.py @@ -0,0 +1,12 @@ +import gen.cli +import gen.prints +import gen.proxies +import gen.tcpip +import gen.termcolor +import of10.dissector +import of10.parser +import of10.prints +import of10.vendors +import of10.dissector +import of13.parser +import of13.prints diff --git a/ofp_dissector_v10.py b/of10/dissector.py similarity index 100% rename from ofp_dissector_v10.py rename to of10/dissector.py diff --git a/ofp_parser_v10.py b/of10/parser.py similarity index 82% rename from ofp_parser_v10.py rename to of10/parser.py index 3b43009..58fe28c 100644 --- a/ofp_parser_v10.py +++ b/of10/parser.py @@ -1,11 +1,15 @@ +''' + Parser for OpenFlow 1.0 +''' + from struct import unpack -import ofp_dissector_v10 -import ofp_prints_v10 +import of10.dissector +import of10.prints import socket import struct -import ofp_tcpip_parser -import ofp_vendors_v10 -import ofp_fsfw_v10 +import gen.tcpip +import of10.vendors +import gen.proxies def process_ofp_type(of_type, packet, h_size, of_xid, print_options, sanitizer): @@ -61,7 +65,7 @@ def process_ofp_type(of_type, packet, h_size, of_xid, print_options, sanitizer): # *************** Hello ***************** def parse_Hello(packet, h_size, of_xid): - ofp_prints_v10.print_of_hello(of_xid) + of10.prints.print_of_hello(of_xid) return 1 @@ -72,20 +76,20 @@ def parse_Error(packet, h_size, of_xid): ofe_type = ofe[0] ofe_code = ofe[1] - nameCode, typeCode = ofp_dissector_v10.get_ofp_error(ofe_type, ofe_code) - ofp_prints_v10.print_of_error(of_xid, nameCode, typeCode) + nameCode, typeCode = of10.dissector.get_ofp_error(ofe_type, ofe_code) + of10.prints.print_of_error(of_xid, nameCode, typeCode) return 1 # ************ EchoReq ***************** def parse_EchoReq(packet, h_size, of_xid): - ofp_prints_v10.print_echoreq(of_xid) + of10.prints.print_echoreq(of_xid) return 1 # ************ EchoRes ***************** def parse_EchoRes(packet, h_size, of_xid): - ofp_prints_v10.print_echores(of_xid) + of10.prints.print_echores(of_xid) return 1 @@ -93,18 +97,18 @@ def parse_EchoRes(packet, h_size, of_xid): def parse_Vendor(packet, h_size, of_xid): of_vendor = packet[h_size:h_size+4] ofv = unpack('!L', of_vendor) - ofp_prints_v10.print_of_vendor(ofv[0], of_xid) + of10.prints.print_of_vendor(ofv[0], of_xid) # If code 8992 = NICIRA if ofv[0] == 8992: - ofp_vendors_v10.parse_nicira(packet, h_size+4, of_xid) + of10.vendors.parse_nicira(packet, h_size+4, of_xid) print return 1 # *********** FeatureReq *************** def parse_FeatureReq(packet, h_size, of_xid): - ofp_prints_v10.print_of_feature_req(of_xid) + of10.prints.print_of_feature_req(of_xid) return 1 @@ -147,8 +151,8 @@ def _parse_phy_curr(values): def _parse_phy_ports(packet, of_xid): phy = unpack('!H6s16sLLLLLL', packet) - port_id = ofp_dissector_v10.get_phy_port_id(phy[0]) - hw_addr = ofp_prints_v10.eth_addr(phy[1]) + port_id = of10.dissector.get_phy_port_id(phy[0]) + hw_addr = of10.prints.eth_addr(phy[1]) config = _parse_phy_config(phy[3]) state = _parse_phy_state(phy[4]) curr = _parse_phy_curr(phy[5]) @@ -173,20 +177,20 @@ def parse_FeatureRes(packet, h_size, of_xid): ofrs = unpack('!8sLB3sLL', of_fres) f_res = {'datapath_id': ofrs[0], 'n_buffers': ofrs[1], 'n_tbls': ofrs[2], 'pad': ofrs[3]} - ofp_prints_v10.print_of_feature_res(of_xid, f_res) + of10.prints.print_of_feature_res(of_xid, f_res) # 'capabilities': ofrs[4], 'actions': ofrs[5]} caps = [] caps = _parse_capabilities(ofrs[4]) actions = [] actions = _parse_actions(ofrs[5]) - ofp_prints_v10.print_of_feature_res_caps_and_actions(of_xid, caps, actions) + of10.prints.print_of_feature_res_caps_and_actions(of_xid, caps, actions) # Ports description? start = h_size + 24 while len(packet[start:]) > 0: ports = _parse_phy_ports(packet[start:start+48], of_xid) - ofp_prints_v10.print_of_feature_res_ports(of_xid, ports) + of10.prints.print_of_feature_res_ports(of_xid, ports) start = start + 48 return 1 @@ -194,7 +198,7 @@ def parse_FeatureRes(packet, h_size, of_xid): # ***************** GetConfigReq ********************* def parse_GetConfigReq(packet, h_size, of_xid): - ofp_prints_v10.print_of_getconfig_req(of_xid) + of10.prints.print_of_getconfig_req(of_xid) return 1 @@ -202,44 +206,44 @@ def parse_GetConfigReq(packet, h_size, of_xid): def _parse_SetGetConfig(packet, h_size): pkt_raw = packet[h_size:h_size+4] pkt_list = unpack('!HH', pkt_raw) - flag = ofp_dissector_v10.get_configres_flags(pkt_list[0]) + flag = of10.dissector.get_configres_flags(pkt_list[0]) miss_send_len = pkt_list[1] return flag, miss_send_len def parse_GetConfigRes(packet, h_size, of_xid): flag, miss_send_len = _parse_SetGetConfig(packet, h_size) - ofp_prints_v10.print_ofp_getConfigRes(of_xid, flag, miss_send_len) + of10.prints.print_ofp_getConfigRes(of_xid, flag, miss_send_len) return 1 # ******************* SetConfig ********************** def parse_SetConfig(packet, h_size, of_xid): flag, miss_send_len = _parse_SetGetConfig(packet, h_size) - ofp_prints_v10.print_ofp_setConfig(of_xid, flag, miss_send_len) + of10.prints.print_ofp_setConfig(of_xid, flag, miss_send_len) return 1 # ****************** PacketIn ************************ def _parse_ethernet_lldp_PacketInOut(packet, start): # Ethernet - eth = ofp_tcpip_parser.get_ethernet_frame(packet[start:start+14], 1) + eth = gen.tcpip.get_ethernet_frame(packet[start:start+14], 1) start = start + 14 etype = '0x0000' vlan = {} # VLAN or not if eth['protocol'] in [33024]: - vlan = ofp_tcpip_parser.get_ethernet_vlan(packet[start:start+2]) + vlan = gen.tcpip.get_ethernet_vlan(packet[start:start+2]) start = start + 2 # If VLAN exists, there is a next eth['protocol'] - etype = ofp_tcpip_parser.get_next_etype(packet[start:start+2]) + etype = gen.tcpip.get_next_etype(packet[start:start+2]) start = start + 2 else: etype = eth['protocol'] # LLDP lldp = {} if etype in [35020, 35138]: - lldp = ofp_tcpip_parser.get_lldp(packet[start:]) + lldp = gen.tcpip.get_lldp(packet[start:]) return eth, vlan, lldp, start eth['protocol'] = etype return eth, vlan, {}, start @@ -253,32 +257,32 @@ def _parse_other_types(packet, start, eth): # If it gets here, means that the LLDP packet is MalFormed print 'LLDP Packet MalFormed' elif eth['protocol'] in [2048]: - ip = ofp_tcpip_parser.get_ip_packet(packet, start) - ofp_prints_v10.print_layer3(ip) + ip = gen.tcpip.get_ip_packet(packet, start) + gen.prints.print_layer3(ip) if ip['protocol'] is 6: - tcp = ofp_tcpip_parser.get_tcp_stream(packet, start + ip['length']) - ofp_prints_v10.print_tcp(tcp) + tcp = gen.tcpip.get_tcp_stream(packet, start + ip['length']) + gen.prints.print_tcp(tcp) elif eth['protocol'] in [2054]: - arp = ofp_tcpip_parser.get_arp(packet[start:]) - ofp_prints_v10.print_arp(arp) + arp = gen.tcpip.get_arp(packet[start:]) + gen.prints.print_arp(arp) else: print 'Ethertype %s not dissected' % hex(eth['protocol']) def _print_packetIn(of_xid, packetIn, eth, vlan, lldp): - ofp_prints_v10.print_ofp_packetIn(of_xid, packetIn) - ofp_prints_v10.print_packetInOut_layer2(of_xid, eth) + of10.prints.print_ofp_packetIn(of_xid, packetIn) + of10.prints.print_packetInOut_layer2(of_xid, eth) if len(vlan) != 0: - ofp_prints_v10.print_packetInOut_vlan(of_xid, vlan) + of10.prints.print_packetInOut_vlan(of_xid, vlan) if len(lldp) != 0: - ofp_prints_v10.print_packetInOut_lldp(of_xid, lldp) + of10.prints.print_packetInOut_lldp(of_xid, lldp) def parse_PacketIn(packet, h_size, of_xid, sanitizer): # buffer_id(32), total_len(16), in_port(16), reason(8), pad(8) pkt_raw = packet[h_size:h_size+10] p_in = unpack('!LHHBB', pkt_raw) - reason = ofp_dissector_v10.get_packetIn_reason(p_in[3]) + reason = of10.dissector.get_packetIn_reason(p_in[3]) packetIn = {'buffer_id': p_in[0], 'total_len': p_in[1], 'in_port': p_in[2], 'reason': reason, 'pad': p_in[4]} @@ -308,13 +312,13 @@ def parse_PacketIn(packet, h_size, of_xid, sanitizer): # ******************** FlowRemoved *************************** def parse_FlowRemoved(packet, h_size, of_xid): ofmatch = _parse_OFMatch(packet, h_size) - ofp_prints_v10.print_ofp_match(of_xid, ofmatch) + of10.prints.print_ofp_match(of_xid, ofmatch) of_rem_body = packet[h_size+40:h_size+40+40] ofrem = unpack('!8sHBBLLHBBQQ', of_rem_body) cookie = ofrem[0] if not len(ofrem[0]) else 0 cookie = '0x' + format(cookie, '02x') - reason = ofp_dissector_v10.get_flow_removed_reason(ofrem[2]) + reason = of10.dissector.get_flow_removed_reason(ofrem[2]) ofrem = {'cookie': cookie, 'priority': ofrem[1], 'reason': reason, 'pad': ofrem[3], 'duration_sec': ofrem[4], @@ -322,7 +326,7 @@ def parse_FlowRemoved(packet, h_size, of_xid): 'pad2': ofrem[7], 'pad3': ofrem[8], 'packet_count': ofrem[9], 'byte_count': ofrem[10]} - ofp_prints_v10.print_ofp_flow_removed(of_xid, ofrem) + of10.prints.print_ofp_flow_removed(of_xid, ofrem) return 1 @@ -330,11 +334,11 @@ def parse_FlowRemoved(packet, h_size, of_xid): def parse_PortStatus(packet, h_size, of_xid): port_raw = packet[h_size:h_size+8] port = unpack('!B7s', port_raw) - reason = ofp_dissector_v10.get_portStatus_reason(port[0]) + reason = of10.dissector.get_portStatus_reason(port[0]) pad = port[1] - ofp_prints_v10.print_portStatus(of_xid, reason, pad) + of10.prints.print_portStatus(of_xid, reason, pad) ports = _parse_phy_ports(packet[h_size+8:h_size+64], of_xid) - ofp_prints_v10.print_of_feature_res_ports(of_xid, ports) + of10.prints.print_of_feature_res_ports(of_xid, ports) return 1 @@ -348,35 +352,35 @@ def parse_PacketOut(packet, h_size, of_xid, sanitizer, print_options): packetOut = {'buffer_id': p_out[0], 'in_port': p_out[1], 'actions_len': actions_len} - ofp_prints_v10.print_ofp_packetOut(of_xid, packetOut) + of10.prints.print_ofp_packetOut(of_xid, packetOut) # Actions start = h_size + 8 _parse_OFAction(of_xid, packet[start:start+packetOut['actions_len']], 0) # Ethernet start = h_size + 8 + packetOut['actions_len'] - eth = ofp_tcpip_parser.get_ethernet_frame(packet[start:start+14], 1) - ofp_prints_v10.print_packetInOut_layer2(of_xid, eth) + eth = gen.tcpip.get_ethernet_frame(packet[start:start+14], 1) + of10.prints.print_packetInOut_layer2(of_xid, eth) start = start + 14 etype = '0x0000' # VLAN or not if eth['protocol'] in [33024]: - vlan = ofp_tcpip_parser.get_ethernet_vlan(packet[start:start+2]) - ofp_prints_v10.print_packetInOut_vlan(of_xid, vlan) + vlan = gen.tcpip.get_ethernet_vlan(packet[start:start+2]) + of10.prints.print_packetInOut_vlan(of_xid, vlan) start = start + 2 # If VLAN exists, there is a next eth['protocol'] - etype = ofp_tcpip_parser.get_next_etype(packet[start:start+2]) + etype = gen.tcpip.get_next_etype(packet[start:start+2]) start = start + 2 else: etype = eth['protocol'] if etype in [35020, 35138]: # LLDP TLV - lldp = ofp_tcpip_parser.get_lldp(packet[start:]) + lldp = gen.tcpip.get_lldp(packet[start:]) if len(lldp) is 0: print 'LLDP Packet MalFormed' else: # Support for FSFW/Proxy - ofp_fsfw_v10.support_fsfw(print_options, lldp) - ofp_prints_v10.print_packetInOut_lldp(of_xid, lldp) + gen.proxies.support_fsfw(print_options, lldp) + of10.prints.print_packetInOut_lldp(of_xid, lldp) return 1 @@ -419,8 +423,8 @@ def _parse_OFMatch(packet, h_size): of_match = packet[h_size:h_size+40] ofm = unpack('!LH6s6sHBBHBBHLLHH', of_match) wildcard = ofm[0] - dl_src = ofp_prints_v10.eth_addr(ofm[2]) - dl_dst = ofp_prints_v10.eth_addr(ofm[3]) + dl_src = of10.prints.eth_addr(ofm[2]) + dl_dst = of10.prints.eth_addr(ofm[3]) nw_src = get_ip_from_long(ofm[11]) nw_dst = get_ip_from_long(ofm[12]) etype = hex(ofm[7]) @@ -558,9 +562,9 @@ def _parse_OFAction(of_xid, packet, start, ofactions=[]): total_length = 4 ofa_action_payload = packet[start:start + 4] - ofa_temp = ofp_prints_v10.print_ofp_action(of_xid, ofa_type, - ofa_length, - ofa_action_payload) + ofa_temp = of10.prints.print_ofp_action(of_xid, ofa_type, + ofa_length, + ofa_action_payload) # Print OVS format ofactions.append(ofa_temp) @@ -576,10 +580,10 @@ def _parse_OFAction(of_xid, packet, start, ofactions=[]): def parse_FlowMod(packet, h_size, of_xid, print_options): ofmatch = _parse_OFMatch(packet, h_size) - ofp_prints_v10.print_ofp_match(of_xid, ofmatch) + of10.prints.print_ofp_match(of_xid, ofmatch) ofbody = _parse_OFBody(packet, h_size) - ofp_prints_v10.print_ofp_body(of_xid, ofbody) + of10.prints.print_ofp_body(of_xid, ofbody) if ofbody['command'] == 3: ovs_command = 'del-flows' @@ -600,8 +604,8 @@ def parse_FlowMod(packet, h_size, of_xid, print_options): ofactions = _parse_OFAction(of_xid, packet, start, ofactions) if print_options['ovs'] == 1: - ofp_prints_v10.print_ofp_ovs(print_options, ofmatch, ofactions, - ovs_command, ofbody['priority']) + of10.prints.print_ofp_ovs(print_options, ofmatch, ofactions, + ovs_command, ofbody['priority']) return 1 @@ -617,7 +621,7 @@ def parse_PortMod(packet, h_size, of_xid): portMod = {'port': pmod[0], 'hw_addr': pmod[1], 'config': config, 'mask': mask, 'advertise': advertise, 'pad': pmod[5]} - ofp_prints_v10.print_PortMod(of_xid, portMod) + of10.prints.print_PortMod(of_xid, portMod) return 1 @@ -639,7 +643,7 @@ def parse_StatsReq(packet, h_size, of_xid): if stat_type == 0: # Description # No extra fields - ofp_prints_v10.print_ofp_statReqDesc(of_xid, stat_type) + of10.prints.print_ofp_statReqDesc(of_xid, stat_type) elif stat_type == 1 or stat_type == 2: # Flow(1) or Aggregate(2) @@ -651,13 +655,13 @@ def parse_StatsReq(packet, h_size, of_xid): table_id = ofstat[0] pad = ofstat[1] out_port = ofstat[2] - ofp_prints_v10.print_ofp_statReqFlowAggregate(of_xid, stat_type, - of_match, table_id, pad, - out_port) + of10.prints.print_ofp_statReqFlowAggregate(of_xid, stat_type, + of_match, table_id, pad, + out_port) elif stat_type == 3: # Table # No extra fields - ofp_prints_v10.print_ofp_statReqTable(of_xid, stat_type) + of10.prints.print_ofp_statReqTable(of_xid, stat_type) elif stat_type == 4: # Port @@ -666,8 +670,8 @@ def parse_StatsReq(packet, h_size, of_xid): ofstat = unpack('!H6s', of_stat_req) port_number = ofstat[0] pad = ofstat[1] - ofp_prints_v10.print_ofp_statReqPort(of_xid, stat_type, port_number, - pad) + of10.prints.print_ofp_statReqPort(of_xid, stat_type, port_number, + pad) elif stat_type == 5: # Queue @@ -677,15 +681,15 @@ def parse_StatsReq(packet, h_size, of_xid): port_number = ofstat[0] pad = ofstat[1] queue_id = ofstat[2] - ofp_prints_v10.print_ofp_statReqQueue(of_xid, stat_type, port_number, - pad, queue_id) + of10.prints.print_ofp_statReqQueue(of_xid, stat_type, port_number, + pad, queue_id) elif stat_type == 65535: # Vendor # Fields: vendor_id(32) + data of_stat_req = packet[start:start+4] ofstat = unpack('!L', of_stat_req) vendor_id = ofstat[0] - ofp_prints_v10.print_ofp_statReqVendor(of_xid, stat_type, vendor_id) + of10.prints.print_ofp_statReqVendor(of_xid, stat_type, vendor_id) else: print ('%s StatReq: Unknown Type: %s' % (of_xid, stat_type)) @@ -716,9 +720,9 @@ def parse_StatsRes(packet, h_size, of_xid): sw_desc = desc[2] serial_num = desc[3] dp_desc = desc[4] - ofp_prints_v10.print_ofp_statResDesc(of_xid, stat_type, mfr_desc, - hw_desc, sw_desc, serial_num, - dp_desc) + of10.prints.print_ofp_statResDesc(of_xid, stat_type, mfr_desc, + hw_desc, sw_desc, serial_num, + dp_desc) elif stat_type == 1: # Flow(1) @@ -739,8 +743,8 @@ def parse_StatsRes(packet, h_size, of_xid): 'cookie': flow[6], 'packet_count': flow[7], 'byte_count': flow[8]}) - ofp_prints_v10.print_ofp_statResFlow(of_xid, stat_type, of_match, - res_flow) + of10.prints.print_ofp_statResFlow(of_xid, stat_type, of_match, + res_flow) # Process Actions[] end = res_flow['length'] - (4 + 40 + 44) actions = packet[start+88:start+88+end] @@ -756,7 +760,7 @@ def parse_StatsRes(packet, h_size, of_xid): flow = unpack('!QQLL', flow_raw) res_flow = {'packet_count': flow[0], 'byte_count': flow[1], 'flow_count': flow[2], 'pad': flow[3]} - ofp_prints_v10.print_ofp_statResAggregate(of_xid, stat_type, res_flow) + of10.prints.print_ofp_statResAggregate(of_xid, stat_type, res_flow) elif stat_type == 3: # Table @@ -769,7 +773,7 @@ def parse_StatsRes(packet, h_size, of_xid): 'wildcards': flow[3], 'max_entries': flow[4], 'active_count': flow[5], 'lookup_count': flow[6], 'matched_count': flow[7]} - ofp_prints_v10.print_ofp_statResTable(of_xid, stat_type, res_flow) + of10.prints.print_ofp_statResTable(of_xid, stat_type, res_flow) elif stat_type == 4: # Port @@ -788,7 +792,7 @@ def parse_StatsRes(packet, h_size, of_xid): 'rx_errors': flow[8], 'tx_errors': flow[9], 'rx_frame_err': flow[10], 'rx_over_err': flow[11], 'rx_crc_err': flow[12], 'collisions': flow[13]} - ofp_prints_v10.print_ofp_statResPort(of_xid, stat_type, res_flow) + of10.prints.print_ofp_statResPort(of_xid, stat_type, res_flow) count = count - 104 start = start + 104 @@ -804,7 +808,7 @@ def parse_StatsRes(packet, h_size, of_xid): res_flow = {'length': flow[0], 'pad': flow[1], 'queue_id': flow[2], 'tx_bytes': flow[3], 'tx_packets': flow[4], 'tx_errors': flow[5]} - ofp_prints_v10.print_ofp_statResQueue(of_xid, stat_type, res_flow) + of10.prints.print_ofp_statResQueue(of_xid, stat_type, res_flow) count = count - 32 start = start + 32 else: @@ -817,7 +821,7 @@ def parse_StatsRes(packet, h_size, of_xid): flow_raw = packet[start:start+4] flow = unpack('!L', flow_raw) res_flow = {'vendor_id': flow[0]} - ofp_prints_v10.print_ofp_statResVendor(of_xid, stat_type, res_flow) + of10.prints.print_ofp_statResVendor(of_xid, stat_type, res_flow) start = start + 4 data = [] @@ -827,7 +831,7 @@ def parse_StatsRes(packet, h_size, of_xid): flow = unpack('!B', flow_raw) data.append(str(flow[0])) start = start + 1 - ofp_prints_v10.print_ofp_statResVendorData(of_xid, ''.join(data)) + of10.prints.print_ofp_statResVendorData(of_xid, ''.join(data)) else: print ('%s StatRes: Unknown Type: %s' % (of_xid, stat_type)) @@ -837,13 +841,13 @@ def parse_StatsRes(packet, h_size, of_xid): # ********************** BarrierReq *********************** def parse_BarrierReq(packet, h_size, of_xid): - ofp_prints_v10.print_of_BarrierReq(of_xid) + of10.prints.print_of_BarrierReq(of_xid) return 1 # ********************** BarrierRes *********************** def parse_BarrierRes(packet, h_size, of_xid): - ofp_prints_v10.print_of_BarrierReply(of_xid) + of10.prints.print_of_BarrierReply(of_xid) return 1 @@ -852,7 +856,7 @@ def parse_QueueGetConfigReq(packet, h_size, of_xid): queue_raw = packet[h_size:h_size+4] queue = unpack('!HH', queue_raw) queueConfReq = {'port': queue[0], 'pad': queue[1]} - ofp_prints_v10.print_queueReq(of_xid, queueConfReq) + of10.prints.print_queueReq(of_xid, queueConfReq) return 1 @@ -862,7 +866,7 @@ def parse_QueueGetConfigRes(packet, h_size, of_xid): queue = unpack('!H6s', queue_raw) queueConfRes = {'port': queue[0], 'pad': queue[1]} - ofp_prints_v10.print_queueRes(of_xid, queueConfRes) + of10.prints.print_queueRes(of_xid, queueConfRes) start = h_size + 8 while (packet[start:] > 0): @@ -871,7 +875,7 @@ def parse_QueueGetConfigRes(packet, h_size, of_xid): queue_raw = packet[start:start+8] queue = unpack('!LHH', queue_raw) queues = {'queue_id': queue[0], 'length': queue[1], 'pad': queue[2]} - ofp_prints_v10.print_queues(of_xid, queues) + of10.prints.print_queues(of_xid, queues) q_start = start + 8 @@ -884,7 +888,7 @@ def parse_QueueGetConfigRes(packet, h_size, of_xid): prop = unpack('!HHLH6s', prop_raw) properties = {'type': prop[0], 'length': prop[1], 'pad': prop[2], 'rate': prop[3], 'pad2': prop[4]} - ofp_prints_v10.print_queueRes_properties(of_xid, properties) + of10.prints.print_queueRes_properties(of_xid, properties) start = start + queues['length'] diff --git a/ofp_prints_v10.py b/of10/prints.py similarity index 72% rename from ofp_prints_v10.py rename to of10/prints.py index 7ddb5de..ce082ec 100644 --- a/ofp_prints_v10.py +++ b/of10/prints.py @@ -1,133 +1,29 @@ -from termcolor import colored -import ofp_dissector_v10 -import ofp_dissector_v13 -from ofp_parser_v10 import get_action, get_ip_from_long -import ofp_cli # NO_COLOR variable -import ofp_fsfw_v10 +''' + Prints for OpenFlow 1.0 only +''' + +import of10.dissector +import of10.parser +import gen.prints +#from gen.prints import * +# red, green, eth_addr, datapath_id +# from prints import print_layer2, print_vlan def red(string): - if ofp_cli.NO_COLOR is True: - return string - return colored(string, 'red') + return gen.prints.red(string) def green(string): - if ofp_cli.NO_COLOR is True: - return string - return colored(string, 'green') - - -def blue(string): - if ofp_cli.NO_COLOR is True: - return string - return colored(string, 'blue') - - -def yellow(string): - if ofp_cli.NO_COLOR is True: - return string - return colored(string, 'yellow') - - -def cyan(string): - if ofp_cli.NO_COLOR is True: - return string - return colored(string, 'cyan') - - -def eth_addr(a): - mac = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" % (ord(a[0]), ord(a[1]), ord(a[2]), - ord(a[3]), ord(a[4]), ord(a[5])) - return mac - - -def datapath_id(a): - dpid = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" % (ord(a[0]), ord(a[1]), - ord(a[2]), ord(a[3]), - ord(a[4]), ord(a[5]), - ord(a[6]), ord(a[7])) - return dpid - - -def print_headers(print_options, date, getlen, caplen, eth, ip, tcp): - if print_options['min'] == 1: - print_minimal(date, getlen, ip, tcp) - else: - print_layer1(date, getlen, caplen) - print_layer2(eth) - print_layer3(ip) - print_tcp(tcp) - + return gen.prints.green(string) -def print_minimal(date, getlen, ip, tcp): - string = '%s %s:%s -> %s:%s Size: %s Bytes' - source = ofp_fsfw_v10.get_ip_name(ip['s_addr'], tcp['source_port']) - dest = ofp_fsfw_v10.get_ip_name(ip['d_addr'], tcp['dest_port']) +def eth_addr(string): + return gen.prints.eth_addr(string) - print string % (date, cyan(source), cyan(tcp['source_port']), - cyan(dest), cyan(tcp['dest_port']), getlen) - - -def print_layer1(date, getlen, caplen): - print ('%s: captured %d bytes, truncated to %d bytes' % - (date, getlen, caplen)) - - -def print_layer2(eth): - print ('Ethernet: Destination MAC: %s Source MAC: %s Protocol: %s' % - (eth_addr(eth['dst_mac']), eth_addr(eth['src_mac']), - red(hex(eth['protocol'])))) - - -def print_vlan(vlan): - print ('Prio: %s CFI: %s VID: %s' % - (vlan['prio'], vlan['cfi'], red(vlan['vid']))) - - -def print_arp(arp): - print ('ARP: Hardware Type: %s Protocol Type: %s ' - 'HW Length: %s Prot Length: %s Opcode: %s ' - '\nARP: Source MAC: %s Source IP: %s Destination MAC: %s ' - 'Destination IP: %s' - % (arp['hw_type'], arp['prot_type'], arp['hw_len'], arp['prot_len'], - arp['opcode'], - eth_addr(arp['src_mac']), get_ip_from_long(arp['src_ip']), - eth_addr(arp['dst_mac']), get_ip_from_long(arp['dst_ip']))) - - -def print_layer3(ip): - print (('IP Version: %d IP Header Length: %d TTL: %d Protocol: %d ' - 'Source Address: %s Destination Address: %s') % - (ip['version'], (ip['ihl'] * 4), ip['ttl'], ip['protocol'], - blue(ip['s_addr']), blue(ip['d_addr']))) - - -def print_tcp(tcp): - print ('TCP Source Port: %s Dest Port: %s Sequence Number: %s ' - 'Acknowledgement: %s TCP header length: %s Flags: (CWR: %s ' - 'ECE: %s URG: %s ACK: %s PSH: %s RST: %s SYN: %s FYN: %s' % - (tcp['source_port'], tcp['dest_port'], tcp['sequence'], - tcp['acknowledgement'], (tcp['length']), tcp['flag_cwr'], - tcp['flag_ece'], tcp['flag_urg'], tcp['flag_ack'], tcp['flag_psh'], - tcp['flag_rst'], tcp['flag_syn'], tcp['flag_fyn'])) - - -def print_openflow_header(of): - version = ofp_dissector_v10.get_ofp_version(of['version']) - name_version = '%s(%s)' % (version, of['version']) - if version == '1.0': - name = ofp_dissector_v10.get_ofp_type(of['type']) - name_type = '%s(%s)' % (name, of['type']) - elif version == '1.3': - name = ofp_dissector_v13.get_ofp_type(of['type']) - name_type = '%s(%s)' % (name, of['type']) - else: - name_type = '%s' % (of['type']) - print ('OpenFlow Version: %s Type: %s Length: %s XID: %s' % - (name_version, yellow(name_type), of['length'], red(of['xid']))) +def datapath_id(string): + return gen.prints.datapath_id(string) def print_of_hello(of_xid): @@ -158,11 +54,11 @@ def print_of_feature_res(of_xid, f_res): def print_of_feature_res_caps_and_actions(of_xid, caps, actions): print ('%s FeatureRes - Capabilities:' % of_xid), for i in caps: - print ofp_dissector_v10.get_feature_res_capabilities(i), + print of10.dissector.get_feature_res_capabilities(i), print print ('%s FeatureRes - Actions:' % of_xid), for i in actions: - print ofp_dissector_v10.get_feature_res_actions(i), + print of10.dissector.get_feature_res_actions(i), print @@ -179,42 +75,42 @@ def print_of_feature_res_ports(of_xid, ports): print ('%s FeatureRes - config:' % of_xid), printed = False for i in ports['config']: - print ofp_dissector_v10.get_phy_config(i), + print of10.dissector.get_phy_config(i), printed = True else: printed = _dont_print_0(printed) print print ('%s FeatureRes - state:' % of_xid), for i in ports['state']: - print ofp_dissector_v10.get_phy_state(i), + print of10.dissector.get_phy_state(i), printed = True else: printed = _dont_print_0(printed) print print ('%s FeatureRes - curr:' % of_xid), for i in ports['curr']: - print ofp_dissector_v10.get_phy_feature(i), + print of10.dissector.get_phy_feature(i), printed = True else: printed = _dont_print_0(printed) print print ('%s FeatureRes - advertised:' % of_xid), for i in ports['advertised']: - print ofp_dissector_v10.get_phy_feature(i), + print of10.dissector.get_phy_feature(i), printed = True else: printed = _dont_print_0(printed) print print ('%s FeatureRes - supported:' % of_xid), for i in ports['supported']: - print ofp_dissector_v10.get_phy_feature(i), + print of10.dissector.get_phy_feature(i), printed = True else: printed = _dont_print_0(printed) print print ('%s FeatureRes - peer:' % of_xid), for i in ports['peer']: - print ofp_dissector_v10.get_phy_feature(i), + print of10.dissector.get_phy_feature(i), printed = True else: printed = _dont_print_0(printed) @@ -234,8 +130,8 @@ def print_ofp_match(xid, ofmatch): def print_ofp_body(xid, ofbody): string = ('%s OpenFlow Body - Cookie: %s Command: %s Idle/Hard Timeouts: ' '%s/%s Priority: %s Buffer ID: %s Out Port: %s Flags: %s') - command = green(ofp_dissector_v10.get_ofp_command(ofbody['command'])) - flags = green(ofp_dissector_v10.get_ofp_flags(ofbody['flags'])) + command = green(of10.dissector.get_ofp_command(ofbody['command'])) + flags = green(of10.dissector.get_ofp_flags(ofbody['flags'])) print string % (xid, ofbody['cookie'], command, ofbody['idle_timeout'], ofbody['hard_timeout'], ofbody['priority'], @@ -256,22 +152,22 @@ def print_ofp_flow_removed(xid, ofrem): def print_ofp_action(xid, action_type, length, payload): if action_type == 0: - port, max_len = get_action(action_type, length, payload) + port, max_len = of10.parser.get_action(action_type, length, payload) - port = ofp_dissector_v10.get_phy_port_id(port) + port = of10.dissector.get_phy_port_id(port) print ('%s OpenFlow Action - Type: %s Length: %s Port: %s ' 'Max Length: %s' % (xid, green('OUTPUT'), length, green(port), max_len)) return 'output:' + port elif action_type == 1: - vlan, pad = get_action(action_type, length, payload) + vlan, pad = of10.parser.get_action(action_type, length, payload) print ('%s OpenFlow Action - Type: %s Length: %s VLAN ID: %s Pad: %s' % (xid, green('SetVLANID'), length, green(str(vlan)), pad)) return 'mod_vlan_vid:' + str(vlan) elif action_type == 2: - vlan_pc, pad = get_action(action_type, length, payload) + vlan_pc, pad = of10.parser.get_action(action_type, length, payload) print ('%s OpenFlow Action - Type: %s Length: %s VLAN PCP: %s Pad: %s' % (xid, green('SetVLANPCP'), length, green(str(vlan_pc)), pad)) return 'mod_vlan_pcp:' + str(vlan_pc) @@ -282,51 +178,52 @@ def print_ofp_action(xid, action_type, length, payload): return 'strip_vlan' elif action_type == 4: - setDLSrc, pad = get_action(action_type, length, payload) + setDLSrc, pad = of10.parser.get_action(action_type, length, payload) print ('%s OpenFlow Action - Type: %s Length: %s SetDLSrc: %s Pad: %s' % (xid, green('SetDLSrc'), length, green(str(eth_addr(setDLSrc))), pad)) return 'mod_dl_src:' + str(eth_addr(setDLSrc)) elif action_type == 5: - setDLDst, pad = get_action(action_type, length, payload) + setDLDst, pad = of10.parser.get_action(action_type, length, payload) print ('%s OpenFlow Action - Type: %s Length: %s SetDLDst: %s Pad: %s' % (xid, green('SetDLDst'), length, green(str(eth_addr(setDLDst))), pad)) return 'mod_dl_dst:' + str(eth_addr(setDLDst)) elif action_type == 6: - nw_addr = get_action(action_type, length, payload) + nw_addr = of10.parser.get_action(action_type, length, payload) print ('%s OpenFlow Action - Type: %s Length: %s SetNWSrc: %s' % (xid, green('SetNWSrc'), length, green(str(nw_addr)))) return 'mod_nw_src:' + str(nw_addr) elif action_type == 7: - nw_addr = get_action(action_type, length, payload) + nw_addr = of10.parser.get_action(action_type, length, payload) print ('%s OpenFlow Action - Type: %s Length: %s SetNWDst: %s' % (xid, green('SetNWDst'), length, green(str(nw_addr)))) return 'mod_nw_src:' + str(nw_addr) elif action_type == 8: - nw_tos, pad = get_action(action_type, length, payload) + nw_tos, pad = of10.parser.get_action(action_type, length, payload) print ('%s OpenFlow Action - Type: %s Length: %s SetNWTos: %s Pad: %s' % (xid, green('SetNWTos'), length, green(str(nw_tos)), pad)) return 'mod_nw_tos:' + str(nw_tos) elif action_type == 9: - port, pad = get_action(action_type, length, payload) + port, pad = of10.parser.get_action(action_type, length, payload) print ('%s OpenFlow Action - Type: %s Length: %s SetTPSrc: %s Pad: %s' % (xid, green('SetTPSrc'), length, green(str(port)), pad)) return 'mod_tp_src:' + str(port) elif action_type == int('a', 16): - port, pad = get_action(action_type, length, payload) + port, pad = of10.parser.get_action(action_type, length, payload) print ('%s OpenFlow Action - Type: %s Length: %s SetTPDst: %s Pad: %s' % (xid, green('SetTPDst'), length, green(str(port)), pad)) return 'mod_tp_dst:' + str(port) elif action_type == int('b', 16): - port, pad, queue_id = get_action(action_type, length, payload) + port, pad, queue_id = of10.parser.get_action(action_type, length, + payload) print (('%s OpenFlow Action - Type: %s Length: %s Enqueue: %s Pad: %s' ' Queue: %s') % (xid, green('Enqueue'), length, green(str(port)), pad, @@ -334,7 +231,7 @@ def print_ofp_action(xid, action_type, length, payload): return 'set_queue:' + str(queue_id) elif action_type == int('ffff', 16): - vendor = get_action(action_type, length, payload) + vendor = of10.parser.get_action(action_type, length, payload) print ('%s OpenFlow Action - Type: %s Length: %s Vendor: %s' % (xid, green('VENDOR'), length, green(str(vendor)))) return 'VendorType' @@ -371,7 +268,7 @@ def _print_portMod_config_mask(of_xid, array, name): print ('%s PortMod %s:' % (of_xid, name)), printed = False for i in array[name]: - print ofp_dissector_v10.get_phy_config(i), + print of10.dissector.get_phy_config(i), printed = True else: printed = _dont_print_0(printed) @@ -396,7 +293,7 @@ def print_of_BarrierReply(of_xid): def print_of_vendor(of_vendor, of_xid): - vendor = ofp_dissector_v10.get_ofp_vendor(of_vendor) + vendor = of10.dissector.get_ofp_vendor(of_vendor) print ('%s OpenFlow Vendor: %s' % (of_xid, vendor)) @@ -538,12 +435,12 @@ def print_portStatus(of_xid, reason, pad): def print_packetInOut_layer2(of_xid, eth): print ('%s' % of_xid), - print_layer2(eth) + gen.prints.print_layer2(eth) def print_packetInOut_vlan(of_xid, vlan): print ('%s Ethernet:' % of_xid), - print_vlan(vlan) + gen.prints.print_vlan(vlan) def print_ofp_packetIn(of_xid, packetIn): @@ -569,7 +466,7 @@ def print_packetInOut_lldp(of_xid, lldp): def print_ofp_packetOut(of_xid, packetOut): print ('%s PacketOut: buffer_id: %s in_port: %s actions_len: %s' % (of_xid, hex(packetOut['buffer_id']), - green(ofp_dissector_v10.get_phy_port_id(packetOut['in_port'])), + green(of10.dissector.get_phy_port_id(packetOut['in_port'])), packetOut['actions_len'])) diff --git a/ofp_vendors_v10.py b/of10/vendors.py similarity index 100% rename from ofp_vendors_v10.py rename to of10/vendors.py diff --git a/of13/__init__.py b/of13/__init__.py new file mode 100644 index 0000000..2c0e3c2 --- /dev/null +++ b/of13/__init__.py @@ -0,0 +1,12 @@ +import gen.cli +import gen.prints +import gen.proxies +import gen.tcpip +import gen.termcolor +import of10.dissector +import of10.parser +import of10.prints +import of10.vendors +import of10.dissector +import of13.parser +import of13.prints diff --git a/of13/dissector.py b/of13/dissector.py new file mode 100644 index 0000000..f83a1aa --- /dev/null +++ b/of13/dissector.py @@ -0,0 +1,223 @@ +''' + OpenFlow 1.3 Types and Codes +''' + + +def get_ofp_type(of_type): + of_types = {0: 'Hello', + 1: 'Error', + 2: 'EchoReq', + 3: 'EchoRes', + 4: 'Experimenter', + 5: 'FeatureReq', + 6: 'FeatureRes', + 7: 'GetConfigReq', + 8: 'GetConfigRes', + 9: 'SetConfig', + 10: 'PacketIn', + 11: 'FlowRemoved', + 12: 'PortStatus', + 13: 'PacketOut', + 14: 'FlowMod', + 15: 'GroupMod', + 16: 'PortMod', + 17: 'TableMod', + 18: 'MultipartReq', + 19: 'MultipartRes', + 20: 'BarrierReq', + 21: 'BarrierRes', + 22: 'QueueGetConfigReq', + 23: 'QueueGetConfigRes', + 24: 'RoleReq', + 25: 'RoleRes', + 26: 'GetAsyncReq', + 27: 'GetAsyncRes', + 28: 'SetAsync', + 29: 'MeterMod'} + try: + return of_types[of_type] + except: + return 'UnknownType(%s)' % of_type + + +def get_ofp_error(error_type, code): + errors_types = {} + codes = {} + + # Starts with an Error + errors_types[error_type] = 'UnknownType(%s)' % error_type + codes[code] = 'UnknownCode(%s)' % code + + # Error Types + if error_type in range(0, 14) or error_type == 65535: + errors_types = {0: 'Hello_Failed(0)', + 1: 'Bad_Request(1)', + 2: 'Bad_Action(2)', + 3: 'Bad_Instruction(3)', + 4: 'Bad_Match(4)', + 5: 'Flow_Mod_Failed(5)', + 6: 'Group_Mod_Failed(6)', + 7: 'Port_Mod_Failed(7)', + 8: 'Table_Mod_Failed(8)', + 9: 'Queue_Op_Failed(9)', + 10: 'Switch_Config_Failed(10)', + 11: 'Role_Request_Failed(11)', + 12: 'Meter_Mod_Failed(12)', + 13: 'Table_Features_Failed(13)', + 65535: 'Experimenter(0xffff)'} + + # Error Codes per Error Type + if error_type == 0: + if code in range(0, 2): + codes = {0: 'Incompatible(0)', + 1: 'EPerm(1)'} + + elif error_type == 1: + if code in range(0, 14): + codes = {0: 'Bad_Version(0)', + 1: 'Bad_Type(1)', + 2: 'Multipart(2)', + 3: 'Bad_Experimenter(3)', + 4: 'Bad_Exp_Type(4)', + 5: 'EPerm(5)', + 6: 'Bad_Len(6)', + 7: 'Buffer_Empty(7)', + 8: 'Buffer_Unknown(8)', + 9: 'Bad_Table_Id(9)', + 10: 'Is_Slave(10)', + 11: 'Bad_Port(11)', + 12: 'Bad_Packet(12)', + 13: 'Multipart_Buffer_Overflow(13)'} + + elif error_type == 2: + if code in range(0, 16): + codes = {0: 'Bad_Type(0)', + 1: 'Bad_Len(1)', + 2: 'Bad_Experimenter(2)', + 3: 'Bad_Exp_Type(3)', + 4: 'Bad_Out_Port(4)', + 5: 'Bad_Argument(5)', + 6: 'EPerm(6)', + 7: 'Too_Many(7)', + 8: 'Bad_Queue(8)', + 9: 'Bad_Out_Group(9)', + 10: 'Match_Inconsistent(10)', + 11: 'Unsupported_Order(11)', + 12: 'Bad_Tag(12)', + 13: 'Bad_Set_Type(13)', + 14: 'Bad_Set_Len(14)', + 15: 'Bad_Set_Argument(15)'} + + elif error_type == 3: + if code in range(0, 9): + codes = {0: 'Unknown_Inst(0)', + 1: 'Unsup_Inst(1)', + 2: 'Bad_Table_Id(2)', + 3: 'Unsup_Metadata(3)', + 4: 'Unsup_Metadata_Mask(4)', + 5: 'Bad_Experimenter(5)', + 6: 'Bad_Exp_Type(6)', + 7: 'Bad_Len(7)', + 8: 'Eperm(8)'} + + elif error_type == 4: + if code in range(0, 12): + codes = {0: 'Bad_Type(0)', + 1: 'Bad_Len(1)', + 2: 'Bad_Tag(2)', + 3: 'Bad_DL_Addr_Mask(3)', + 4: 'Bad_NW_Addr_Mask(4)', + 5: 'Bad_Wildcards(5)', + 6: 'Bad_Field(6)', + 7: 'Bad_Value(7)', + 8: 'Bad_Mask(8)', + 9: 'Bad_Prereq(9)', + 10: 'Dup_Field(10)', + 11: 'Eperm(11)'} + + elif error_type == 5: + if code in range(0, 8): + codes = {0: 'Unknown(0)', + 1: 'Table_Full(1)', + 2: 'Bad_Table_Id(2)', + 3: 'Overlap(3)', + 4: 'EPerm(4)', + 5: 'Bad_Timeout(5)', + 6: 'Bad_Command(6)', + 7: 'Bad_Flags(7)'} + + elif error_type == 6: + if code in range(0, 15): + codes = {0: 'Group_Exists(0)', + 1: 'Invalid_Group(1)', + 2: 'Weight_Unsupported(2)', + 3: 'Out_Of_Groups(3)', + 4: 'Out_Of_Buckets(4)', + 5: 'Chaining_Unsupported(5)', + 6: 'Watch_Unsupported(6)', + 7: 'Loop(7)', + 8: 'Unknown_Group(8)', + 9: 'Chained_Group(9)', + 10: 'Bad_Type(10)', + 11: 'Bad_Command(11)', + 12: 'Bad_Bucket(12)', + 13: 'Bad_Watch(13)', + 14: 'Eperm(14)'} + + elif error_type == 7: + if code in range(0, 5): + codes = {0: 'Bad_Port(0)', + 1: 'Bad_Hw_Addr(1)', + 2: 'Bad_Config(2)', + 3: 'Bad_Advertise(3)', + 4: 'Eperm(4)'} + + elif error_type == 8: + if code in range(0, 3): + codes = {0: 'Bad_Table(0)', + 1: 'Bad_Config(1)', + 2: 'Eperm(2)'} + + elif error_type == 9: + if code in range(0, 3): + codes = {0: 'Bad_Port(0)', + 1: 'Bad_Queue(1)', + 2: 'Eperm(2)'} + + elif error_type == int('A', 16): + if code in range(0, 3): + codes = {0: 'Bad_Flags(0)', + 1: 'Bad_Len(1)', + 2: 'Eperm(2)'} + + elif error_type == int('B', 16): + if code in range(0, 3): + codes = {0: 'Stale(0)', + 1: 'Unsupported(1)', + 2: 'Bad_Role(2)'} + + elif error_type == int('C', 16): + if code in range(0, 12): + codes = {0: 'Unknown(0)', + 1: 'Meter_Exists(1)', + 2: 'Invalid_Meter(2)', + 3: 'Unknown_Meter(3)', + 4: 'Bad_Command(4)', + 5: 'Bad_Flags(5)', + 6: 'Bad_Rate(6)', + 7: 'Bad_Burst(7)', + 8: 'Bad_Band(8)', + 9: 'Bad_Band_Value(9)', + 10: 'Out_Of_Meters(10)', + 11: 'Out_of_Bands(11)'} + + elif error_type == int('D', 16): + if code in range(0, 6): + codes = {0: 'Bad_Table(0)', + 1: 'Bad_Metadata(1)', + 2: 'Bad_Type(2)', + 3: 'Bad_Length(3)', + 4: 'Bad_Argument(4)', + 5: 'Eperm(5)'} + + return errors_types[error_type], codes[code] diff --git a/ofp_parser_v13.py b/of13/parser.py similarity index 89% rename from ofp_parser_v13.py rename to of13/parser.py index 64f535c..84173db 100644 --- a/ofp_parser_v13.py +++ b/of13/parser.py @@ -1,6 +1,5 @@ from struct import unpack -# import ofp_dissector_v13 -import ofp_prints_v13 +import of13.prints # import socket @@ -76,7 +75,7 @@ def process_ofp_type13(of_type, packet, h_size, of_xid, print_options, def parse_Hello(packet, h_size, of_xid): def process_bitmap(of_xid, bitmap): - ofp_prints_v13.print_hello_bitmap(of_xid, bitmap) + of13.prints.print_hello_bitmap(of_xid, bitmap) start = h_size count = 0 @@ -85,7 +84,7 @@ def process_bitmap(of_xid, bitmap): count += 1 elem_raw = packet[start:start+4] el_type, el_length = unpack('!HH', elem_raw) - ofp_prints_v13.print_hello_elememnts(of_xid, el_type, el_length, count) + of13.prints.print_hello_elememnts(of_xid, el_type, el_length, count) bitmaps = packet[start+4:start+el_length] start_bit = 0 @@ -103,26 +102,26 @@ def process_bitmap(of_xid, bitmap): # ************** Error ***************** def parse_Error(packet, h_size, of_xid): - # of_error = packet[h_size:h_size+4] - # ofe = unpack('!HH', of_error) - # ofe_type = ofe[0] - # ofe_code = ofe[1] + of_error = packet[h_size:h_size+4] + ofe = unpack('!HH', of_error) + ofe_type = ofe[0] + ofe_code = ofe[1] - # nameCode, typeCode = ofp_dissector_v10.get_ofp_error(ofe_type, ofe_code) - # ofp_prints_v10.print_of_error(of_xid, nameCode, typeCode) - return 0 + nameCode, typeCode = of13.dissector.get_ofp_error(ofe_type, ofe_code) + of13.prints.print_of_error(of_xid, nameCode, typeCode) + return 1 # ************ EchoReq ***************** def parse_EchoReq(packet, h_size, of_xid): - # ofp_prints_v10.print_echoreq(of_xid) - return 0 + of13.prints.print_echoreq(of_xid) + return 1 # ************ EchoRes ***************** def parse_EchoRes(packet, h_size, of_xid): - # ofp_prints_v10.print_echores(of_xid) - return 0 + of13.prints.print_echores(of_xid) + return 1 def parse_Experimenter(packet, h_size, of_xid): @@ -190,11 +189,13 @@ def parse_MultipartRes(packet, h_size, of_xid): def parse_BarrierReq(packet, h_size, of_xid): - return 0 + of13.prints.print_of_BarrierReq(of_xid) + return 1 def parse_BarrierRes(packet, h_size, of_xid): - return 0 + of13.prints.print_of_BarrierReply(of_xid) + return 1 def parse_QueueGetConfigReq(packet, h_size, of_xid): diff --git a/of13/prints.py b/of13/prints.py new file mode 100644 index 0000000..fc93a25 --- /dev/null +++ b/of13/prints.py @@ -0,0 +1,35 @@ +import gen.prints + + +def red(string): + return gen.prints.red(string) + + +def print_hello_elememnts(of_xid, el_type, el_length, count): + print ('%s Hello - Element: %s Type: %s Length: %s' % + (of_xid, count, el_type, el_length)) + + +def print_hello_bitmap(of_xid, bitmap): + print ('%s Hello - Bitmap: %s' % (of_xid, hex(bitmap))) + + +def print_of_error(of_xid, nameCode, typeCode): + print ('%s OpenFlow Error - Type: %s Code: %s' % + (of_xid, red(nameCode), red(typeCode))) + + +def print_echoreq(of_xid): + print ('%s OpenFlow Echo Request' % (of_xid)) + + +def print_echores(of_xid): + print ('%s OpenFlow Echo Reply' % (of_xid)) + + +def print_of_BarrierReq(of_xid): + print '%s OpenFlow Barrier Request' % of_xid + + +def print_of_BarrierReply(of_xid): + print '%s OpenFlow Barrier Reply' % of_xid diff --git a/ofp_dissector_v13.py b/ofp_dissector_v13.py deleted file mode 100644 index d44015f..0000000 --- a/ofp_dissector_v13.py +++ /dev/null @@ -1,35 +0,0 @@ -def get_ofp_type(of_type): - of_types = {0: 'Hello', - 1: 'Error', - 2: 'EchoReq', - 3: 'EchoRes', - 4: 'Experimenter', - 5: 'FeatureReq', - 6: 'FeatureRes', - 7: 'GetConfigReq', - 8: 'GetConfigRes', - 9: 'SetConfig', - 10: 'PacketIn', - 11: 'FlowRemoved', - 12: 'PortStatus', - 13: 'PacketOut', - 14: 'FlowMod', - 15: 'GroupMod', - 16: 'PortMod', - 17: 'TableMod', - 18: 'MultipartReq', - 19: 'MiltopartRes', - 20: 'BarrierReq', - 21: 'BarrierRes', - 22: 'QueueGetConfigReq', - 23: 'QueueGetConfigRes', - 24: 'RoleReq', - 25: 'RoleRes', - 26: 'GetAsyncReq', - 27: 'GetAsyncRes', - 28: 'SetAsync', - 29: 'MeterMod'} - try: - return of_types[of_type] - except: - return 'UnknownType(%s)' % of_type diff --git a/ofp_prints_v13.py b/ofp_prints_v13.py deleted file mode 100644 index f895b4b..0000000 --- a/ofp_prints_v13.py +++ /dev/null @@ -1,7 +0,0 @@ -def print_hello_elememnts(of_xid, el_type, el_length, count): - print ('%s Hello - Element: %s Type: %s Length: %s' % - (of_xid, count, el_type, el_length)) - - -def print_hello_bitmap(of_xid, bitmap): - print ('%s Hello - Bitmap: %s' % (of_xid, hex(bitmap))) diff --git a/ofp_sniffer.py b/ofp_sniffer.py index 26e8acc..7e6fdeb 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -15,25 +15,24 @@ Author: Jeronimo Bezerra ''' - import datetime import pcapy import sys -from ofp_prints_v10 import print_headers, print_openflow_header -from ofp_parser_v10 import process_ofp_type -from ofp_tcpip_parser import get_ethernet_frame, get_ip_packet, \ +from gen.tcpip import get_ethernet_frame, get_ip_packet, \ get_tcp_stream, get_openflow_header -import ofp_cli -import ofp_dissector_v10 -import ofp_fsfw_v10 -from ofp_parser_v13 import process_ofp_type13 +import gen.cli +import gen.proxies +from gen.prints import print_headers, print_openflow_header +from of10.parser import process_ofp_type +import of10.dissector +from of13.parser import process_ofp_type13 def main(argv): ''' This is the main function ''' - print_options, infilter, sanitizer, dev, capfile = ofp_cli.get_params(argv) + print_options, infilter, sanitizer, dev, capfile = gen.cli.get_params(argv) try: if len(capfile) > 0: print "Using file %s " % capfile @@ -52,7 +51,7 @@ def main(argv): header.getlen(), header.getcaplen(), print_options, sanitizer) except KeyboardInterrupt: - print ofp_fsfw_v10.close() + print gen.proxies.close() print 'Exiting...' sys.exit(0) except Exception as exception: @@ -72,7 +71,7 @@ def sanitizer_filters(of_header, date, getlen, caplen, header_size, return 0 # OF Versions supported through json file (-F) - name_version = ofp_dissector_v10.get_ofp_version(of_header['version']) + name_version = of10.dissector.get_ofp_version(of_header['version']) supported_versions = [] for version in sanitizer['allowed_of_versions']: supported_versions.append(version) From d925a605061c6109be025fdfea0ddc51c32f2fce Mon Sep 17 00:00:00 2001 From: sdn Date: Sat, 26 Dec 2015 22:10:08 -0500 Subject: [PATCH 03/88] FlowMod almost ready. All matches parsed and tested. Workiing on Instructions now. --- gen/prints.py | 9 ++- of10/parser.py | 8 +- of13/dissector.py | 147 ++++++++++++++++++++++++++++++++++++ of13/parser.py | 187 ++++++++++++++++++++++++++++++++++++++++++++-- of13/prints.py | 108 ++++++++++++++++++++++++++ 5 files changed, 445 insertions(+), 14 deletions(-) diff --git a/gen/prints.py b/gen/prints.py index 24a6b1f..321f348 100644 --- a/gen/prints.py +++ b/gen/prints.py @@ -5,9 +5,10 @@ from gen.termcolor import colored import of10.dissector import of13.dissector -from of10.parser import get_ip_from_long import gen.cli # NO_COLOR variable import gen.proxies +import socket +import struct def red(string): @@ -54,6 +55,10 @@ def datapath_id(a): return dpid +def get_ip_from_long(long_ip): + return (socket.inet_ntoa(struct.pack('!L', long_ip))) + + def print_headers(print_options, date, getlen, caplen, eth, ip, tcp): if print_options['min'] == 1: print_minimal(date, getlen, ip, tcp) @@ -132,5 +137,3 @@ def print_openflow_header(of): print ('OpenFlow Version: %s Type: %s Length: %s XID: %s' % (name_version, yellow(name_type), of['length'], red(of['xid']))) - - diff --git a/of10/parser.py b/of10/parser.py index 58fe28c..522a5cc 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -315,8 +315,8 @@ def parse_FlowRemoved(packet, h_size, of_xid): of10.prints.print_ofp_match(of_xid, ofmatch) of_rem_body = packet[h_size+40:h_size+40+40] - ofrem = unpack('!8sHBBLLHBBQQ', of_rem_body) - cookie = ofrem[0] if not len(ofrem[0]) else 0 + ofrem = unpack('!QHBBLLHBBQQ', of_rem_body) + cookie = ofrem[0] if ofrem[0] > 0 else 0 cookie = '0x' + format(cookie, '02x') reason = of10.dissector.get_flow_removed_reason(ofrem[2]) @@ -469,8 +469,8 @@ def _parse_OFMatch(packet, h_size): def _parse_OFBody(packet, h_size): of_mod_body = packet[h_size+40:h_size+40+24] - ofmod = unpack('!8sHHHHLHH', of_mod_body) - ofmod_cookie = ofmod[0] if not len(ofmod[0]) else 0 + ofmod = unpack('!QHHHHLHH', of_mod_body) + ofmod_cookie = ofmod[0] if ofmod[0] > 0 else 0 ofmod_cookie = '0x' + format(ofmod_cookie, '02x') ofmod_buffer_id = '0x' + format(ofmod[5], '02x') diff --git a/of13/dissector.py b/of13/dissector.py index f83a1aa..f06387b 100644 --- a/of13/dissector.py +++ b/of13/dissector.py @@ -221,3 +221,150 @@ def get_ofp_error(error_type, code): 5: 'Eperm(5)'} return errors_types[error_type], codes[code] + + +def get_feature_res_capabilities(cap): + caps = {1: 'FLOW_STATS(0x1)', + 2: 'TABLE_STATS(0x2)', + 4: 'PORT_STATS(0x4)', + 8: 'GROUP_STATS(0x8)', + 32: 'IP_REASM(0x20)', + 64: 'QUEUE_STATS(0x40)', + 256: 'PORT_BLOCKED(0x100)'} + try: + return caps[cap] + except: + return 'UnknownCapability(%s)' % cap + + +def get_configres_flags(flag): + flags = {0: 'FRAG_NORMAL(0)', + 1: 'FRAG_DROP(1)', + 2: 'FRAG_REASM(2)', + 3: 'FRAG_MASK(3)'} + try: + return flags[flag] + except: + return 'UnknownFlag(%s)' % flag + + +def get_phy_port_id(p_id): + ids = {65280: 'Max(OxFF00)', + 65528: 'InPort(0xFFF8)', + 65529: 'Table(0xFFF9)', + 65530: 'Normal(0xFFFA)', + 65531: 'Flood(0xFFFB)', + 65532: 'All(0xFFFC)', + 65533: 'Controller(0xFFFD)', + 65534: 'Local(0xFFFE)', + 65535: 'Any(0xFFFF)'} + try: + return ids[p_id] + except: + return '%s' % p_id + + +def get_flow_match_fields(value): + values = {0: 'In_Port', + 1: 'In_Phy_Port', + 2: 'Metadata', + 3: 'Eth_Dst', + 4: 'Eth_Src', + 5: 'Eth_Type', + 6: 'Vlan_VID', + 7: 'Vlan_PCP', + 8: 'IP_DSCP', + 9: 'IP_ECN', + 10: 'IP_PROTO', + 11: 'IPv4_Src', + 12: 'IPv4_Dst', + 13: 'TCP_Src', + 14: 'TCP_Dst', + 15: 'UDP_Src', + 16: 'UDP_Dst', + 17: 'SCTP_Src', + 18: 'SCTP_Dst', + 19: 'ICMPv4_Type', + 20: 'ICMPv4_Code', + 21: 'ARP_OP', + 22: 'ARP_SPA', + 23: 'ARP_TPA', + 24: 'ARP_SHA', + 25: 'ARP_THA', + 26: 'IPv6_Src', + 27: 'IPv6_Dst', + 28: 'IPv6_FLabel', + 29: 'ICMPv6_Type', + 30: 'ICMPv6_Code', + 31: 'IPv6_ND_Target', + 32: 'IPv6_ND_SLL', + 33: 'IPv6_ND_TLL', + 34: 'MPLS_Label', + 35: 'MPLS_TC', + 36: 'MPLS_BoS', + 37: 'PBB_ISID', + 38: 'Tunnel_ID', + 39: 'IPv6_EXTHDR'} + + try: + return '%s(%s)' % (values[value], value) + except: + return 'UnknownMatchField(%s)' % value + + +def get_of_command(command): + commands = {0: 'Add(0)', + 1: 'Modify(1)', + 2: 'ModifyStrict(2)', + 3: 'Delete(3)', + 4: 'DeleteStrict(4)'} + try: + return commands[command] + except: + return 'UnknownCommand(%s)' % command + + +def get_of_flags(flag): + flags = {0: 'NoFlagSet(0)', + 1: 'SendFlowRem(0x1)', + 2: 'CheckOverLap(0x2)', + 4: 'ResetCounts(0x4)', + 16: 'NoPacketCounts(0x10)', + 32: 'NoByteCounts(0x20)'} + try: + return flags[flag] + except: + return 'UnknownFlag(%s)' % flag + + +def get_ipv6_extension(bit): + options = {1: 'NO_NEXT', + 2: 'ESP', + 4: 'AUTH', + 8: 'DEST', + 16: 'FRAG', + 32: 'ROUTER', + 64: 'HOP', + 128: 'UNREP', + 256: 'UNSEQ'} + try: + return '%s(%s)' % (options[bit], hex(bit)) + except: + return 'UnknownBit(%s)' % bit + + +def get_instructions(instruction): + instructions = {1: 'GOTO_TABLE', + 2: 'WRITE_METADATA', + 3: 'WRITE_ACTIONS', + 4: 'APPLY_ACTIONS', + 5: 'CLEAR_ACTIONS', + 6: 'METER', + 65535: 'EXPERIMENTER'} + + try: + return '%s(%s)' % (instructions[instruction], instruction) + except: + return 'UnknownInstruction(%s)' % instruction + + diff --git a/of13/parser.py b/of13/parser.py index 84173db..26edf82 100644 --- a/of13/parser.py +++ b/of13/parser.py @@ -1,6 +1,6 @@ from struct import unpack import of13.prints -# import socket +import netaddr def process_ofp_type13(of_type, packet, h_size, of_xid, print_options, @@ -129,23 +129,66 @@ def parse_Experimenter(packet, h_size, of_xid): def parse_FeatureReq(packet, h_size, of_xid): - return 0 + of13.prints.print_of_feature_req(of_xid) + return 1 + + +# ******************** FeatureRes ******************* +def _parse_bitmask(bitmask, array): + size = len(array) + for i in range(0, size): + mask = 2**i + aux = bitmask & mask + if aux == 0: + array.remove(mask) + return array + + +def _parse_capabilities(capabilities): + caps = [1, 2, 4, 8, 16, 32, 64, 128, 256] + return _parse_bitmask(capabilities, caps) def parse_FeatureRes(packet, h_size, of_xid): - return 0 + of_fres = packet[h_size:h_size+24] + ofrs = unpack('!8sLBBHLL', of_fres) + caps = [] + caps = _parse_capabilities(ofrs[5]) + f_res = {'datapath_id': ofrs[0], 'n_buffers': ofrs[1], 'n_tbls': ofrs[2], + 'auxiliary_id': ofrs[3], 'pad': ofrs[4], 'caps': caps, + 'reserved': ofrs[6]} + of13.prints.print_of_feature_res(of_xid, f_res) + return 1 + + +# ***************** GetConfigReq ********************* def parse_GetConfigReq(packet, h_size, of_xid): - return 0 + of13.prints.print_of_getconfig_req(of_xid) + return 1 + + +# ***************** GetConfigRes ******************** +def _parse_SetGetConfig(packet, h_size): + pkt_raw = packet[h_size:h_size+4] + pkt_list = unpack('!HH', pkt_raw) + flag = of13.dissector.get_configres_flags(pkt_list[0]) + miss_send_len = pkt_list[1] + return flag, miss_send_len def parse_GetConfigRes(packet, h_size, of_xid): - return 0 + flag, miss_send_len = _parse_SetGetConfig(packet, h_size) + of13.prints.print_of_getConfigRes(of_xid, flag, miss_send_len) + return 1 +# ******************* SetConfig ********************** def parse_SetConfig(packet, h_size, of_xid): - return 0 + flag, miss_send_len = _parse_SetGetConfig(packet, h_size) + of13.prints.print_of_setConfig(of_xid, flag, miss_send_len) + return 1 def parse_PacketIn(packet, h_size, of_xid, sanitizer): @@ -164,8 +207,138 @@ def parse_PacketOut(packet, h_size, of_xid, sanitizer, print_options): return 0 +# ********************* FlowMod *************************** +def parse_ipv6_extension_header(extensions): + bits = [1, 2, 4, 8, 16, 32, 64, 128, 256] + return _parse_bitmask(extensions, bits) + + +def unpack_oxm_content(content_length, oxm_content, oxm): + if oxm['hasmask'] == 0: + if content_length == 1: + strg = '!B' + elif content_length == 2: + strg = '!H' + elif content_length == 3: + strg = '!3s' + elif content_length == 4: + strg = '!L' + elif content_length == 6: + strg = '!6s' + elif content_length == 8: + strg = '!Q' + elif content_length == 16: + net, host = unpack('!QQ', oxm_content) + ipv6 = ((net << 64) | host) + oxm['value'] = netaddr.IPAddress(ipv6) + return oxm + + oxm['value'] = unpack(strg, oxm_content)[0] + + else: + if content_length == 2: + strg = '!BB' + elif content_length == 4: + strg = '!HH' + elif content_length == 6: + strg = '!3s3s' + elif content_length == 8: + strg = '!LL' + elif content_length == 12: + strg = '!6s6s' + elif content_length == 16: + strg = '!QQ' + elif content_length == 32: + net, host, net1, host1 = unpack('!QQQQ', oxm_content) + host = (net << 64) | host + subnet = (net1 << 64) | host1 + oxm['value'] = netaddr.IPAddress(host) + oxm['mask'] = netaddr.IPAddress(subnet) + return oxm + + oxm['value'], oxm['mask'] = unpack(strg, oxm_content) + return oxm + + +def print_oxm(of_xid, oxm, content_length, x_content): + oxm = unpack_oxm_content(content_length, x_content, oxm) + + of13.prints.print_match_generic(of_xid, oxm) + of13.prints.print_match(oxm) + + +def print_padding(padding): + for i in range(0, padding): + print '\b0', + print + + +def _parse_matches(of_xid, packet, start): + matches_raw = packet[start:start+4] + matches = unpack('!HH', matches_raw) + m_type = matches[0] + m_length = matches[1] + + of13.prints.print_match_type(of_xid, m_type, m_length) + + length_oxm = (m_length - 4) + # Debug + # print 'Length_oxm %s' % length_oxm + padding = (((m_length + 7)/8*8 - m_length)) + + start = start + 4 + oxms = packet[start:start+length_oxm] + start_2 = 0 + + while len(oxms[start_2:]) > 0: + oxm_raw = oxms[start_2:start_2+4] + oxm = unpack('!L', oxm_raw) + x_class = (oxm[0] >> 16) + x_field = ((oxm[0] >> 9) & 0x7f) + x_hasmask = ((oxm[0] >> 8) & 1) + x_length = (oxm[0] & 0xff) + oxm_tlv = {'class': x_class, 'field': x_field, 'hasmask': x_hasmask, + 'length': x_length} + + oxm_content = oxms[start_2+4:start_2+4+x_length] + print_oxm(of_xid, oxm_tlv, len(oxm_content), oxm_content) + start_2 = start_2 + 4 + x_length + + print ('%s Flow Matches - Padding: ' % of_xid), + print_padding(padding) + + # Return offset for Instructions + return start + start_2 + + +def _parse_instructions(of_xid, packet, instructions_start): + print + def parse_FlowMod(packet, h_size, of_xid, print_options): - return 0 + flow_mod_raw = packet[h_size:h_size+40] + ofmod = unpack('!QQBBHHHLLLHH', flow_mod_raw) + + cookie = ofmod[0] if ofmod[0] > 0 else 0 + cookie = '0x' + format(cookie, '02x') + cookie_mask = ofmod[1] if ofmod[1] > 0 else 0 + cookie_mask = '0x' + format(cookie_mask, '02x') + buffer_id = '0x' + format(ofmod[7], '02x') + port = 65535 if ofmod[8] > 65535 else ofmod[8] + + flow_mod = {'cookie': cookie, 'cookie_mask': cookie_mask, + 'table_id': ofmod[2], 'command': ofmod[3], + 'idle_timeout': ofmod[4], 'hard_timeout': ofmod[5], + 'priority': ofmod[6], 'buffer_id': buffer_id, + 'out_port': port, 'out_group': ofmod[9], + 'flags': ofmod[10], 'padding': ofmod[11]} + + of13.prints.print_flow_mod(of_xid, flow_mod) + + instructions_start = _parse_matches(of_xid, packet, h_size+40) + + _parse_instructions(of_xid, packet, instructions_start) + + return 1 def parse_GroupMod(packet, h_size, of_xid): diff --git a/of13/prints.py b/of13/prints.py index fc93a25..4f9a569 100644 --- a/of13/prints.py +++ b/of13/prints.py @@ -1,10 +1,22 @@ +''' + OpenFlow 1.3 prints +''' import gen.prints +import of13.dissector def red(string): return gen.prints.red(string) +def green(string): + return gen.prints.green(string) + + +def datapath_id(string): + return gen.prints.datapath_id(string) + + def print_hello_elememnts(of_xid, el_type, el_length, count): print ('%s Hello - Element: %s Type: %s Length: %s' % (of_xid, count, el_type, el_length)) @@ -27,6 +39,102 @@ def print_echores(of_xid): print ('%s OpenFlow Echo Reply' % (of_xid)) +def print_of_feature_req(of_xid): + print '%s OpenFlow Feature Request' % of_xid + + +def print_of_feature_res(of_xid, f_res): + print '%s OpenFlow Feature Reply' % of_xid + dpid = datapath_id(f_res['datapath_id']) + print ('%s FeatureRes - datapath_id: %s n_buffers: %s n_tbls: %s ' + 'Auxiliary_ID: %s , pad: %s' + % (of_xid, green(dpid), f_res['n_buffers'], f_res['n_tbls'], + f_res['auxiliary_id'], f_res['pad'])) + print ('%s FeatureRes - Capabilities:' % of_xid), + for i in f_res['caps']: + print of13.dissector.get_feature_res_capabilities(i), + print + + +def print_of_getconfig_req(of_xid): + print '%s OpenFlow GetConfig Request' % of_xid + + +def print_of_getConfigRes(of_xid, flag, miss): + print ('%s OpenFlow GetConfigRes - Flag: %s Miss_send_len: %s' % + (of_xid, flag, miss)) + + +def print_of_setConfig(of_xid, flag, miss): + print ('%s OpenFlow SetConfig - Flag: %s Miss_send_len: %s' % + (of_xid, flag, miss)) + + +def print_flow_mod(of_xid, fmod): + string = ('%s FlowMod - Cookie/Mask: %s/%s Table_id: %s Command: %s ' + 'Idle/Hard Timeouts: %s/%s\n%s FlowMod - Priority: %s ' + 'Buffer ID: %s Out Port: %s Out Group: %s Flags: %s Pad: %s') + + command = green(of13.dissector.get_of_command(fmod['command'])) + flags = green(of13.dissector.get_of_flags(fmod['flags'])) + port = green(of13.dissector.get_phy_port_id(fmod['out_port'])) + print string % (of_xid, fmod['cookie'], fmod['cookie_mask'], + fmod['table_id'], command, fmod['idle_timeout'], + fmod['hard_timeout'], of_xid, fmod['priority'], + fmod['buffer_id'], port, fmod['out_group'], + flags, fmod['padding']) + + +def print_match_type(of_xid, m_type, m_length): + print '%s Flow Matches - Type: %s Length: %s' % (of_xid, m_type, m_length) + + +def print_match_generic(of_xid, oxm): + print ('%s OXM Match: Class: %s Length: %s HasMask: %s Field: %s:' % + (of_xid, hex(oxm['class']), oxm['length'], oxm['hasmask'], + green(of13.dissector.get_flow_match_fields(oxm['field'])))), + + +def print_match(oxm): + if oxm['hasmask'] == 0: + if oxm['field'] in [0]: + oxm['value'] = oxm['value'] & 0xffff + oxm['value'] = of13.dissector.get_phy_port_id(oxm['value']) + # DL_DST or DL_SRC + elif oxm['field'] in [3, 4, 24, 25, 32, 33]: + print green(gen.prints.eth_addr(oxm['value'])) + return + # DL_TYPE + elif oxm['field'] in [5]: + oxm['value'] = hex(oxm['value']) + # DL_VLAN + elif oxm['field'] == 6: + if oxm['value'] == 0: + oxm['value'] = 'UNTAGGED' + else: + oxm['value'] = oxm['value'] & 0xfff + # NW_SRC or NW_DST + elif oxm['field'] in [11, 12, 22, 23]: + oxm['value'] = gen.prints.get_ip_from_long(oxm['value']) + # IPv6 Extensions + elif oxm['field'] in [39]: + extensions = of13.parser.parse_ipv6_extension_header(oxm['values']) + for i in extensions: + print green(of13.dissector.get_ipv6_extension(i)), + + print '%s' % green(oxm['value']) + + elif oxm['hasmask'] == 1: + if oxm['field'] in [3, 4, 24, 25]: + oxm['value'] = gen.prints.eth_addr(oxm['value']) + oxm['mask'] = gen.prints.eth_addr(oxm['mask']) + if oxm['field'] in [11, 12, 22, 23]: + oxm['value'] = gen.prints.get_ip_from_long(oxm['value']) + oxm['mask'] = gen.prints.get_ip_from_long(oxm['mask']) + + print ('%s/%s' % (green(oxm['value']), green(oxm['mask']))) + + def print_of_BarrierReq(of_xid): print '%s OpenFlow Barrier Request' % of_xid From 551a5933df1d317ab58bba3099f7d4ea2d151080 Mon Sep 17 00:00:00 2001 From: sdn Date: Sat, 9 Jan 2016 16:04:19 -0500 Subject: [PATCH 04/88] Major change: instead of using standalong and printing as you go through the packet, a Packet object was created with all information. This change will require a lot of code rewriting, working on it. Currently working: - Hello, Echos, Barriers, Error and PacketIn. PacketOut missing the Action field. --- __init__.py | 1 + gen/__init__.py | 1 + gen/cli.py | 3 +- gen/packet.py | 119 ++++++++++++++++++++++++++++++ gen/prints.py | 32 ++++++--- gen/tcpip.py | 28 ++++++++ of10/__init__.py | 1 + of10/dissector.py | 14 ---- of10/parser.py | 179 ++++++++++++++++++++++++++-------------------- of10/prints.py | 145 ++++++++++++++++++++++++------------- of13/__init__.py | 1 + of13/parser.py | 71 ++++++++++++++++-- ofp_sniffer.py | 172 +++++++++----------------------------------- 13 files changed, 474 insertions(+), 293 deletions(-) create mode 100644 gen/packet.py diff --git a/__init__.py b/__init__.py index 2c0e3c2..86f35cb 100644 --- a/__init__.py +++ b/__init__.py @@ -1,4 +1,5 @@ import gen.cli +import gen.packet import gen.prints import gen.proxies import gen.tcpip diff --git a/gen/__init__.py b/gen/__init__.py index 2c0e3c2..86f35cb 100644 --- a/gen/__init__.py +++ b/gen/__init__.py @@ -1,4 +1,5 @@ import gen.cli +import gen.packet import gen.prints import gen.proxies import gen.tcpip diff --git a/gen/cli.py b/gen/cli.py index e5e9a37..a84eb2b 100644 --- a/gen/cli.py +++ b/gen/cli.py @@ -57,7 +57,7 @@ def get_params(argv): print str(err) usage(argv[0]) - print_options = {'min': 1, 'ovs': 0, 'colors': 0} + print_options = {'min': 1, 'ovs': 0, 'colors': 0, 'filters': 0} for option, param in opts: if option in ['-p', '--print']: @@ -93,6 +93,7 @@ def get_params(argv): 'flowMod_logs': {}, 'packetIn_filter': {}} else: + print_options['filters'] = 1 sanitizer = read_sanitizer(sanitizer_file) return print_options, input_filter, sanitizer, dev, captured_file diff --git a/gen/packet.py b/gen/packet.py new file mode 100644 index 0000000..da5c553 --- /dev/null +++ b/gen/packet.py @@ -0,0 +1,119 @@ +from gen.tcpip import get_ethernet_frame, get_ip_packet, get_tcp_stream, \ + get_openflow_header +from of10.parser import process_ofp_type +import gen.prints +import of10.prints + + +IP_PROTOCOL = 8 +TCP_PROTOCOL = 6 +TCP_FLAG_PUSH = 8 +OF_HEADER_SIZE = 8 + + +class Packet: + ''' + Used to save all data about the packet + ''' + def __init__(self, packet, print_options, sanitizer): + self.l1 = {} + self.l2 = {} + self.l3 = {} + self.l4 = {} + self.of_h = {} + self.of_body = {} + self.packet = packet + self.openflow_packet = False + self.offset = 0 + self.print_options = print_options + self.sanitizer = sanitizer + self.printing_seq = [] + + def seq_of_print(self, function): + self.printing_seq.append(function) + + def process_header(self, captured_size, truncated_size, now): + self.process_l1(captured_size, truncated_size, now) + self.process_l2() + if self.l2['protocol'] == IP_PROTOCOL: + self.process_l3() + if self.l3['protocol'] == TCP_PROTOCOL: + self.process_l4() + if self.l4['flag_psh'] == TCP_FLAG_PUSH: + self.openflow_packet = True + + return self.openflow_packet + + def process_l1(self, captured_size, truncated_size, now): + self.l1 = {'caplen': captured_size, 'truncate_len': truncated_size, + 'time': now} + + def process_l2(self): + self.l2 = get_ethernet_frame(self.packet) + self.offset = self.l2['length'] + + def process_l3(self): + self.l3 = get_ip_packet(self.packet, self.offset) + self.offset += self.l3['length'] + + def process_l4(self): + self.l4 = get_tcp_stream(self.packet, self.offset) + self.offset += self.l4['length'] + # Avoid this: + self.print_options['device_ip'] = self.l3['d_addr'] + self.print_options['device_port'] = self.l4['dest_port'] + + def process_openflow_header(self): + self.of_h = get_openflow_header(self.packet, self.offset) + self.offset += 8 + + def get_remaining_bytes(self): + return self.l1['caplen'] - self.offset + + def process_openflow_body(self): + self.remaining_bytes = self.get_remaining_bytes() + self.start = self.offset + while (self.remaining_bytes >= 8): + self.process_openflow_header() + self.remaining_bytes -= self.of_h['length'] + self.start += OF_HEADER_SIZE + self.end = self.of_h['length'] - OF_HEADER_SIZE + self.this_packet = self.packet[self.start:self.start+self.end] + if self.of_h['version'] is 1: + if not process_ofp_type(self): + of10.prints.print_type_unknown(self) + return + else: + self.start += (self.of_h['length'] - OF_HEADER_SIZE) + # remove this: + print + + def prepare_printing(self, string, values): + self.of_body[string] = values + self.seq_of_print(string) + + def print_packet(self): + if not self.check_filters(): + gen.prints.print_headers(self) + gen.prints.print_openflow_header(self.of_h) + if self.of_h['version'] is 1: + of10.prints.print_body(self) +# elif self.of_h['version'] is 4: +# print of13.prints.print_body(self) + + def check_filters(self): + # Was -F submitted? + if self.print_options['filters'] is 0: + return False + # Check if there is any limitation for printing + name_version = gen.tcpip.get_ofp_version(self.of_h['version']) + supported_versions = [] + for version in self.sanitizer['allowed_of_versions']: + supported_versions.append(version) + if name_version not in supported_versions: + return True + + # OF Types to be ignored through json file (-F) + rejected_types = self.sanitizer['allowed_of_versions'][name_version] + if self.of_h['type'] in rejected_types['rejected_of_types']: + return True diff --git a/gen/prints.py b/gen/prints.py index 321f348..8c47f9a 100644 --- a/gen/prints.py +++ b/gen/prints.py @@ -9,6 +9,7 @@ import gen.proxies import socket import struct +import gen.tcpip def red(string): @@ -59,14 +60,14 @@ def get_ip_from_long(long_ip): return (socket.inet_ntoa(struct.pack('!L', long_ip))) -def print_headers(print_options, date, getlen, caplen, eth, ip, tcp): - if print_options['min'] == 1: - print_minimal(date, getlen, ip, tcp) +def print_headers(pkt): + if pkt.print_options['min'] == 1: + print_minimal(pkt.l1['time'], pkt.l1['caplen'], pkt.l3, pkt.l4) else: - print_layer1(date, getlen, caplen) - print_layer2(eth) - print_layer3(ip) - print_tcp(tcp) + print_layer1(pkt.l1['time'], pkt.l1['caplen'], pkt.l1['truncate_len']) + print_layer2(pkt.l2) + print_layer3(pkt.l3) + print_tcp(pkt.l4) def print_minimal(date, getlen, ip, tcp): @@ -87,7 +88,7 @@ def print_layer1(date, getlen, caplen): def print_layer2(eth): print ('Ethernet: Destination MAC: %s Source MAC: %s Protocol: %s' % (eth_addr(eth['dst_mac']), eth_addr(eth['src_mac']), - red(hex(eth['protocol'])))) + red(gen.tcpip.get_ethertype(eth['protocol'])))) def print_vlan(vlan): @@ -124,7 +125,7 @@ def print_tcp(tcp): def print_openflow_header(of): - version = of10.dissector.get_ofp_version(of['version']) + version = gen.tcpip.get_ofp_version(of['version']) name_version = '%s(%s)' % (version, of['version']) if version == '1.0': name = of10.dissector.get_ofp_type(of['type']) @@ -137,3 +138,16 @@ def print_openflow_header(of): print ('OpenFlow Version: %s Type: %s Length: %s XID: %s' % (name_version, yellow(name_type), of['length'], red(of['xid']))) + + +def print_lldp(pkt): + lldp = pkt.of_body['print_lldp'] + print ('LLDP: Chassis Type(%s) Length: %s SubType: %s ID: %s\n' + 'LLDP: Port Type(%s) Length: %s SubType: %s ID: %s\n' + 'LLDP: TTL(%s) Length: %s Seconds: %s\n' + 'LLDP: END(%s) Length: %s' % + (lldp['c_type'], lldp['c_length'], lldp['c_subtype'], + green(lldp['c_id']), lldp['p_type'], + lldp['p_length'], lldp['p_subtype'], green(lldp['p_id']), + lldp['t_type'], lldp['t_length'], lldp['t_ttl'], + lldp['e_type'], lldp['e_length'])) diff --git a/gen/tcpip.py b/gen/tcpip.py index 9a26e8b..f5e0098 100644 --- a/gen/tcpip.py +++ b/gen/tcpip.py @@ -16,6 +16,20 @@ def get_ethernet_frame(packet, host_order=0): return eth_frame +def get_ethertype(etype): + etypes = {8: 'IP', + 2048: 'IP', + 2054: 'ARP', + 34925: 'IPv6', + 34887: 'MPLS', + 35020: 'LLDP', + 35138: 'BBDP'} + try: + return '%s(%s)' % (etypes[etype], hex(etype)) + except: + return etype + + def get_ethernet_vlan(packet): vlan_length = 2 vlan_pq = packet[:vlan_length] @@ -98,6 +112,20 @@ def get_tcp_stream(packet, header_size): return tcp_stream +def get_ofp_version(version): + of_versions = {0: 'Experimental', + 1: '1.0', + 2: '1.1', + 3: '1.2', + 4: '1.3', + 5: '1.4', + 6: '1.5'} + try: + return of_versions[version] + except: + return 'Unknown(%s)' % version + + def get_openflow_header(packet, start): ''' Returns OpenFlow header diff --git a/of10/__init__.py b/of10/__init__.py index 2c0e3c2..86f35cb 100644 --- a/of10/__init__.py +++ b/of10/__init__.py @@ -1,4 +1,5 @@ import gen.cli +import gen.packet import gen.prints import gen.proxies import gen.tcpip diff --git a/of10/dissector.py b/of10/dissector.py index 1453bd6..ac37471 100644 --- a/of10/dissector.py +++ b/of10/dissector.py @@ -4,20 +4,6 @@ ''' -def get_ofp_version(version): - of_versions = {0: 'Experimental', - 1: '1.0', - 2: '1.1', - 3: '1.2', - 4: '1.3', - 5: '1.4', - 6: '1.5'} - try: - return of_versions[version] - except: - return 'Unknown(%s)' % version - - def get_ofp_type(of_type): of_types = {0: 'Hello', 1: 'Error', diff --git a/of10/parser.py b/of10/parser.py index 522a5cc..f2fa700 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -12,19 +12,25 @@ import gen.proxies -def process_ofp_type(of_type, packet, h_size, of_xid, print_options, sanitizer): +def process_ofp_type(pkt): + of_type = pkt.of_h['type'] + of_xid = pkt.of_h['xid'] + print_options = pkt.print_options + h_size = 0 + packet = pkt.this_packet + if of_type == 0: - result = parse_Hello(packet, h_size, of_xid) + result = parse_Hello(pkt) elif of_type == 1: - result = parse_Error(packet, h_size, of_xid) + result = parse_Error(pkt) elif of_type == 2: - result = parse_EchoReq(packet, h_size, of_xid) + result = parse_EchoReq(pkt) elif of_type == 3: - result = parse_EchoRes(packet, h_size, of_xid) + result = parse_EchoRes(pkt) elif of_type == 4: result = parse_Vendor(packet, h_size, of_xid) elif of_type == 5: - result = parse_FeatureReq(packet, h_size, of_xid) + result = parse_FeatureReq(pkt) elif of_type == 6: result = parse_FeatureRes(packet, h_size, of_xid) elif of_type == 7: @@ -34,26 +40,25 @@ def process_ofp_type(of_type, packet, h_size, of_xid, print_options, sanitizer): elif of_type == 9: result = parse_SetConfig(packet, h_size, of_xid) elif of_type == 10: - result = parse_PacketIn(packet, h_size, of_xid, sanitizer) + result = parse_PacketIn(pkt) elif of_type == 11: result = parse_FlowRemoved(packet, h_size, of_xid) elif of_type == 12: result = parse_PortStatus(packet, h_size, of_xid) elif of_type == 13: - result = parse_PacketOut(packet, h_size, of_xid, sanitizer, - print_options) + result = parse_PacketOut(pkt) elif of_type == 14: result = parse_FlowMod(packet, h_size, of_xid, print_options) elif of_type == 15: result = parse_PortMod(packet, h_size, of_xid) - elif of_type == 16: - result = parse_StatsReq(packet, h_size, of_xid) - elif of_type == 17: - result = parse_StatsRes(packet, h_size, of_xid) +# elif of_type == 16: +# result = parse_StatsReq(packet, h_size, of_xid) +# elif of_type == 17: +# result = parse_StatsRes(packet, h_size, of_xid) elif of_type == 18: - result = parse_BarrierReq(packet, h_size, of_xid) + result = parse_BarrierReq(pkt) elif of_type == 19: - result = parse_BarrierRes(packet, h_size, of_xid) + result = parse_BarrierRes(pkt) elif of_type == 20: result = parse_QueueGetConfigReq(packet, h_size, of_xid) elif of_type == 21: @@ -64,32 +69,34 @@ def process_ofp_type(of_type, packet, h_size, of_xid, print_options, sanitizer): # *************** Hello ***************** -def parse_Hello(packet, h_size, of_xid): - of10.prints.print_of_hello(of_xid) +def parse_Hello(pkt): + pkt.prepare_printing('print_of_hello', None) + pkt.print_packet() return 1 # ************** Error ***************** -def parse_Error(packet, h_size, of_xid): - of_error = packet[h_size:h_size+4] +def parse_Error(pkt): + of_error = pkt.this_packet[0:4] ofe = unpack('!HH', of_error) - ofe_type = ofe[0] - ofe_code = ofe[1] - nameCode, typeCode = of10.dissector.get_ofp_error(ofe_type, ofe_code) - of10.prints.print_of_error(of_xid, nameCode, typeCode) + error = {'type': ofe[0], 'code': ofe[1]} + pkt.prepare_printing('print_of_error', error) + pkt.print_packet() return 1 # ************ EchoReq ***************** -def parse_EchoReq(packet, h_size, of_xid): - of10.prints.print_echoreq(of_xid) +def parse_EchoReq(pkt): + pkt.prepare_printing('print_echoreq', None) + pkt.print_packet() return 1 # ************ EchoRes ***************** -def parse_EchoRes(packet, h_size, of_xid): - of10.prints.print_echores(of_xid) +def parse_EchoRes(pkt): + pkt.prepare_printing('print_echores', None) + pkt.print_packet() return 1 @@ -107,8 +114,9 @@ def parse_Vendor(packet, h_size, of_xid): # *********** FeatureReq *************** -def parse_FeatureReq(packet, h_size, of_xid): - of10.prints.print_of_feature_req(of_xid) +def parse_FeatureReq(pkt): + pkt.prepare_printing('print_of_feature_req', None) + pkt.print_packet() return 1 @@ -249,24 +257,28 @@ def _parse_ethernet_lldp_PacketInOut(packet, start): return eth, vlan, {}, start -def _parse_other_types(packet, start, eth): +def _parse_other_types(packet, start, eth, pkt): # OESS FVD if eth['protocol'] in [34998]: - print 'OESS FVD' + message = {'message': 'OESS FVD'} + pkt.prepare_printing('print_string', message) elif eth['protocol'] in [35020]: # If it gets here, means that the LLDP packet is MalFormed - print 'LLDP Packet MalFormed' + message = {'message': 'LLDP Packet MalFormed'} + pkt.prepare_printing('print_string', message) elif eth['protocol'] in [2048]: ip = gen.tcpip.get_ip_packet(packet, start) - gen.prints.print_layer3(ip) if ip['protocol'] is 6: tcp = gen.tcpip.get_tcp_stream(packet, start + ip['length']) - gen.prints.print_tcp(tcp) + pkt.prepare_printing('print_layer3', ip) + pkt.prepare_printing('print_tcp', tcp) elif eth['protocol'] in [2054]: arp = gen.tcpip.get_arp(packet[start:]) - gen.prints.print_arp(arp) + pkt.prepare_printing('print_arp', arp) else: - print 'Ethertype %s not dissected' % hex(eth['protocol']) + string = 'Ethertype %s not dissected' % hex(eth['protocol']) + message = {'message': string} + pkt.prepare_printing('print_string', message) def _print_packetIn(of_xid, packetIn, eth, vlan, lldp): @@ -278,33 +290,43 @@ def _print_packetIn(of_xid, packetIn, eth, vlan, lldp): of10.prints.print_packetInOut_lldp(of_xid, lldp) -def parse_PacketIn(packet, h_size, of_xid, sanitizer): +# def parse_PacketIn(packet, h_size, of_xid, sanitizer): +def parse_PacketIn(pkt): # buffer_id(32), total_len(16), in_port(16), reason(8), pad(8) - pkt_raw = packet[h_size:h_size+10] + pkt_raw = pkt.this_packet[0:10] p_in = unpack('!LHHBB', pkt_raw) reason = of10.dissector.get_packetIn_reason(p_in[3]) packetIn = {'buffer_id': p_in[0], 'total_len': p_in[1], 'in_port': p_in[2], 'reason': reason, 'pad': p_in[4]} - eth, vlan, lldp, offset = _parse_ethernet_lldp_PacketInOut(packet, - h_size + 10) + pkt.prepare_printing('print_packetIn', packetIn) + + eth, vlan, lldp, offset = _parse_ethernet_lldp_PacketInOut(pkt.this_packet, + 10) + + pkt.prepare_printing('print_layer2_pktIn', eth) + if len(vlan) > 0: + pkt.prepare_printing('print_vlan', vlan) + if len(lldp) == 0: - _print_packetIn(of_xid, packetIn, eth, vlan, {}) - _parse_other_types(packet[offset:], 0, eth) - return 1 + _parse_other_types(pkt.this_packet[offset:], 0, eth, pkt) + else: + pkt.prepare_printing('print_lldp', lldp) + + pkt.print_packet() # If we have filters (-F) - filters = sanitizer['packetIn_filter'] - - if len(filters) > 0: - if filters['switch_dpid'] == "any": - _print_packetIn(of_xid, packetIn, eth, vlan, lldp) - elif filters['switch_dpid'] == lldp['c_id']: - if (filters['in_port'] == "any" or - filters['in_port'] == lldp['in_port']): - _print_packetIn(of_xid, packetIn, eth, vlan, lldp) - else: - _print_packetIn(of_xid, packetIn, eth, vlan, lldp) + # filters = sanitizer['packetIn_filter'] + + # if len(filters) > 0: + # if filters['switch_dpid'] == "any": + # _print_packetIn(of_xid, packetIn, eth, vlan, lldp) + # elif filters['switch_dpid'] == lldp['c_id']: + # if (filters['in_port'] == "any" or + # filters['in_port'] == lldp['in_port']): + # _print_packetIn(of_xid, packetIn, eth, vlan, lldp) + # else: + # _print_packetIn(of_xid, packetIn, eth, vlan, lldp) return 1 @@ -343,45 +365,46 @@ def parse_PortStatus(packet, h_size, of_xid): # ******************* PacketOut ***************************** -# Actions need to be handled -def parse_PacketOut(packet, h_size, of_xid, sanitizer, print_options): +def parse_PacketOut(pkt): # buffer_id(32), in_port(16), actions_len(16) - pkt_raw = packet[h_size:h_size+8] + pkt_raw = pkt.this_packet[0:8] p_out = unpack('!LHH', pkt_raw) actions_len = p_out[2] packetOut = {'buffer_id': p_out[0], 'in_port': p_out[1], 'actions_len': actions_len} - of10.prints.print_ofp_packetOut(of_xid, packetOut) + pkt.prepare_printing('print_packetOut', packetOut) # Actions - start = h_size + 8 - _parse_OFAction(of_xid, packet[start:start+packetOut['actions_len']], 0) + start = 8 + _parse_OFAction(pkt.this_packet[start:start+packetOut['actions_len']], 0) # Ethernet - start = h_size + 8 + packetOut['actions_len'] - eth = gen.tcpip.get_ethernet_frame(packet[start:start+14], 1) - of10.prints.print_packetInOut_layer2(of_xid, eth) + start = 8 + packetOut['actions_len'] + eth = gen.tcpip.get_ethernet_frame(pkt.this_packet[start:start+14], 1) + pkt.prepare_printing('print_layer2_pktIn', eth) start = start + 14 etype = '0x0000' # VLAN or not if eth['protocol'] in [33024]: - vlan = gen.tcpip.get_ethernet_vlan(packet[start:start+2]) - of10.prints.print_packetInOut_vlan(of_xid, vlan) + vlan = gen.tcpip.get_ethernet_vlan(pkt.this_packet[start:start+2]) + if len(vlan) > 0: + pkt.prepare_printing('print_vlan', vlan) start = start + 2 # If VLAN exists, there is a next eth['protocol'] - etype = gen.tcpip.get_next_etype(packet[start:start+2]) + etype = gen.tcpip.get_next_etype(pkt.this_packet[start:start+2]) start = start + 2 else: etype = eth['protocol'] if etype in [35020, 35138]: # LLDP TLV - lldp = gen.tcpip.get_lldp(packet[start:]) + lldp = gen.tcpip.get_lldp(pkt.this_packet[start:]) if len(lldp) is 0: print 'LLDP Packet MalFormed' else: # Support for FSFW/Proxy - gen.proxies.support_fsfw(print_options, lldp) - of10.prints.print_packetInOut_lldp(of_xid, lldp) + gen.proxies.support_fsfw(pkt.print_options, lldp) + pkt.prepare_printing('print_lldp', lldp) + pkt.print_packet() return 1 @@ -536,7 +559,7 @@ def get_action(action_type, length, payload): return type_f[0] -def _parse_OFAction(of_xid, packet, start, ofactions=[]): +def _parse_OFAction(packet, start, ofactions=[]): ''' Actions ''' @@ -562,7 +585,7 @@ def _parse_OFAction(of_xid, packet, start, ofactions=[]): total_length = 4 ofa_action_payload = packet[start:start + 4] - ofa_temp = of10.prints.print_ofp_action(of_xid, ofa_type, + ofa_temp = of10.prints.print_ofp_action(ofa_type, ofa_length, ofa_action_payload) @@ -601,7 +624,7 @@ def parse_FlowMod(packet, h_size, of_xid, print_options): # 12 for types 4,5,b start = h_size+64 - ofactions = _parse_OFAction(of_xid, packet, start, ofactions) + ofactions = _parse_OFAction(packet, start, ofactions) if print_options['ovs'] == 1: of10.prints.print_ofp_ovs(print_options, ofmatch, ofactions, @@ -748,7 +771,7 @@ def parse_StatsRes(packet, h_size, of_xid): # Process Actions[] end = res_flow['length'] - (4 + 40 + 44) actions = packet[start+88:start+88+end] - _parse_OFAction(of_xid, actions, 0) + _parse_OFAction(actions, 0) count = count - int(res_flow['length']) start = start + int(res_flow['length']) @@ -840,14 +863,16 @@ def parse_StatsRes(packet, h_size, of_xid): # ********************** BarrierReq *********************** -def parse_BarrierReq(packet, h_size, of_xid): - of10.prints.print_of_BarrierReq(of_xid) +def parse_BarrierReq(pkt): + pkt.prepare_printing('print_of_BarrierReq', None) + pkt.print_packet() return 1 # ********************** BarrierRes *********************** -def parse_BarrierRes(packet, h_size, of_xid): - of10.prints.print_of_BarrierReply(of_xid) +def parse_BarrierRes(pkt): + pkt.prepare_printing('print_of_BarrierReply', None) + pkt.print_packet() return 1 diff --git a/of10/prints.py b/of10/prints.py index ce082ec..2c22327 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -5,9 +5,7 @@ import of10.dissector import of10.parser import gen.prints -#from gen.prints import * -# red, green, eth_addr, datapath_id -# from prints import print_layer2, print_vlan +import gen.packet def red(string): @@ -26,17 +24,39 @@ def datapath_id(string): return gen.prints.datapath_id(string) -def print_of_hello(of_xid): - print '%s OpenFlow Hello' % of_xid +def print_layer2(pkt): + gen.prints.print_layer2(pkt.l2) -def print_of_error(of_xid, nameCode, typeCode): - print ('%s OpenFlow Error - Type: %s Code: %s' % - (of_xid, red(nameCode), red(typeCode))) +def print_layer2_pktIn(pkt): + gen.prints.print_layer2(pkt.of_body['print_layer2_pktIn']) -def print_of_feature_req(of_xid): - print '%s OpenFlow Feature Request' % of_xid +def print_lldp(pkt): + gen.prints.print_lldp(pkt) + + +def print_arp(pkt): + gen.prints.print_arp(pkt.of_body['print_arp']) + + +def print_type_unknown(pkt): + string = '%s OpenFlow OFP_Type %s unknown \n' + print string % (pkt.of_h['xid'], pkt.of_h['type']) + + +def print_of_hello(pkt): + print 'OpenFlow Hello' + + +def print_of_error(pkt): + error = pkt.of_body['print_of_error'] + nCode, tCode = of10.dissector.get_ofp_error(error['type'], error['code']) + print ('OpenFlow Error - Type: %s Code: %s' % (red(nCode), red(tCode))) + + +def print_of_feature_req(pkt): + print 'OpenFlow Feature Request' def print_of_getconfig_req(of_xid): @@ -150,90 +170,90 @@ def print_ofp_flow_removed(xid, ofrem): ofrem['byte_count']) -def print_ofp_action(xid, action_type, length, payload): +def print_ofp_action(action_type, length, payload): if action_type == 0: port, max_len = of10.parser.get_action(action_type, length, payload) port = of10.dissector.get_phy_port_id(port) - print ('%s OpenFlow Action - Type: %s Length: %s Port: %s ' + print ('OpenFlow Action - Type: %s Length: %s Port: %s ' 'Max Length: %s' % - (xid, green('OUTPUT'), length, green(port), max_len)) + (green('OUTPUT'), length, green(port), max_len)) return 'output:' + port elif action_type == 1: vlan, pad = of10.parser.get_action(action_type, length, payload) - print ('%s OpenFlow Action - Type: %s Length: %s VLAN ID: %s Pad: %s' % - (xid, green('SetVLANID'), length, green(str(vlan)), pad)) + print ('OpenFlow Action - Type: %s Length: %s VLAN ID: %s Pad: %s' % + (green('SetVLANID'), length, green(str(vlan)), pad)) return 'mod_vlan_vid:' + str(vlan) elif action_type == 2: vlan_pc, pad = of10.parser.get_action(action_type, length, payload) - print ('%s OpenFlow Action - Type: %s Length: %s VLAN PCP: %s Pad: %s' % - (xid, green('SetVLANPCP'), length, green(str(vlan_pc)), pad)) + print ('OpenFlow Action - Type: %s Length: %s VLAN PCP: %s Pad: %s' % + (green('SetVLANPCP'), length, green(str(vlan_pc)), pad)) return 'mod_vlan_pcp:' + str(vlan_pc) elif action_type == 3: - print ('%s OpenFlow Action - Type: %s Length: %s' % - (xid, green('StripVLAN'), length)) + print ('OpenFlow Action - Type: %s Length: %s' % + (green('StripVLAN'), length)) return 'strip_vlan' elif action_type == 4: setDLSrc, pad = of10.parser.get_action(action_type, length, payload) - print ('%s OpenFlow Action - Type: %s Length: %s SetDLSrc: %s Pad: %s' % - (xid, green('SetDLSrc'), length, green(str(eth_addr(setDLSrc))), + print ('OpenFlow Action - Type: %s Length: %s SetDLSrc: %s Pad: %s' % + (green('SetDLSrc'), length, green(str(eth_addr(setDLSrc))), pad)) return 'mod_dl_src:' + str(eth_addr(setDLSrc)) elif action_type == 5: setDLDst, pad = of10.parser.get_action(action_type, length, payload) - print ('%s OpenFlow Action - Type: %s Length: %s SetDLDst: %s Pad: %s' % - (xid, green('SetDLDst'), length, green(str(eth_addr(setDLDst))), + print ('OpenFlow Action - Type: %s Length: %s SetDLDst: %s Pad: %s' % + (green('SetDLDst'), length, green(str(eth_addr(setDLDst))), pad)) return 'mod_dl_dst:' + str(eth_addr(setDLDst)) elif action_type == 6: nw_addr = of10.parser.get_action(action_type, length, payload) - print ('%s OpenFlow Action - Type: %s Length: %s SetNWSrc: %s' % - (xid, green('SetNWSrc'), length, green(str(nw_addr)))) + print ('OpenFlow Action - Type: %s Length: %s SetNWSrc: %s' % + (green('SetNWSrc'), length, green(str(nw_addr)))) return 'mod_nw_src:' + str(nw_addr) elif action_type == 7: nw_addr = of10.parser.get_action(action_type, length, payload) - print ('%s OpenFlow Action - Type: %s Length: %s SetNWDst: %s' % - (xid, green('SetNWDst'), length, green(str(nw_addr)))) + print ('OpenFlow Action - Type: %s Length: %s SetNWDst: %s' % + (green('SetNWDst'), length, green(str(nw_addr)))) return 'mod_nw_src:' + str(nw_addr) elif action_type == 8: nw_tos, pad = of10.parser.get_action(action_type, length, payload) - print ('%s OpenFlow Action - Type: %s Length: %s SetNWTos: %s Pad: %s' % - (xid, green('SetNWTos'), length, green(str(nw_tos)), pad)) + print ('OpenFlow Action - Type: %s Length: %s SetNWTos: %s Pad: %s' % + (green('SetNWTos'), length, green(str(nw_tos)), pad)) return 'mod_nw_tos:' + str(nw_tos) elif action_type == 9: port, pad = of10.parser.get_action(action_type, length, payload) - print ('%s OpenFlow Action - Type: %s Length: %s SetTPSrc: %s Pad: %s' % - (xid, green('SetTPSrc'), length, green(str(port)), pad)) + print ('OpenFlow Action - Type: %s Length: %s SetTPSrc: %s Pad: %s' % + (green('SetTPSrc'), length, green(str(port)), pad)) return 'mod_tp_src:' + str(port) elif action_type == int('a', 16): port, pad = of10.parser.get_action(action_type, length, payload) - print ('%s OpenFlow Action - Type: %s Length: %s SetTPDst: %s Pad: %s' % - (xid, green('SetTPDst'), length, green(str(port)), pad)) + print ('OpenFlow Action - Type: %s Length: %s SetTPDst: %s Pad: %s' % + (green('SetTPDst'), length, green(str(port)), pad)) return 'mod_tp_dst:' + str(port) elif action_type == int('b', 16): port, pad, queue_id = of10.parser.get_action(action_type, length, payload) - print (('%s OpenFlow Action - Type: %s Length: %s Enqueue: %s Pad: %s' + print (('OpenFlow Action - Type: %s Length: %s Enqueue: %s Pad: %s' ' Queue: %s') % - (xid, green('Enqueue'), length, green(str(port)), pad, + (green('Enqueue'), length, green(str(port)), pad, green(str(queue_id)))) return 'set_queue:' + str(queue_id) elif action_type == int('ffff', 16): vendor = of10.parser.get_action(action_type, length, payload) - print ('%s OpenFlow Action - Type: %s Length: %s Vendor: %s' % - (xid, green('VENDOR'), length, green(str(vendor)))) + print ('OpenFlow Action - Type: %s Length: %s Vendor: %s' % + (green('VENDOR'), length, green(str(vendor)))) return 'VendorType' else: @@ -284,12 +304,12 @@ def print_PortMod(of_xid, portMod): _print_portMod_config_mask(of_xid, portMod, 'advertise') -def print_of_BarrierReq(of_xid): - print '%s OpenFlow Barrier Request' % of_xid +def print_of_BarrierReq(pkt): + print 'OpenFlow Barrier Request' -def print_of_BarrierReply(of_xid): - print '%s OpenFlow Barrier Reply' % of_xid +def print_of_BarrierReply(pkt): + print 'OpenFlow Barrier Reply' def print_of_vendor(of_vendor, of_xid): @@ -420,12 +440,12 @@ def print_ofp_setConfig(of_xid, flag, miss): (of_xid, flag, miss)) -def print_echoreq(of_xid): - print ('%s OpenFlow Echo Request' % (of_xid)) +def print_echoreq(pkt): + print 'OpenFlow Echo Request' -def print_echores(of_xid): - print ('%s OpenFlow Echo Reply' % (of_xid)) +def print_echores(pkt): + print 'OpenFlow Echo Reply' def print_portStatus(of_xid, reason, pad): @@ -443,14 +463,31 @@ def print_packetInOut_vlan(of_xid, vlan): gen.prints.print_vlan(vlan) -def print_ofp_packetIn(of_xid, packetIn): - print ('%s PacketIn: buffer_id: %s total_len: %s in_port: %s reason: %s ' +def print_packetIn(pkt): + packetIn = pkt.of_body['print_packetIn'] + + # If we have filters (-F) + # filters = pkt.sanitizer['packetIn_filter'] + + # if len(filters) > 0: + # if filters['switch_dpid'] == "any": + # should_print = True _print_packetIn(of_xid, packetIn, eth, vlan, lldp) + # elif filters['switch_dpid'] == lldp['c_id']: + # if (filters['in_port'] == "any" or + # filters['in_port'] == lldp['in_port']): + # _print_packetIn(of_xid, packetIn, eth, vlan, lldp) + # else: + # _print_packetIn(of_xid, packetIn, eth, vlan, lldp) + + print ('PacketIn: buffer_id: %s total_len: %s in_port: %s reason: %s ' 'pad: %s' % - (of_xid, hex(packetIn['buffer_id']), packetIn['total_len'], + (hex(packetIn['buffer_id']), packetIn['total_len'], green(packetIn['in_port']), green(packetIn['reason']), packetIn['pad'])) +# a print_lldp function was created on gen.prints +# remove this def print_packetInOut_lldp(of_xid, lldp): print ('%s LLDP: Chassis Type(%s) Length: %s SubType: %s ID: %s\n' '%s LLDP: Port Type(%s) Length: %s SubType: %s ID: %s\n' @@ -463,9 +500,10 @@ def print_packetInOut_lldp(of_xid, lldp): lldp['e_length'])) -def print_ofp_packetOut(of_xid, packetOut): - print ('%s PacketOut: buffer_id: %s in_port: %s actions_len: %s' % - (of_xid, hex(packetOut['buffer_id']), +def print_packetOut(pkt): + packetOut = pkt.of_body['print_packetOut'] + print ('PacketOut: buffer_id: %s in_port: %s actions_len: %s' % + (hex(packetOut['buffer_id']), green(of10.dissector.get_phy_port_id(packetOut['in_port'])), packetOut['actions_len'])) @@ -489,3 +527,8 @@ def print_queueRes_properties(of_xid, properties): print ('%s Property: %s Length: %s Pad: %s Rate: %s Pad: %s' % (of_xid, properties['type'], properties['length'], properties['pad'], properties['rate'], properties['pad2'])) + + +def print_body(pkt): + for f in pkt.printing_seq: + eval(f)(pkt) diff --git a/of13/__init__.py b/of13/__init__.py index 2c0e3c2..86f35cb 100644 --- a/of13/__init__.py +++ b/of13/__init__.py @@ -1,4 +1,5 @@ import gen.cli +import gen.packet import gen.prints import gen.proxies import gen.tcpip diff --git a/of13/parser.py b/of13/parser.py index 26edf82..3432b61 100644 --- a/of13/parser.py +++ b/of13/parser.py @@ -282,8 +282,6 @@ def _parse_matches(of_xid, packet, start): of13.prints.print_match_type(of_xid, m_type, m_length) length_oxm = (m_length - 4) - # Debug - # print 'Length_oxm %s' % length_oxm padding = (((m_length + 7)/8*8 - m_length)) start = start + 4 @@ -308,12 +306,77 @@ def _parse_matches(of_xid, packet, start): print_padding(padding) # Return offset for Instructions - return start + start_2 + return start + length_oxm + padding -def _parse_instructions(of_xid, packet, instructions_start): +def _parse_actions(of_xid, packet, length): + print '%s Actions: ' % (of_xid) + + +def _inst_goto_table(packet, start, i_len): + print + + +def _inst_write_metadata(packet, start, i_len): + print + + +def _inst_write_actions(packet, start, i_len): + print + + +def _inst_apply_actions(of_xid, packet, start, i_len): + print 'APPLY_ACTIONS' + + apply_raw = packet[start:start+4] + apply_padding = unpack('!L', apply_raw) + print '%s Padding: %s' % (of_xid, apply_padding[0]) + _parse_actions(of_xid, packet[start+4:], i_len-8) + + +def _inst_clear_actions(packet, start, i_len): + print + + +def _inst_meter(packet, start, i_len): + print + + +def _inst_experimenter(packet, start, i_len): print + +def _parse_instructions(of_xid, packet, instructions_start): + + start = instructions_start + + while len(packet[start:]) > 0: + instructions_raw = packet[instructions_start:instructions_start+4] + instructions = unpack('!HH', instructions_raw) + i_type = instructions[0] + i_len = instructions[1] + start = start + 4 + + print ('%s Instructions:' % of_xid), + # Call proper instruction + if i_type == 1: + _inst_goto_table(packet, start, i_len) + elif i_type == 2: + _inst_write_metadata(packet, start, i_len) + elif i_type == 3: + _inst_write_actions(packet, start, i_len) + elif i_type == 4: + _inst_apply_actions(of_xid, packet, start, i_len) + elif i_type == 5: + _inst_clear_actions(packet, start, i_len) + elif i_type == 6: + _inst_meter(packet, start, i_len) + elif i_type == 65535: + _inst_experimenter(packet, start, i_len) + + start = start + i_len - 4 + + def parse_FlowMod(packet, h_size, of_xid, print_options): flow_mod_raw = packet[h_size:h_size+40] ofmod = unpack('!QQBBHHHLLLHH', flow_mod_raw) diff --git a/ofp_sniffer.py b/ofp_sniffer.py index 7e6fdeb..46317d5 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -10,7 +10,7 @@ More info on how to use it: www.sdn.amlight.net - Current version: 0.2 + Current version: 0.3 Author: Jeronimo Bezerra @@ -18,14 +18,8 @@ import datetime import pcapy import sys -from gen.tcpip import get_ethernet_frame, get_ip_packet, \ - get_tcp_stream, get_openflow_header import gen.cli -import gen.proxies -from gen.prints import print_headers, print_openflow_header -from of10.parser import process_ofp_type -import of10.dissector -from of13.parser import process_ofp_type13 +from gen.packet import Packet def main(argv): @@ -47,11 +41,15 @@ def main(argv): # start sniffing packets while(1): (header, packet) = cap.next() - parse_packet(packet, datetime.datetime.now(), - header.getlen(), header.getcaplen(), - print_options, sanitizer) + time = datetime.datetime.now() + pkt = Packet(packet, print_options, sanitizer) + pkt.process_header(header.getlen(), header.getcaplen(), time) + if pkt.openflow_packet: + pkt.process_openflow_body() + # Prints + del pkt + except KeyboardInterrupt: - print gen.proxies.close() print 'Exiting...' sys.exit(0) except Exception as exception: @@ -59,132 +57,32 @@ def main(argv): return -def sanitizer_filters(of_header, date, getlen, caplen, header_size, - eth, ip, tcp, sanitizer): - ''' - If -F was provided, use filters specified - ''' - if (of_header['version'] == -1): - print ('h_size : %s - caplen: %s ' % (header_size, caplen)) - print_headers(1, date, getlen, caplen, eth, ip, tcp) - print 'OpenFlow header not complete. Ignoring packet.' - return 0 - - # OF Versions supported through json file (-F) - name_version = of10.dissector.get_ofp_version(of_header['version']) - supported_versions = [] - for version in sanitizer['allowed_of_versions']: - supported_versions.append(version) - if name_version not in supported_versions: - return 0 - - # OF Types to be ignored through json file (-F) - rejected_types = sanitizer['allowed_of_versions'][name_version] - if of_header['type'] in rejected_types['rejected_of_types']: - return 0 - - return 1 - - -def parse_packet(packet, date, getlen, caplen, print_options, sanitizer): - ''' - This functions gets the raw packet and dissassembly it. - Only TCP + OpenFlow are analysed. Others are discarted - ''' - eth = get_ethernet_frame(packet) - - # If protocol is no IP(8) returns - if (eth['protocol'] != 8): - return - - ip = get_ip_packet(packet, eth['length']) - - # If protocol is not TCP, returns - if (ip['protocol'] != 6): - return - - header_size = ip['length'] + eth['length'] - tcp = get_tcp_stream(packet, header_size) - - # If TCP flag is not PUSH, return - if (tcp['flag_psh'] != 8): - return - - # Now let's process all OpenFlow packets in the payload - header_size = header_size + tcp['length'] - remaining_bytes = caplen - header_size - - print_header_once = 0 - start = header_size - - # If there is less than 8 bytes, it is because it is fragment. - # There is no support for fragmented packet at this time - while (remaining_bytes >= 8): - of_header = get_openflow_header(packet, start) - - # If -F was passed... - if len(sanitizer['allowed_of_versions']) != 0: - result = sanitizer_filters(of_header, date, getlen, caplen, - header_size, eth, ip, tcp, sanitizer) - if result == 0: - return - - # If not OpenFlow version 1.0 or 1.3 return - if of_header['version'] not in [1, 4]: - return - - # In case there are multiple flow_mods - remaining_bytes = remaining_bytes - of_header['length'] - - # Starts printing - if print_header_once == 0: - print_headers(print_options, date, getlen, caplen, eth, ip, tcp) - print_header_once = 1 - - # Prints the OpenFlow header, it doesn't matter the OF version - print_openflow_header(of_header) - - print_options['device_ip'] = ip['d_addr'] - print_options['device_port'] = tcp['dest_port'] - - # Process and Print OF body - # OF_Header lenght = 8 - start = start + 8 - this_packet = packet[start:start+of_header['length'] - 8] - - # If OpenFlow version is 1.0 - if of_header['version'] is 1: - if not process_ofp_type(of_header['type'], this_packet, 0, - of_header['xid'], print_options, sanitizer): - - print ('%s OpenFlow OFP_Type %s unknown \n' % - (of_header['xid'], of_header['type'])) - return - else: - # Get next packet - start = start + (of_header['length'] - 8) - - # If OpenFlow version is 1.3 - elif of_header['version'] is 4: - # Process and Print OF body - # OF_Header lenght = 8 - if not process_ofp_type13(of_header['type'], this_packet, 0, - of_header['xid'], print_options, - sanitizer): - print ('%s OpenFlow OFP_Type %s not dissected yet \n' % - (of_header['xid'], of_header['type'])) - return - else: - # Get next packet - start = start + (of_header['length'] - 8) - - # Do not process extra data from Hello and Error. - # Maybe in the future. - if (of_header['type'] == 0 or of_header['type'] == 1): - print - return +#def sanitizer_filters(of_header, date, getlen, caplen, header_size, +# eth, ip, tcp, sanitizer): +# ''' +# If -F was provided, use filters specified +# ''' +# if (of_header['version'] == -1): +# print ('h_size : %s - caplen: %s ' % (header_size, caplen)) +# print_headers(1, date, getlen, caplen, eth, ip, tcp) +# print 'OpenFlow header not complete. Ignoring packet.' +# return 0 +# +# # OF Versions supported through json file (-F) +# name_version = of10.dissector.get_ofp_version(of_header['version']) +# supported_versions = [] +# for version in sanitizer['allowed_of_versions']: +# supported_versions.append(version) +# if name_version not in supported_versions: +# return 0 +# +# # OF Types to be ignored through json file (-F) +# rejected_types = sanitizer['allowed_of_versions'][name_version] +# if of_header['type'] in rejected_types['rejected_of_types']: +# return 0 +# +# return 1 - print if __name__ == "__main__": main(sys.argv) From 8b18ee7b8e8837022dde3ae173f511b0934d00b0 Mon Sep 17 00:00:00 2001 From: sdn Date: Mon, 11 Jan 2016 20:34:25 -0500 Subject: [PATCH 05/88] moving to the laptop - no improvements --- example_filter.json | 1 - of10/parser.py | 42 ++++++++++++++++++++++-------------------- of10/prints.py | 7 ++++--- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/example_filter.json b/example_filter.json index dc8b14c..8701ad4 100644 --- a/example_filter.json +++ b/example_filter.json @@ -6,7 +6,6 @@ 3, 10, 13, - 16, 17 ] }, diff --git a/of10/parser.py b/of10/parser.py index f2fa700..0e99237 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -42,17 +42,17 @@ def process_ofp_type(pkt): elif of_type == 10: result = parse_PacketIn(pkt) elif of_type == 11: - result = parse_FlowRemoved(packet, h_size, of_xid) + result = parse_FlowRemoved(pkt) elif of_type == 12: - result = parse_PortStatus(packet, h_size, of_xid) + result = parse_PortStatus(pkt) elif of_type == 13: result = parse_PacketOut(pkt) elif of_type == 14: result = parse_FlowMod(packet, h_size, of_xid, print_options) elif of_type == 15: result = parse_PortMod(packet, h_size, of_xid) -# elif of_type == 16: -# result = parse_StatsReq(packet, h_size, of_xid) + elif of_type == 16: + result = parse_StatsReq(pkt) # elif of_type == 17: # result = parse_StatsRes(packet, h_size, of_xid) elif of_type == 18: @@ -332,11 +332,11 @@ def parse_PacketIn(pkt): # ******************** FlowRemoved *************************** -def parse_FlowRemoved(packet, h_size, of_xid): - ofmatch = _parse_OFMatch(packet, h_size) - of10.prints.print_ofp_match(of_xid, ofmatch) +def parse_FlowRemoved(pkt): + ofmatch = _parse_OFMatch(pkt.this_packet, 0) + pkt.prepare_printing('print_ofp_match', ofmatch) - of_rem_body = packet[h_size+40:h_size+40+40] + of_rem_body = pkt.this_packet[40:40+40] ofrem = unpack('!QHBBLLHBBQQ', of_rem_body) cookie = ofrem[0] if ofrem[0] > 0 else 0 cookie = '0x' + format(cookie, '02x') @@ -348,19 +348,22 @@ def parse_FlowRemoved(packet, h_size, of_xid): 'pad2': ofrem[7], 'pad3': ofrem[8], 'packet_count': ofrem[9], 'byte_count': ofrem[10]} - of10.prints.print_ofp_flow_removed(of_xid, ofrem) + pkt.prepare_printing('print_ofp_flow_removed', ofrem) + pkt.print_packet() return 1 # ******************* PortStatus ***************************** -def parse_PortStatus(packet, h_size, of_xid): - port_raw = packet[h_size:h_size+8] +def parse_PortStatus(pkt): + port_raw = pkt.this_packet[0:8] port = unpack('!B7s', port_raw) reason = of10.dissector.get_portStatus_reason(port[0]) - pad = port[1] - of10.prints.print_portStatus(of_xid, reason, pad) - ports = _parse_phy_ports(packet[h_size+8:h_size+64], of_xid) - of10.prints.print_of_feature_res_ports(of_xid, ports) + p_status = {'reason': reason, 'pad': port[1]} + pkt.prepare_printing('print_portStatus', p_status) + + ports = _parse_phy_ports(pkt.this_packet[8:64], pkt.of_h['xid']) + pkt.prepare_printing('print_of_feature_res_ports', ports) + pkt.print_packet() return 1 @@ -588,7 +591,6 @@ def _parse_OFAction(packet, start, ofactions=[]): ofa_temp = of10.prints.print_ofp_action(ofa_type, ofa_length, ofa_action_payload) - # Print OVS format ofactions.append(ofa_temp) ofactions.append(',') @@ -649,13 +651,13 @@ def parse_PortMod(packet, h_size, of_xid): # ******************** StatReq **************************** -def parse_StatsReq(packet, h_size, of_xid): +def parse_StatsReq(pkt): ''' Process the StatsReq ''' # Get type = 16bits # Get flags = 16bits - of_stat_req = packet[h_size:h_size+4] + of_stat_req = pkt.this_packet[0:4] ofstat = unpack('!HH', of_stat_req) stat_type = ofstat[0] # FLags were not defined yet. Ignoring. @@ -666,14 +668,14 @@ def parse_StatsReq(packet, h_size, of_xid): if stat_type == 0: # Description # No extra fields - of10.prints.print_ofp_statReqDesc(of_xid, stat_type) + pkt.prepare_printing('print_ofp_statReqDesc', stat_type) elif stat_type == 1 or stat_type == 2: # Flow(1) or Aggregate(2) # Fields: match(40), table_id(8), pad(8), out_port(16) of_match = _parse_OFMatch(packet, start) # 44 Bytes (40B from Match, 4 from header) - of_stat_req = packet[start+40:start+40+4] + of_stat_req = pkt.this_packet[start+40:start+40+4] ofstat = unpack('!BBH', of_stat_req) table_id = ofstat[0] pad = ofstat[1] diff --git a/of10/prints.py b/of10/prints.py index 2c22327..d4cd500 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -448,9 +448,10 @@ def print_echores(pkt): print 'OpenFlow Echo Reply' -def print_portStatus(of_xid, reason, pad): - print ('%s OpenFlow PortStatus - Reason: %s Pad: %s' % - (of_xid, reason, pad)) +def print_portStatus(pkt): + reason = pkt.of_body['print_portStatus']['reason'] + pad = pkt.of_body['print_portStatus']['pad'] + print ('OpenFlow PortStatus - Reason: %s Pad: %s' % (reason, pad)) def print_packetInOut_layer2(of_xid, eth): From e60c520225f157e22d391fb35041d738a5e9754c Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Tue, 15 Dec 2015 14:27:20 -0500 Subject: [PATCH 06/88] OF1.0 migrated to the new approach. A few tests and old features are required. Working on them. --- example_filter.json | 6 +- gen/packet.py | 8 +- gen/tcpip.py | 10 +- of10/dissector.py | 7 + of10/parser.py | 419 ++++++++++++++++++++++---------------------- of10/prints.py | 352 +++++++++++++++++++++++-------------- 6 files changed, 443 insertions(+), 359 deletions(-) diff --git a/example_filter.json b/example_filter.json index 8701ad4..5e2b916 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,11 +2,7 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 2, - 3, - 10, - 13, - 17 + 10, 13 ] }, "1.3": { diff --git a/gen/packet.py b/gen/packet.py index da5c553..4545ec3 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -79,14 +79,17 @@ def process_openflow_body(self): self.start += OF_HEADER_SIZE self.end = self.of_h['length'] - OF_HEADER_SIZE self.this_packet = self.packet[self.start:self.start+self.end] + # debug + # print self.of_h['type'] if self.of_h['version'] is 1: if not process_ofp_type(self): of10.prints.print_type_unknown(self) return else: + # Print packets + self.print_packet() self.start += (self.of_h['length'] - OF_HEADER_SIZE) - # remove this: - print + # print def prepare_printing(self, string, values): self.of_body[string] = values @@ -100,6 +103,7 @@ def print_packet(self): of10.prints.print_body(self) # elif self.of_h['version'] is 4: # print of13.prints.print_body(self) + print def check_filters(self): # Was -F submitted? diff --git a/gen/tcpip.py b/gen/tcpip.py index f5e0098..37a75c2 100644 --- a/gen/tcpip.py +++ b/gen/tcpip.py @@ -23,11 +23,12 @@ def get_ethertype(etype): 34925: 'IPv6', 34887: 'MPLS', 35020: 'LLDP', - 35138: 'BBDP'} + 35138: 'BBDP', + 34998: 'PRIVATE'} try: return '%s(%s)' % (etypes[etype], hex(etype)) except: - return etype + return hex(etype) def get_ethernet_vlan(packet): @@ -50,14 +51,11 @@ def get_next_etype(packet): def get_arp(packet): arp_raw = packet[:28] arp = unpack('!HHBBH6sL6sL', arp_raw) - src_ip = arp[6] - dst_ip = arp[8] arp_frame = {'hw_type': arp[0], 'prot_type': arp[1], 'hw_len': arp[2], 'prot_len': arp[3], 'opcode': arp[4], 'src_mac': arp[5], - 'src_ip': src_ip, 'dst_mac': arp[7], 'dst_ip': dst_ip} + 'src_ip': arp[6], 'dst_mac': arp[7], 'dst_ip': arp[8]} return arp_frame - def get_ip_packet(packet, eth_length): ''' Returns IP Header fields diff --git a/of10/dissector.py b/of10/dissector.py index ac37471..4070aec 100644 --- a/of10/dissector.py +++ b/of10/dissector.py @@ -123,6 +123,13 @@ def get_ofp_command(command): return 'UnknownCommand(%s)' % command +def get_vlan(vlan): + vlans = {65535: 'Untagged(0xFFFF)'} + try: + return vlans[vlan] + except: + return vlan + def get_ofp_flags(flag): flags = {0: 'NoFlagSet(0)', 1: 'SendFlowRem(1)', diff --git a/of10/parser.py b/of10/parser.py index 0e99237..f2ca090 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -13,56 +13,50 @@ def process_ofp_type(pkt): - of_type = pkt.of_h['type'] - of_xid = pkt.of_h['xid'] - print_options = pkt.print_options - h_size = 0 - packet = pkt.this_packet - - if of_type == 0: + if pkt.of_h['type'] == 0: result = parse_Hello(pkt) - elif of_type == 1: + elif pkt.of_h['type'] == 1: result = parse_Error(pkt) - elif of_type == 2: + elif pkt.of_h['type'] == 2: result = parse_EchoReq(pkt) - elif of_type == 3: + elif pkt.of_h['type'] == 3: result = parse_EchoRes(pkt) - elif of_type == 4: - result = parse_Vendor(packet, h_size, of_xid) - elif of_type == 5: + elif pkt.of_h['type'] == 4: + result = parse_Vendor(pkt) + elif pkt.of_h['type'] == 5: result = parse_FeatureReq(pkt) - elif of_type == 6: - result = parse_FeatureRes(packet, h_size, of_xid) - elif of_type == 7: - result = parse_GetConfigReq(packet, h_size, of_xid) - elif of_type == 8: - result = parse_GetConfigRes(packet, h_size, of_xid) - elif of_type == 9: - result = parse_SetConfig(packet, h_size, of_xid) - elif of_type == 10: + elif pkt.of_h['type'] == 6: + result = parse_FeatureRes(pkt) + elif pkt.of_h['type'] == 7: + result = parse_GetConfigReq(pkt) + elif pkt.of_h['type'] == 8: + result = parse_GetConfigRes(pkt) + elif pkt.of_h['type'] == 9: + result = parse_SetConfig(pkt) + elif pkt.of_h['type'] == 10: result = parse_PacketIn(pkt) - elif of_type == 11: + elif pkt.of_h['type'] == 11: result = parse_FlowRemoved(pkt) - elif of_type == 12: + elif pkt.of_h['type'] == 12: result = parse_PortStatus(pkt) - elif of_type == 13: + elif pkt.of_h['type'] == 13: result = parse_PacketOut(pkt) - elif of_type == 14: - result = parse_FlowMod(packet, h_size, of_xid, print_options) - elif of_type == 15: - result = parse_PortMod(packet, h_size, of_xid) - elif of_type == 16: + elif pkt.of_h['type'] == 14: + result = parse_FlowMod(pkt) + elif pkt.of_h['type'] == 15: + result = parse_PortMod(pkt) + elif pkt.of_h['type'] == 16: result = parse_StatsReq(pkt) -# elif of_type == 17: -# result = parse_StatsRes(packet, h_size, of_xid) - elif of_type == 18: + elif pkt.of_h['type'] == 17: + result = parse_StatsRes(pkt) + elif pkt.of_h['type'] == 18: result = parse_BarrierReq(pkt) - elif of_type == 19: + elif pkt.of_h['type'] == 19: result = parse_BarrierRes(pkt) - elif of_type == 20: - result = parse_QueueGetConfigReq(packet, h_size, of_xid) - elif of_type == 21: - result = parse_QueueGetConfigRes(packet, h_size, of_xid) + elif pkt.of_h['type'] == 20: + result = parse_QueueGetConfigReq(pkt) + elif pkt.of_h['type'] == 21: + result = parse_QueueGetConfigRes(pkt) else: return 0 return result @@ -71,7 +65,6 @@ def process_ofp_type(pkt): # *************** Hello ***************** def parse_Hello(pkt): pkt.prepare_printing('print_of_hello', None) - pkt.print_packet() return 1 @@ -82,41 +75,38 @@ def parse_Error(pkt): error = {'type': ofe[0], 'code': ofe[1]} pkt.prepare_printing('print_of_error', error) - pkt.print_packet() return 1 # ************ EchoReq ***************** def parse_EchoReq(pkt): pkt.prepare_printing('print_echoreq', None) - pkt.print_packet() return 1 # ************ EchoRes ***************** def parse_EchoRes(pkt): pkt.prepare_printing('print_echores', None) - pkt.print_packet() return 1 # ************ Vendor ****************** -def parse_Vendor(packet, h_size, of_xid): - of_vendor = packet[h_size:h_size+4] +def parse_Vendor(pkt): + of_vendor = pkt.this_packet[0:4] ofv = unpack('!L', of_vendor) - of10.prints.print_of_vendor(ofv[0], of_xid) + pkt.prepare_printing('print_of_vendor', ofv[0]) + # Future - version 0.4 # If code 8992 = NICIRA - if ofv[0] == 8992: - of10.vendors.parse_nicira(packet, h_size+4, of_xid) - print + #if ofv[0] == 8992: + # of10.vendors.parse_nicira(packet, h_size+4, of_xid) + return 1 # *********** FeatureReq *************** def parse_FeatureReq(pkt): pkt.prepare_printing('print_of_feature_req', None) - pkt.print_packet() return 1 @@ -156,7 +146,7 @@ def _parse_phy_curr(values): return _parse_bitmask(values, confs) -def _parse_phy_ports(packet, of_xid): +def _parse_phy_ports(packet): phy = unpack('!H6s16sLLLLLL', packet) port_id = of10.dissector.get_phy_port_id(phy[0]) @@ -180,33 +170,35 @@ def _parse_phy_ports(packet, of_xid): return phy_ports -def parse_FeatureRes(packet, h_size, of_xid): - of_fres = packet[h_size:h_size+24] +def parse_FeatureRes(pkt): + of_fres = pkt.this_packet[0:24] ofrs = unpack('!8sLB3sLL', of_fres) f_res = {'datapath_id': ofrs[0], 'n_buffers': ofrs[1], 'n_tbls': ofrs[2], 'pad': ofrs[3]} - of10.prints.print_of_feature_res(of_xid, f_res) + pkt.prepare_printing('print_of_feature_res', f_res) # 'capabilities': ofrs[4], 'actions': ofrs[5]} caps = [] caps = _parse_capabilities(ofrs[4]) + pkt.prepare_printing('print_of_feature_res_caps', caps) + actions = [] actions = _parse_actions(ofrs[5]) - of10.prints.print_of_feature_res_caps_and_actions(of_xid, caps, actions) + pkt.prepare_printing('print_of_feature_res_actions', actions) # Ports description? - start = h_size + 24 - while len(packet[start:]) > 0: - ports = _parse_phy_ports(packet[start:start+48], of_xid) - of10.prints.print_of_feature_res_ports(of_xid, ports) + start = 24 + while len(pkt.this_packet[start:]) > 0: + ports = _parse_phy_ports(pkt.this_packet[start:start+48]) + pkt.prepare_printing('print_of_feature_res_ports', ports) start = start + 48 return 1 # ***************** GetConfigReq ********************* -def parse_GetConfigReq(packet, h_size, of_xid): - of10.prints.print_of_getconfig_req(of_xid) +def parse_GetConfigReq(pkt): + pkt.prepare_printing('print_of_getconfig_req', pkt) return 1 @@ -216,19 +208,19 @@ def _parse_SetGetConfig(packet, h_size): pkt_list = unpack('!HH', pkt_raw) flag = of10.dissector.get_configres_flags(pkt_list[0]) miss_send_len = pkt_list[1] - return flag, miss_send_len + return {'flag': flag, 'miss_send_len': miss_send_len} -def parse_GetConfigRes(packet, h_size, of_xid): - flag, miss_send_len = _parse_SetGetConfig(packet, h_size) - of10.prints.print_ofp_getConfigRes(of_xid, flag, miss_send_len) +def parse_GetConfigRes(pkt): + getConfig = _parse_SetGetConfig(pkt.this_packet, 0) + pkt.prepare_printing('print_ofp_getConfigRes', getConfig) return 1 # ******************* SetConfig ********************** -def parse_SetConfig(packet, h_size, of_xid): - flag, miss_send_len = _parse_SetGetConfig(packet, h_size) - of10.prints.print_ofp_setConfig(of_xid, flag, miss_send_len) +def parse_SetConfig(pkt): + setConfig = _parse_SetGetConfig(pkt.this_packet, 0) + pkt.prepare_printing('print_ofp_setConfig', setConfig) return 1 @@ -274,7 +266,7 @@ def _parse_other_types(packet, start, eth, pkt): pkt.prepare_printing('print_tcp', tcp) elif eth['protocol'] in [2054]: arp = gen.tcpip.get_arp(packet[start:]) - pkt.prepare_printing('print_arp', arp) + # pkt.prepare_printing('print_arp', arp) else: string = 'Ethertype %s not dissected' % hex(eth['protocol']) message = {'message': string} @@ -290,7 +282,6 @@ def _print_packetIn(of_xid, packetIn, eth, vlan, lldp): of10.prints.print_packetInOut_lldp(of_xid, lldp) -# def parse_PacketIn(packet, h_size, of_xid, sanitizer): def parse_PacketIn(pkt): # buffer_id(32), total_len(16), in_port(16), reason(8), pad(8) pkt_raw = pkt.this_packet[0:10] @@ -313,8 +304,6 @@ def parse_PacketIn(pkt): else: pkt.prepare_printing('print_lldp', lldp) - pkt.print_packet() - # If we have filters (-F) # filters = sanitizer['packetIn_filter'] @@ -349,7 +338,6 @@ def parse_FlowRemoved(pkt): 'packet_count': ofrem[9], 'byte_count': ofrem[10]} pkt.prepare_printing('print_ofp_flow_removed', ofrem) - pkt.print_packet() return 1 @@ -361,9 +349,8 @@ def parse_PortStatus(pkt): p_status = {'reason': reason, 'pad': port[1]} pkt.prepare_printing('print_portStatus', p_status) - ports = _parse_phy_ports(pkt.this_packet[8:64], pkt.of_h['xid']) + ports = _parse_phy_ports(pkt.this_packet[8:64]) pkt.prepare_printing('print_of_feature_res_ports', ports) - pkt.print_packet() return 1 @@ -372,16 +359,22 @@ def parse_PacketOut(pkt): # buffer_id(32), in_port(16), actions_len(16) pkt_raw = pkt.this_packet[0:8] p_out = unpack('!LHH', pkt_raw) - actions_len = p_out[2] packetOut = {'buffer_id': p_out[0], 'in_port': p_out[1], - 'actions_len': actions_len} + 'actions_len': p_out[2]} pkt.prepare_printing('print_packetOut', packetOut) # Actions start = 8 - _parse_OFAction(pkt.this_packet[start:start+packetOut['actions_len']], 0) + actions_dict = _parse_OFAction(pkt.this_packet[start:start+packetOut['actions_len']], 0) + pkt.prepare_printing('print_actions', actions_dict) + + start = start + packetOut['actions_len'] + + # Check if we still have content in the PacketOut + if len(pkt.this_packet[start:]) == 0: + return 1 + # Ethernet - start = 8 + packetOut['actions_len'] eth = gen.tcpip.get_ethernet_frame(pkt.this_packet[start:start+14], 1) pkt.prepare_printing('print_layer2_pktIn', eth) start = start + 14 @@ -407,7 +400,6 @@ def parse_PacketOut(pkt): gen.proxies.support_fsfw(pkt.print_options, lldp) pkt.prepare_printing('print_lldp', lldp) - pkt.print_packet() return 1 @@ -462,10 +454,10 @@ def _parse_OFMatch(packet, h_size): 'tp_dst': ofm[14]} if wildcard >= ((1 << 22) - 1): - ofmatch = {'wildcards': '4194303'} + ofmatch = {'wildcards': 4194303} return ofmatch elif wildcard == 0: - ofmatch = {'wildcards': '0'} + ofmatch = {'wildcards': 0} return ofmatch else: src_netmask = process_src_subnet(wildcard) @@ -562,7 +554,7 @@ def get_action(action_type, length, payload): return type_f[0] -def _parse_OFAction(packet, start, ofactions=[]): +def _parse_OFAction(packet, start): ''' Actions ''' @@ -572,6 +564,8 @@ def _parse_OFAction(packet, start, ofactions=[]): # 0 for type 3 # 12 for types 4,5,b action_header = 4 + # Add all actions to a list for future printing + actions_list = [] while (1): ofp_action = packet[start:start + action_header] if len(ofp_action) > 0: @@ -588,56 +582,38 @@ def _parse_OFAction(packet, start, ofactions=[]): total_length = 4 ofa_action_payload = packet[start:start + 4] - ofa_temp = of10.prints.print_ofp_action(ofa_type, - ofa_length, - ofa_action_payload) - # Print OVS format - ofactions.append(ofa_temp) - ofactions.append(',') + actions_dict = {'type': ofa_type, 'length': ofa_length, + 'payload': ofa_action_payload} + actions_list.append(actions_dict) # Next packet would start at.. start = start + total_length else: break - return ofactions - + return actions_list -def parse_FlowMod(packet, h_size, of_xid, print_options): - ofmatch = _parse_OFMatch(packet, h_size) - of10.prints.print_ofp_match(of_xid, ofmatch) - - ofbody = _parse_OFBody(packet, h_size) - of10.prints.print_ofp_body(of_xid, ofbody) +def parse_FlowMod(pkt): + ofmatch = _parse_OFMatch(pkt.this_packet, 0) + pkt.prepare_printing("print_ofp_match", ofmatch) - if ofbody['command'] == 3: - ovs_command = 'del-flows' - else: - ovs_command = 'add-flow' + ofbody = _parse_OFBody(pkt.this_packet, 0) + pkt.prepare_printing("print_ofp_body", ofbody) - # Print OVS ofactions = [] - ofactions.append("action=") # Actions: Header = 4 , plus each possible action - # Payload varies: - # 4 for types 0,1,2,6,7,8,9,a,ffff - # 0 for type 3 - # 12 for types 4,5,b - start = h_size+64 - - ofactions = _parse_OFAction(packet, start, ofactions) + actions_start = 64 + actions_dict = _parse_OFAction(pkt.this_packet, actions_start) + pkt.prepare_printing('print_actions', actions_dict) - if print_options['ovs'] == 1: - of10.prints.print_ofp_ovs(print_options, ofmatch, ofactions, - ovs_command, ofbody['priority']) return 1 # ********************* PortMod **************************** -def parse_PortMod(packet, h_size, of_xid): +def parse_PortMod(pkt): # port(16), hw_addr(48), config(32), mask(32), advertise(32), pad(32) - pmod_raw = packet[h_size:h_size+24] + pmod_raw = pkt.this_packet[0:24] pmod = unpack('!H6sLLLL', pmod_raw) config = _parse_phy_config(pmod[2]) @@ -646,7 +622,7 @@ def parse_PortMod(packet, h_size, of_xid): portMod = {'port': pmod[0], 'hw_addr': pmod[1], 'config': config, 'mask': mask, 'advertise': advertise, 'pad': pmod[5]} - of10.prints.print_PortMod(of_xid, portMod) + pkt.prepare_printing('print_PortMod', portMod) return 1 @@ -662,7 +638,7 @@ def parse_StatsReq(pkt): stat_type = ofstat[0] # FLags were not defined yet. Ignoring. # flags = ofstat[1] - start = h_size+4 + start = 4 # 7 Types available if stat_type == 0: @@ -673,132 +649,145 @@ def parse_StatsReq(pkt): elif stat_type == 1 or stat_type == 2: # Flow(1) or Aggregate(2) # Fields: match(40), table_id(8), pad(8), out_port(16) - of_match = _parse_OFMatch(packet, start) + of_match = _parse_OFMatch(pkt.this_packet, start) # 44 Bytes (40B from Match, 4 from header) of_stat_req = pkt.this_packet[start+40:start+40+4] ofstat = unpack('!BBH', of_stat_req) table_id = ofstat[0] pad = ofstat[1] out_port = ofstat[2] - of10.prints.print_ofp_statReqFlowAggregate(of_xid, stat_type, - of_match, table_id, pad, - out_port) + stats = {'type': stat_type, 'match': of_match, 'table_id': table_id, 'pad': pad, + 'out_port': out_port} + pkt.prepare_printing('print_ofp_statReqFlowAggregate', stats) + elif stat_type == 3: # Table # No extra fields - of10.prints.print_ofp_statReqTable(of_xid, stat_type) + pkt.prepare_printing('print_ofp_statReqTable', stat_type) elif stat_type == 4: # Port # Fields: port_number(16), pad(48) - of_stat_req = packet[start:start+8] + of_stat_req = pkt.this_packet[start:start+8] ofstat = unpack('!H6s', of_stat_req) port_number = ofstat[0] pad = ofstat[1] - of10.prints.print_ofp_statReqPort(of_xid, stat_type, port_number, - pad) + stats = {'type': stat_type, 'port_number': port_number, 'pad': pad} + pkt.prepare_printing('print_ofp_statReqPort', stats) elif stat_type == 5: # Queue # Fields: port_number(16), pad(16), queue_id(32) - of_stat_req = packet[start:start+8] + of_stat_req = pkt.this_packet[start:start+8] ofstat = unpack('!HHL', of_stat_req) port_number = ofstat[0] pad = ofstat[1] queue_id = ofstat[2] - of10.prints.print_ofp_statReqQueue(of_xid, stat_type, port_number, - pad, queue_id) + stats = {'type': stat_type, 'port_number': port_number, 'pad': pad, + 'queue_id': queue_id} + pkt.prepare_printing('print_ofp_statReqQueue', stats) + elif stat_type == 65535: # Vendor # Fields: vendor_id(32) + data - of_stat_req = packet[start:start+4] + of_stat_req = pkt.this_packet[start:start+4] ofstat = unpack('!L', of_stat_req) vendor_id = ofstat[0] - of10.prints.print_ofp_statReqVendor(of_xid, stat_type, vendor_id) + stats = {'type': stat_type, 'vendor_id': vendor_id} + pkt.prepare_printing('print_ofp_statReqVendor', stats) else: - print ('%s StatReq: Unknown Type: %s' % (of_xid, stat_type)) - return 0 + print 'StatReq: Unknown Type: %s' % stat_type + return 1 # *********************** StatsRes **************************** -# Actions need to be handled -def parse_StatsRes(packet, h_size, of_xid): +def parse_StatsRes(pkt): # Get type = 16bits # Get flags = 16bits - of_stat_req = packet[h_size:h_size+4] + of_stat_req = pkt.this_packet[0:4] ofstat = unpack('!HH', of_stat_req) stat_type = ofstat[0] # flags = ofstat[1] - start = h_size+4 + start = 4 # 7 Types available if stat_type == 0: # Description # Fields: mfr_desc(2048), hw_desc(2048), sw_desc(2048), serial_num(256), # dp_desc(2048) - desc_raw = packet[start:start+1056] + desc_raw = pkt.this_packet[start:start+1056] desc = unpack('!256s256s256s32s256s', desc_raw) - mfr_desc = desc[0] - hw_desc = desc[1] - sw_desc = desc[2] - serial_num = desc[3] - dp_desc = desc[4] - of10.prints.print_ofp_statResDesc(of_xid, stat_type, mfr_desc, - hw_desc, sw_desc, serial_num, - dp_desc) + stats = {'mfr_desc': desc[0], + 'hw_desc': desc[1], + 'sw_desc': desc[2], + 'serial_num': desc[3], + 'dp_desc': desc[4], + 'type': stat_type} + pkt.prepare_printing('print_ofp_statResDesc', stats) elif stat_type == 1: # Flow(1) # Fields: length(16), table_id(8), pad(8), match(40), duration_sec(32), # duration_nsec(32), priority(16), idle_timeout(16), hard_timeout(16), # pad(48), cookie(64), packet_count(64), byte_count(64), actions[] - count = len(packet[h_size:]) - 4 + count = len(pkt.this_packet[0:]) - 4 + flows = [] while (count > 0): - flow_raw = packet[start:start+4] + flow_raw = pkt.this_packet[start:start+4] flow = unpack('!HBB', flow_raw) res_flow = {'length': flow[0], 'table_id': flow[1], 'pad': flow[2]} - of_match = _parse_OFMatch(packet, start+4) - flow_raw = packet[start+44:start+44+44] + of_match = _parse_OFMatch(pkt.this_packet, start+4) + + flow_raw = pkt.this_packet[start+44:start+44+44] flow = unpack('!LLHHH6sQQQ', flow_raw) res_flow.update({'duration_sec': flow[0], 'duration_nsec': flow[1], 'priority': flow[2], 'idle_timeout': flow[3], 'hard_timeout': flow[4], 'pad2': flow[5], 'cookie': flow[6], 'packet_count': flow[7], 'byte_count': flow[8]}) + stats = {'type': stat_type, 'match': of_match, 'res_flow': res_flow} - of10.prints.print_ofp_statResFlow(of_xid, stat_type, of_match, - res_flow) # Process Actions[] end = res_flow['length'] - (4 + 40 + 44) - actions = packet[start+88:start+88+end] - _parse_OFAction(actions, 0) + actions = pkt.this_packet[start+88:start+88+end] + actions_dict = _parse_OFAction(actions, 0) + + stats = {'type': stat_type, 'match': of_match, + 'res_flow': res_flow, 'print_actions': actions_dict} + + flows.append(stats) count = count - int(res_flow['length']) start = start + int(res_flow['length']) + # important to have a sequencial list here because there are multiple + # flows. So, print_ofp_statResFlow will print a list of flows. + pkt.prepare_printing('print_ofp_statResFlowArray', flows) + elif stat_type == 2: # Aggregate(2) # Fields: packet_count(64), byte_count(64), flow_count(32), pad(32) - flow_raw = packet[start:start+24] + flow_raw = pkt.this_packet[start:start+24] flow = unpack('!QQLL', flow_raw) - res_flow = {'packet_count': flow[0], 'byte_count': flow[1], - 'flow_count': flow[2], 'pad': flow[3]} - of10.prints.print_ofp_statResAggregate(of_xid, stat_type, res_flow) + res_flow = {'type': stat_type, 'packet_count': flow[0], + 'byte_count': flow[1], 'flow_count': flow[2], + 'pad': flow[3]} + pkt.prepare_printing('print_ofp_statResAggregate', res_flow) elif stat_type == 3: # Table # Fields: table_id(8), pad(24), name(256), wildcards(32), # max_entries(32), active_count(32), lookup_count(64), # matched_count(64) - flow_raw = packet[start:start+64] + flow_raw = pkt.this_packet[start:start+64] flow = unpack('!B3s32sLLLQQ', flow_raw) - res_flow = {'table_id': flow[0], 'pad': flow[1], 'name': flow[2], - 'wildcards': flow[3], 'max_entries': flow[4], - 'active_count': flow[5], 'lookup_count': flow[6], - 'matched_count': flow[7]} - of10.prints.print_ofp_statResTable(of_xid, stat_type, res_flow) + res_flow = {'type': stat_type, 'table_id': flow[0], 'pad': flow[1], + 'name': flow[2], 'wildcards': flow[3], + 'max_entries': flow[4], 'active_count': flow[5], + 'lookup_count': flow[6], 'matched_count': flow[7]} + pkt.prepare_printing('print_ofp_statResTable', res_flow) elif stat_type == 4: # Port @@ -806,116 +795,124 @@ def parse_StatsRes(packet, h_size, of_xid): # rx_bytes(64), tx_bytes(64), rx_dropped(64), tx_dropped(64), # rx_errors(64), tx_errors(64), rx_frame_err(64), rx_over_err(64), # rx_crc_err(64), collisions(64) - count = len(packet[h_size:]) - 4 + count = len(pkt.this_packet[0:]) - 4 + ports = [] while (count > 0): - flow_raw = packet[start:start+104] + flow_raw = pkt.this_packet[start:start+104] flow = unpack('!H6sQQQQQQQQQQQQ', flow_raw) - res_flow = {'port_number': flow[0], 'pad': flow[1], - 'rx_packets': flow[2], 'tx_packets': flow[3], - 'rx_bytes': flow[4], 'tx_bytes': flow[5], - 'rx_dropped': flow[6], 'tx_dropped': flow[7], - 'rx_errors': flow[8], 'tx_errors': flow[9], - 'rx_frame_err': flow[10], 'rx_over_err': flow[11], - 'rx_crc_err': flow[12], 'collisions': flow[13]} - of10.prints.print_ofp_statResPort(of_xid, stat_type, res_flow) + port = {'type': stat_type, 'port_no': flow[0], 'pad': flow[1], + 'rx_packets': flow[2], 'tx_packets': flow[3], + 'rx_bytes': flow[4], 'tx_bytes': flow[5], + 'rx_dropped': flow[6], 'tx_dropped': flow[7], + 'rx_errors': flow[8], 'tx_errors': flow[9], + 'rx_frame_err': flow[10], 'rx_over_err': flow[11], + 'rx_crc_err': flow[12], 'collisions': flow[13]} + + ports.append(port) count = count - 104 start = start + 104 + pkt.prepare_printing('print_ofp_statResPortArray', ports) + elif stat_type == 5: # Queue # Fields: length(16), pad(16), queue_id(32), tx_bytes(64), # tx_packets(64), tx_errors(64) - count = len(packet[h_size:]) - 4 + count = len(pkt.this_packet[0:]) - 4 + queues = [] while (count > 0): - flow_raw = packet[start:start+32] + flow_raw = pkt.this_packet[start:start+32] flow = unpack('!HHLQQQ', flow_raw) - res_flow = {'length': flow[0], 'pad': flow[1], 'queue_id': flow[2], - 'tx_bytes': flow[3], 'tx_packets': flow[4], - 'tx_errors': flow[5]} - of10.prints.print_ofp_statResQueue(of_xid, stat_type, res_flow) + queue = {'length': flow[0], 'pad': flow[1], 'queue_id': flow[2], + 'tx_bytes': flow[3], 'tx_packets': flow[4], + 'tx_errors': flow[5], 'type': stat_type} + queues.append(queue) count = count - 32 start = start + 32 - else: - print ('%s StatRes Type: Queue(%s)' % (of_xid, stat_type)) - print ('%s No Queues' % (of_xid)) + + pkt.prepare_printing('print_ofp_statResQueueArray', queues) elif stat_type == 65535: # Vendor # Fields: vendor_id(32), data(?) - flow_raw = packet[start:start+4] + flow_raw = pkt.this_packet[start:start+4] flow = unpack('!L', flow_raw) - res_flow = {'vendor_id': flow[0]} - of10.prints.print_ofp_statResVendor(of_xid, stat_type, res_flow) - - start = start + 4 - data = [] - count = len(packet[h_size:]) - while (start < count): - flow_raw = packet[start:start+1] - flow = unpack('!B', flow_raw) - data.append(str(flow[0])) - start = start + 1 - of10.prints.print_ofp_statResVendorData(of_xid, ''.join(data)) + vendor_flow = {'type': stat_type, 'vendor_id': flow[0]} + pkt.prepare_printing('print_ofp_statResVendor', vendor_flow) + + + pkt.prepare_printing('print_ofp_statResVendorData', + pkt.this_packet[start+4:]) + #start = start + 4 + #data = [] + #count = len(packet[0:]) + + #import hexdump + #hexdump.hexdump(pkt.this_packet[start:]) + #print + # while (start < count): + # flow_raw = pkt.this_packet[start:start+1] + # flow = unpack('!B', flow_raw) + # data.append(str(flow[0])) + # start = start + 1 + # pkt.prepare_printing('print_ofp_statResVendorData', ''.join(data)) else: - print ('%s StatRes: Unknown Type: %s' % (of_xid, stat_type)) - return 0 + print ('StatRes: Unknown Type: %s' % (stat_type)) return 1 # ********************** BarrierReq *********************** def parse_BarrierReq(pkt): pkt.prepare_printing('print_of_BarrierReq', None) - pkt.print_packet() return 1 # ********************** BarrierRes *********************** def parse_BarrierRes(pkt): pkt.prepare_printing('print_of_BarrierReply', None) - pkt.print_packet() return 1 # ******************* QueueGetConfigReq ******************* -def parse_QueueGetConfigReq(packet, h_size, of_xid): - queue_raw = packet[h_size:h_size+4] +def parse_QueueGetConfigReq(pkt): + queue_raw = pkt.this_packet[0:4] queue = unpack('!HH', queue_raw) queueConfReq = {'port': queue[0], 'pad': queue[1]} - of10.prints.print_queueReq(of_xid, queueConfReq) + pkt.prepare_printing('print_queueReq', queueConfReq) return 1 # ****************** QueueGetConfigRes ******************** -def parse_QueueGetConfigRes(packet, h_size, of_xid): - queue_raw = packet[h_size:h_size+8] +def parse_QueueGetConfigRes(pkt): + queue_raw = pkt.this_packet[0:8] queue = unpack('!H6s', queue_raw) queueConfRes = {'port': queue[0], 'pad': queue[1]} - of10.prints.print_queueRes(of_xid, queueConfRes) + pkt.prepare_printing('print_queueRea', queueConfRea) - start = h_size + 8 - while (packet[start:] > 0): + start = 8 + while (pkt.this_packet[start:] > 0): # Queues - it could be multiple # queue_id(32), length(16), pad(16) - queue_raw = packet[start:start+8] + queue_raw = pkt.this_packet[start:start+8] queue = unpack('!LHH', queue_raw) queues = {'queue_id': queue[0], 'length': queue[1], 'pad': queue[2]} - of10.prints.print_queues(of_xid, queues) + of10.prints.print_queues(queues) q_start = start + 8 # Look of properties # property(16), length(16), pad(32), rate(16), pad(48) - properties = packet[q_start:q_start+queues['length']-8] + properties = pkt.this_packet[q_start:q_start+queues['length']-8] while (len(properties[q_start:]) > 0): - prop_raw = packet[q_start:q_start+8] + prop_raw = pkt.this_packet[q_start:q_start+8] prop = unpack('!HHLH6s', prop_raw) properties = {'type': prop[0], 'length': prop[1], 'pad': prop[2], 'rate': prop[3], 'pad2': prop[4]} - of10.prints.print_queueRes_properties(of_xid, properties) + of10.prints.print_queueRes_properties(properties) start = start + queues['length'] diff --git a/of10/prints.py b/of10/prints.py index d4cd500..cf21bb4 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -32,6 +32,14 @@ def print_layer2_pktIn(pkt): gen.prints.print_layer2(pkt.of_body['print_layer2_pktIn']) +def print_tcp(pkt): + gen.prints.print_tcp(pkt.l4) + + +def print_layer3(pkt): + gen.prints.print_layer3(pkt.of_body['print_layer3']) + + def print_lldp(pkt): gen.prints.print_lldp(pkt) @@ -59,24 +67,28 @@ def print_of_feature_req(pkt): print 'OpenFlow Feature Request' -def print_of_getconfig_req(of_xid): - print '%s OpenFlow GetConfig Request' % of_xid +def print_of_getconfig_req(pkt): + print 'OpenFlow GetConfig Request' -def print_of_feature_res(of_xid, f_res): - print '%s OpenFlow Feature Reply' % of_xid +def print_of_feature_res(pkt): + f_res = pkt.of_body['print_of_feature_res'] + print 'OpenFlow Feature Reply' dpid = datapath_id(f_res['datapath_id']) - print ('%s FeatureRes - datapath_id: %s n_buffers: %s n_tbls: %s, pad: %s' - % (of_xid, green(dpid), f_res['n_buffers'], f_res['n_tbls'], - f_res['pad'])) + print ('FeatureRes - datapath_id: %s n_buffers: %s n_tbls: %s, pad: %s' + % (green(dpid), f_res['n_buffers'], f_res['n_tbls'], f_res['pad'])) -def print_of_feature_res_caps_and_actions(of_xid, caps, actions): - print ('%s FeatureRes - Capabilities:' % of_xid), +def print_of_feature_res_caps(pkt): + caps = pkt.of_body['print_of_feature_res_caps'] + print ('FeatureRes - Capabilities:'), for i in caps: print of10.dissector.get_feature_res_capabilities(i), print - print ('%s FeatureRes - Actions:' % of_xid), + +def print_of_feature_res_actions(pkt): + actions = pkt.of_body['print_of_feature_res_actions'] + print ('FeatureRes - Actions:'), for i in actions: print of10.dissector.get_feature_res_actions(i), print @@ -88,11 +100,12 @@ def _dont_print_0(printed): return False -def print_of_feature_res_ports(of_xid, ports): - print ('%s FeatureRes - port_id: %s hw_addr: %s name: %s' % (of_xid, +def print_of_feature_res_ports(pkt): + ports = pkt.of_body['print_of_feature_res_ports'] + print ('FeatureRes - port_id: %s hw_addr: %s name: %s' % ( green(ports['port_id']), green(ports['hw_addr']), green(ports['name']))) - print ('%s FeatureRes - config:' % of_xid), + print ('FeatureRes - config:'), printed = False for i in ports['config']: print of10.dissector.get_phy_config(i), @@ -100,35 +113,35 @@ def print_of_feature_res_ports(of_xid, ports): else: printed = _dont_print_0(printed) print - print ('%s FeatureRes - state:' % of_xid), + print ('FeatureRes - state:'), for i in ports['state']: print of10.dissector.get_phy_state(i), printed = True else: printed = _dont_print_0(printed) print - print ('%s FeatureRes - curr:' % of_xid), + print ('FeatureRes - curr:'), for i in ports['curr']: print of10.dissector.get_phy_feature(i), printed = True else: printed = _dont_print_0(printed) print - print ('%s FeatureRes - advertised:' % of_xid), + print ('FeatureRes - advertised:'), for i in ports['advertised']: print of10.dissector.get_phy_feature(i), printed = True else: printed = _dont_print_0(printed) print - print ('%s FeatureRes - supported:' % of_xid), + print ('FeatureRes - supported:'), for i in ports['supported']: print of10.dissector.get_phy_feature(i), printed = True else: printed = _dont_print_0(printed) print - print ('%s FeatureRes - peer:' % of_xid), + print ('FeatureRes - peer:'), for i in ports['peer']: print of10.dissector.get_phy_feature(i), printed = True @@ -137,114 +150,129 @@ def print_of_feature_res_ports(of_xid, ports): print -def print_ofp_match(xid, ofmatch): - if xid == '': - print 'OpenFlow Match -', - else: - print ('%s OpenFlow Match -' % (xid)), +def print_ofp_match(pkt): + ofmatch = pkt.of_body['print_ofp_match'] + print 'Match -' , for K in ofmatch: - print ("%s: %s" % (K, green(ofmatch[K]))), + value = ofmatch[K] + if K is 'dl_vlan': + value = of10.dissector.get_vlan(value) + elif K is 'wildcards': + value = hex(value) + elif K is 'dl_type': + value = gen.tcpip.get_ethertype(int(value, 16)) + + print ("%s: %s" % (K, green(value))), + print -def print_ofp_body(xid, ofbody): - string = ('%s OpenFlow Body - Cookie: %s Command: %s Idle/Hard Timeouts: ' - '%s/%s Priority: %s Buffer ID: %s Out Port: %s Flags: %s') +def print_ofp_body(pkt): + ofbody = pkt.of_body['print_ofp_body'] + string = ('Body - Cookie: %s Command: %s Idle/Hard Timeouts: ' + '%s/%s\nBody - Priority: %s Buffer ID: %s Out Port: %s Flags: %s') command = green(of10.dissector.get_ofp_command(ofbody['command'])) flags = green(of10.dissector.get_ofp_flags(ofbody['flags'])) + out_port = green(of10.dissector.get_phy_port_id(ofbody['out_port'])) - print string % (xid, ofbody['cookie'], command, ofbody['idle_timeout'], + print string % (ofbody['cookie'], command, ofbody['idle_timeout'], ofbody['hard_timeout'], ofbody['priority'], - ofbody['buffer_id'], ofbody['out_port'], flags) + ofbody['buffer_id'], out_port, flags) -def print_ofp_flow_removed(xid, ofrem): - string = ('%s OpenFlow Body - Cookie: %s Priority: %s Reason: %s Pad: %s ' +def print_ofp_flow_removed(pkt): + ofrem = pkt.of_body['print_ofp_flow_removed'] + string = ('Body - Cookie: %s Priority: %s Reason: %s Pad: %s ' 'Duration Secs/NSecs: %s/%s Idle Timeout: %s Pad2/Pad3: %s/%s' ' Packet Count: %s Byte Count: %s') - print string % (xid, ofrem['cookie'], ofrem['priority'], + print string % (ofrem['cookie'], ofrem['priority'], red(ofrem['reason']), ofrem['pad'], ofrem['duration_sec'], ofrem['duration_nsec'], ofrem['idle_timeout'], ofrem['pad2'], ofrem['pad3'], ofrem['packet_count'], ofrem['byte_count']) +def print_actions(pkt): + for action in pkt.of_body['print_actions']: + print_ofp_action(action['type'], action['length'], action['payload']) + + def print_ofp_action(action_type, length, payload): if action_type == 0: port, max_len = of10.parser.get_action(action_type, length, payload) port = of10.dissector.get_phy_port_id(port) - print ('OpenFlow Action - Type: %s Length: %s Port: %s ' + print ('Action - Type: %s Length: %s Port: %s ' 'Max Length: %s' % (green('OUTPUT'), length, green(port), max_len)) return 'output:' + port elif action_type == 1: vlan, pad = of10.parser.get_action(action_type, length, payload) - print ('OpenFlow Action - Type: %s Length: %s VLAN ID: %s Pad: %s' % + print ('Action - Type: %s Length: %s VLAN ID: %s Pad: %s' % (green('SetVLANID'), length, green(str(vlan)), pad)) return 'mod_vlan_vid:' + str(vlan) elif action_type == 2: vlan_pc, pad = of10.parser.get_action(action_type, length, payload) - print ('OpenFlow Action - Type: %s Length: %s VLAN PCP: %s Pad: %s' % + print ('Action - Type: %s Length: %s VLAN PCP: %s Pad: %s' % (green('SetVLANPCP'), length, green(str(vlan_pc)), pad)) return 'mod_vlan_pcp:' + str(vlan_pc) elif action_type == 3: - print ('OpenFlow Action - Type: %s Length: %s' % + print ('Action - Type: %s Length: %s' % (green('StripVLAN'), length)) return 'strip_vlan' elif action_type == 4: setDLSrc, pad = of10.parser.get_action(action_type, length, payload) - print ('OpenFlow Action - Type: %s Length: %s SetDLSrc: %s Pad: %s' % + print ('Action - Type: %s Length: %s SetDLSrc: %s Pad: %s' % (green('SetDLSrc'), length, green(str(eth_addr(setDLSrc))), pad)) return 'mod_dl_src:' + str(eth_addr(setDLSrc)) elif action_type == 5: setDLDst, pad = of10.parser.get_action(action_type, length, payload) - print ('OpenFlow Action - Type: %s Length: %s SetDLDst: %s Pad: %s' % + print ('Action - Type: %s Length: %s SetDLDst: %s Pad: %s' % (green('SetDLDst'), length, green(str(eth_addr(setDLDst))), pad)) return 'mod_dl_dst:' + str(eth_addr(setDLDst)) elif action_type == 6: nw_addr = of10.parser.get_action(action_type, length, payload) - print ('OpenFlow Action - Type: %s Length: %s SetNWSrc: %s' % + print ('Action - Type: %s Length: %s SetNWSrc: %s' % (green('SetNWSrc'), length, green(str(nw_addr)))) return 'mod_nw_src:' + str(nw_addr) elif action_type == 7: nw_addr = of10.parser.get_action(action_type, length, payload) - print ('OpenFlow Action - Type: %s Length: %s SetNWDst: %s' % + print ('Action - Type: %s Length: %s SetNWDst: %s' % (green('SetNWDst'), length, green(str(nw_addr)))) return 'mod_nw_src:' + str(nw_addr) elif action_type == 8: nw_tos, pad = of10.parser.get_action(action_type, length, payload) - print ('OpenFlow Action - Type: %s Length: %s SetNWTos: %s Pad: %s' % + print ('Action - Type: %s Length: %s SetNWTos: %s Pad: %s' % (green('SetNWTos'), length, green(str(nw_tos)), pad)) return 'mod_nw_tos:' + str(nw_tos) elif action_type == 9: port, pad = of10.parser.get_action(action_type, length, payload) - print ('OpenFlow Action - Type: %s Length: %s SetTPSrc: %s Pad: %s' % + print ('Action - Type: %s Length: %s SetTPSrc: %s Pad: %s' % (green('SetTPSrc'), length, green(str(port)), pad)) return 'mod_tp_src:' + str(port) elif action_type == int('a', 16): port, pad = of10.parser.get_action(action_type, length, payload) - print ('OpenFlow Action - Type: %s Length: %s SetTPDst: %s Pad: %s' % + print ('Action - Type: %s Length: %s SetTPDst: %s Pad: %s' % (green('SetTPDst'), length, green(str(port)), pad)) return 'mod_tp_dst:' + str(port) elif action_type == int('b', 16): port, pad, queue_id = of10.parser.get_action(action_type, length, payload) - print (('OpenFlow Action - Type: %s Length: %s Enqueue: %s Pad: %s' + print (('Action - Type: %s Length: %s Enqueue: %s Pad: %s' ' Queue: %s') % (green('Enqueue'), length, green(str(port)), pad, green(str(queue_id)))) @@ -252,7 +280,7 @@ def print_ofp_action(action_type, length, payload): elif action_type == int('ffff', 16): vendor = of10.parser.get_action(action_type, length, payload) - print ('OpenFlow Action - Type: %s Length: %s Vendor: %s' % + print ('Action - Type: %s Length: %s Vendor: %s' % (green('VENDOR'), length, green(str(vendor)))) return 'VendorType' @@ -284,8 +312,8 @@ def print_ofp_ovs(print_options, ofmatch, ofactions, ovs_command, prio): return -def _print_portMod_config_mask(of_xid, array, name): - print ('%s PortMod %s:' % (of_xid, name)), +def _print_portMod_config_mask(array, name): + print ('PortMod %s:' % (name)), printed = False for i in array[name]: print of10.dissector.get_phy_config(i), @@ -295,13 +323,13 @@ def _print_portMod_config_mask(of_xid, array, name): print -def print_PortMod(of_xid, portMod): - print ('%s PortMod Port: %s HW Addr %s Pad: %s' % - (of_xid, portMod['port'], eth_addr(portMod['hw_addr']), - portMod['pad'])) - _print_portMod_config_mask(of_xid, portMod, 'config') - _print_portMod_config_mask(of_xid, portMod, 'mask') - _print_portMod_config_mask(of_xid, portMod, 'advertise') +def print_PortMod(pkt): + portMod = pkt.of_body['print_PortMod'] + print ('PortMod Port: %s HW Addr %s Pad: %s' % + (portMod['port'], eth_addr(portMod['hw_addr']), portMod['pad'])) + _print_portMod_config_mask(portMod, 'config') + _print_portMod_config_mask(portMod, 'mask') + _print_portMod_config_mask(portMod, 'advertise') def print_of_BarrierReq(pkt): @@ -312,132 +340,184 @@ def print_of_BarrierReply(pkt): print 'OpenFlow Barrier Reply' -def print_of_vendor(of_vendor, of_xid): +def print_of_vendor(pkt): + of_vendor = pkt.of_body['print_of_vendor'] vendor = of10.dissector.get_ofp_vendor(of_vendor) - print ('%s OpenFlow Vendor: %s' % (of_xid, vendor)) + print ('OpenFlow Vendor: %s' % vendor) -def print_ofp_statReqDesc(of_xid, stat_type): - print ('%s StatReq Type: Description(%s)' % (of_xid, stat_type)) +def print_ofp_statReqDesc(pkt): + print 'StatReq Type: Description(%s)' % pkt.of_body['print_ofp_statReqDesc'] -def print_ofp_statReqFlowAggregate(of_xid, stat_type, of_match, table_id, pad, - out_port): - if stat_type == 1: +def print_ofp_statReqFlowAggregate(pkt): + stats = pkt.of_body['print_ofp_statReqFlowAggregate'] + if stats['type'] == 1: type_name = 'Flow' else: type_name = 'Aggregate' - print ('%s StatReq Type: %s(%s)' % (of_xid, type_name, stat_type)) - print_ofp_match(of_xid, of_match) - print ('%s StatReq Table_id: %s Pad: %d Out_Port: %s' % (of_xid, table_id, - pad, out_port)) + print ('StatReq Type: %s(%s)' % (type_name, stats['type'])) + pkt.of_body['print_ofp_match'] = stats['match'] + print_ofp_match(pkt) + print ('StatReq Table_id: %s Pad: %d Out_Port: %s' % (stats['table_id'], + stats['pad'], stats['out_port'])) -def print_ofp_statReqTable(of_xid, stat_type): - print ('%s StatReq Type: Table(%s)' % (of_xid, stat_type)) +def print_ofp_statReqTable(pkt): + print 'StatReq Type: Table(%s)' % pkt.of_body['print_ofp_statReqTable'] -def print_ofp_statReqPort(of_xid, stat_type, port_number, pad): - print ('%s StatReq Type: Port(%s): Port_Number: %s Pad: %s' % (of_xid, - stat_type, green(port_number), pad)) +def print_ofp_statReqPort(pkt): + stats = pkt.of_body['print_ofp_statReqPort'] + stat_type = stats['type'] + port_number = of10.dissector.get_phy_port_id(stats['port_number']) + pad = stats['pad'] + print ('StatReq Type: Port(%s): Port_Number: %s Pad: %s' % + (stat_type, green(port_number), pad)) -def print_ofp_statReqQueue(of_xid, stat_type, port_number, pad, queue_id): - print ('%s StatReq Type: Queue(%s): Port_Number: %s Pad: %s Queue_id: %s' % - (of_xid, stat_type, green(port_number), pad, queue_id)) +def print_ofp_statReqQueue(pkt): + stats = pkt.of_body['print_ofp_statReqQueue'] + stat_type = stats['type'] + port_number = of10.dissector.get_phy_port_id(stats['port_number']) + pad = stats['pad'] + queue_id = stats['queue_id'] + print ('StatReq Type: Queue(%s): Port_Number: %s Pad: %s Queue_id: %s' % + (stat_type, green(port_number), pad, queue_id)) -def print_ofp_statReqVendor(of_xid, stat_type, vendor_id): - print ('%s StatReq Type: Vendor(%s): Vendor_ID: %s' % (of_xid, stat_type, +def print_ofp_statReqVendor(pkt): + stats = pkt.of_body['print_ofp_statReqVendor'] + stat_type = stats['type'] + vendor_id = stats['vendor_id'] + print ('StatReq Type: Vendor(%s): Vendor_ID: %s' % (stat_type, vendor_id)) -def print_ofp_statResDesc(of_xid, stat_type, mfr_desc, hw_desc, sw_desc, - serial_num, dp_desc): - print ('%s StatRes Type: Description(%s)' % (of_xid, stat_type)) - print ('%s StatRes mfr_desc: %s' % (of_xid, mfr_desc)) - print ('%s StatRes hw_desc: %s' % (of_xid, hw_desc)) - print ('%s StatRes sw_desc: %s' % (of_xid, sw_desc)) - print ('%s StatRes serial_num: %s' % (of_xid, serial_num)) - print ('%s StatRes dp_desc: %s' % (of_xid, dp_desc)) - - -def print_ofp_statResFlow(of_xid, stat_type, match, res_flow): - print ('%s StatRes Type: Flow(%s)' % (of_xid, stat_type)) - print ('%s StatRes Length: %s Table_id: %s Pad: %s ' % - (of_xid, res_flow['length'], res_flow['table_id'], res_flow['pad'])) - print ('%s StatRes' % of_xid), - print_ofp_match('', match) - print ('%s StatRes duration_sec: %s, duration_nsec: %s, priority: %s,' +def print_ofp_statResDesc(pkt): + stats = pkt.of_body['print_ofp_statResDesc'] + print ('StatRes Type: Description(%s)' % (stats['type'])) + print ('StatRes mfr_desc: %s' % (stats['mfr_desc'])) + print ('StatRes hw_desc: %s' % (stats['hw_desc'])) + print ('StatRes sw_desc: %s' % (stats['sw_desc'])) + print ('StatRes serial_num: %s' % (stats['serial_num'])) + print ('StatRes dp_desc: %s' % (stats['dp_desc'])) + + +def print_ofp_statResFlowArray(pkt): + flows = pkt.of_body['print_ofp_statResFlowArray'] + if len(flows) == 0: + print ('StatRes Type: Flow(1)\nNo Content') + return + + for flow_stats in flows: + print_ofp_statResFlow(pkt, flow_stats) + + +def print_ofp_statResFlow(pkt, stats): + stat_type = stats['type'] + res_flow = stats['res_flow'] + print ('StatRes Type: Flow(%s)' % (stat_type)) + print ('StatRes Length: %s Table_id: %s Pad: %s ' % + (res_flow['length'], res_flow['table_id'], res_flow['pad'])) + print ('StatRes'), + pkt.of_body['print_ofp_match'] = stats['match'] + print_ofp_match(pkt) + print ('StatRes duration_sec: %s, duration_nsec: %s, priority: %s,' ' idle_timeout: %s, hard_timeout: %s, pad: %s, cookie: %s,' ' packet_count: %s, byte_count: %s' % - (of_xid, res_flow['duration_sec'], res_flow['duration_nsec'], + (res_flow['duration_sec'], res_flow['duration_nsec'], res_flow['priority'], res_flow['idle_timeout'], res_flow['hard_timeout'], res_flow['pad'], res_flow['cookie'], res_flow['packet_count'], res_flow['byte_count'])) + pkt.of_body['print_actions'] = stats['print_actions'] + print_actions(pkt) -def print_ofp_statResAggregate(of_xid, stat_type, res_flow): - print ('%s StatRes Type: Aggregate(%s)' % (of_xid, stat_type)) - print ('%s StatRes packet_count: %s, byte_count: %s flow_count: %s ' +def print_ofp_statResAggregate(pkt): + res_flow = pkt.of_body['print_ofp_statResAggregate'] + print ('StatRes Type: Aggregate(%s)' % (res_flow['type'])) + print ('StatRes packet_count: %s, byte_count: %s flow_count: %s ' 'pad: %s' % - (of_xid, res_flow['packet_count'], res_flow['byte_count'], + (res_flow['packet_count'], res_flow['byte_count'], res_flow['flow_count'], res_flow['pad'])) -def print_ofp_statResTable(of_xid, stat_type, res_flow): - print ('%s StatRes Type: Table(%s)' % (of_xid, stat_type)) - print ('%s StatRes table_id: %s, pad: %s, name: "%s", wildcards: %s, ' +def print_ofp_statResTable(pkt): + res_flow = pkt.of_body['print_ofp_statResTable'] + print ('StatRes Type: Table(%s)' % (res_flow['type'])) + print ('StatRes table_id: %s, pad: %s, name: "%s", wildcards: %s, ' 'max_entries: %s, active_count: %s, lookup_count: %s, ' 'matched_count: %s' % - (of_xid, res_flow['table_id'], res_flow['pad'], + (res_flow['table_id'], res_flow['pad'], res_flow['name'], hex(res_flow['wildcards']), res_flow['max_entries'], res_flow['active_count'], res_flow['lookup_count'], res_flow['matched_count'])) -def print_ofp_statResPort(of_xid, stat_type, res_flow): - print ('%s StatRes Type: Port(%s)' % (of_xid, stat_type)) - print ('%s StatRes port_no: %s rx_packets: %s rx_bytes: %s rx_errors: %s' +def print_ofp_statResPortArray(pkt): + for port_stats in pkt.of_body['print_ofp_statResPortArray']: + print_ofp_statResPort(port_stats) + + +def print_ofp_statResPort(port): + print ('StatRes Type: Port(%s)' % (port['type'])) + print ('StatRes port_no: %s rx_packets: %s rx_bytes: %s rx_errors: %s' ' rx_crc_err: %s rx_dropped: %s rx_over_err: %s rx_frame_err: %s\n' - '%s StatRes port_no: %s tx_packets: %s tx_bytes: %s tx_errors: %s' + 'StatRes port_no: %s tx_packets: %s tx_bytes: %s tx_errors: %s' ' tx_dropped: %s collisions: %s pad: %s' % - (of_xid, red(res_flow['port_number']), res_flow['rx_packets'], - res_flow['rx_bytes'], res_flow['rx_errors'], res_flow['rx_crc_err'], - res_flow['rx_dropped'], res_flow['rx_over_err'], - res_flow['rx_frame_err'], of_xid, red(res_flow['port_number']), - res_flow['tx_packets'], res_flow['tx_bytes'], res_flow['tx_errors'], - res_flow['tx_dropped'], res_flow['collisions'], res_flow['pad'])) + (red(port['port_no']), port['rx_packets'], + port['rx_bytes'], port['rx_errors'], port['rx_crc_err'], + port['rx_dropped'], port['rx_over_err'], + port['rx_frame_err'], red(port['port_no']), + port['tx_packets'], port['tx_bytes'], port['tx_errors'], + port['tx_dropped'], port['collisions'], port['pad'])) -def print_ofp_statResQueue(of_xid, stat_type, res_flow): - print ('%s StatRes Type: Queue(%s)' % (of_xid, stat_type)) - print ('%s StatRes queue_id: %s length: %s pad: %s' - ' tx_bytes: %s tx_packets: %s tx_errors: %s' % - (of_xid, res_flow['queue_id'], res_flow['length'], res_flow['pad'], - res_flow['tx_bytes'], res_flow['tx_packets'], - res_flow['tx_errors'])) +def print_ofp_statResQueueArray(pkt): + queues = pkt.of_body['print_ofp_statResQueueArray'] + if len(queues) == 0: + print 'StatRes Type: Queue(5)\nNo Queues' + return + + for queue_stats in queues: + print_ofp_statResQueue(queue_stats) -def print_ofp_statResVendor(of_xid, stat_type, res_flow): - print ('%s StatRes Type: Vendor(%s)' % (of_xid, stat_type)) - print ('%s StatRes vendor_id: %s' % (of_xid, res_flow['vendor_id'])) +def print_ofp_statResQueue(queue): + print ('StatRes Type: Queue(%s)' % (queue['type'])) + print ('StatRes queue_id: %s length: %s pad: %s' + ' tx_bytes: %s tx_packets: %s tx_errors: %s' % + (queue['queue_id'], queue['length'], queue['pad'], + queue['tx_bytes'], queue['tx_packets'], + queue['tx_errors'])) + +def print_ofp_statResVendor(pkt): + vendor = pkt.of_body['print_ofp_statResVendor'] + print ('StatRes Type: Vendor(%s)' % (vendor['type'])) + print ('StatRes vendor_id: %s' % (vendor['vendor_id'])) -def print_ofp_statResVendorData(of_xid, data): - print '%s StatRes Vendor Data: %s' % (of_xid, data) +def print_ofp_statResVendorData(pkt): + data = pkt.of_body['print_ofp_statResVendorData'] + #print 'StatRes Vendor Data: %s' % (data) + print ('StatRes Vendor Data: ') + import hexdump + hexdump.hexdump(data) -def print_ofp_getConfigRes(of_xid, flag, miss): - print ('%s OpenFlow GetConfigRes - Flag: %s Miss_send_len: %s' % - (of_xid, flag, miss)) +def print_ofp_getConfigRes(pkt): + print ('OpenFlow GetConfigRes - Flag: %s Miss_send_len: %s' % + (pkt.of_body['print_ofp_getConfigRes']['flag'], + pkt.of_body['print_ofp_getConfigRes']['miss_send_len'])) -def print_ofp_setConfig(of_xid, flag, miss): - print ('%s OpenFlow SetConfig - Flag: %s Miss_send_len: %s' % - (of_xid, flag, miss)) +def print_ofp_setConfig(pkt): + print ('OpenFlow SetConfig - Flag: %s Miss_send_len: %s' % + (pkt.of_body['print_ofp_setConfig']['flag'], + pkt.of_body['print_ofp_setConfig']['miss_send_len'])) def print_echoreq(pkt): @@ -509,14 +589,16 @@ def print_packetOut(pkt): packetOut['actions_len'])) -def print_queueReq(of_xid, queueConfReq): - print ('%s QueueGetConfigReq Port: %s Pad: %s' % - (of_xid, queueConfReq['port'], queueConfReq['pad'])) +def print_queueReq(pkt): + queueConfReq = pkt.of_body['print_queueReq'] + print ('QueueGetConfigReq Port: %s Pad: %s' % + (queueConfReq['port'], queueConfReq['pad'])) -def print_queueRes(of_xid, queueConfRes): - print ('%s QueueGetConfigRes Port: %s Pad: %s' % - (of_xid, queueConfRes['port'], queueConfRes['pad'])) +def print_queueRes(pkt): + queueConfRes = pkt.of_body['print_queueRes'] + print ('QueueGetConfigRes Port: %s Pad: %s' % + (queueConfRes['port'], queueConfRes['pad'])) def print_queueRes_queues(of_xid, queues): From 51eb6aa4144452c316a88b61573494d880a0a9dc Mon Sep 17 00:00:00 2001 From: sdn Date: Fri, 22 Jan 2016 16:41:59 -0500 Subject: [PATCH 07/88] improvements --- gen/prints.py | 2 +- gen/tcpip.py | 1 + of10/parser.py | 42 +++++++++++++++++++++--------------------- of10/prints.py | 15 ++++++++++++--- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/gen/prints.py b/gen/prints.py index 8c47f9a..449e7e0 100644 --- a/gen/prints.py +++ b/gen/prints.py @@ -92,7 +92,7 @@ def print_layer2(eth): def print_vlan(vlan): - print ('Prio: %s CFI: %s VID: %s' % + print ('VLAN: Prio: %s CFI: %s VID: %s' % (vlan['prio'], vlan['cfi'], red(vlan['vid']))) diff --git a/gen/tcpip.py b/gen/tcpip.py index 37a75c2..49cb479 100644 --- a/gen/tcpip.py +++ b/gen/tcpip.py @@ -20,6 +20,7 @@ def get_ethertype(etype): etypes = {8: 'IP', 2048: 'IP', 2054: 'ARP', + 33024: 'VLAN', 34925: 'IPv6', 34887: 'MPLS', 35020: 'LLDP', diff --git a/of10/parser.py b/of10/parser.py index f2ca090..249182f 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -98,7 +98,7 @@ def parse_Vendor(pkt): # Future - version 0.4 # If code 8992 = NICIRA - #if ofv[0] == 8992: + # if ofv[0] == 8992: # of10.vendors.parse_nicira(packet, h_size+4, of_xid) return 1 @@ -260,13 +260,13 @@ def _parse_other_types(packet, start, eth, pkt): pkt.prepare_printing('print_string', message) elif eth['protocol'] in [2048]: ip = gen.tcpip.get_ip_packet(packet, start) + pkt.prepare_printing('print_layer3', ip) if ip['protocol'] is 6: tcp = gen.tcpip.get_tcp_stream(packet, start + ip['length']) - pkt.prepare_printing('print_layer3', ip) pkt.prepare_printing('print_tcp', tcp) elif eth['protocol'] in [2054]: arp = gen.tcpip.get_arp(packet[start:]) - # pkt.prepare_printing('print_arp', arp) + pkt.prepare_printing('print_arp', arp) else: string = 'Ethertype %s not dissected' % hex(eth['protocol']) message = {'message': string} @@ -365,7 +365,8 @@ def parse_PacketOut(pkt): pkt.prepare_printing('print_packetOut', packetOut) # Actions start = 8 - actions_dict = _parse_OFAction(pkt.this_packet[start:start+packetOut['actions_len']], 0) + total = start+packetOut['actions_len'] + actions_dict = _parse_OFAction(pkt.this_packet[start:total], 0) pkt.prepare_printing('print_actions', actions_dict) start = start + packetOut['actions_len'] @@ -600,7 +601,7 @@ def parse_FlowMod(pkt): ofbody = _parse_OFBody(pkt.this_packet, 0) pkt.prepare_printing("print_ofp_body", ofbody) - ofactions = [] + # ofactions = [] # Actions: Header = 4 , plus each possible action actions_start = 64 @@ -656,8 +657,8 @@ def parse_StatsReq(pkt): table_id = ofstat[0] pad = ofstat[1] out_port = ofstat[2] - stats = {'type': stat_type, 'match': of_match, 'table_id': table_id, 'pad': pad, - 'out_port': out_port} + stats = {'type': stat_type, 'match': of_match, 'table_id': table_id, + 'pad': pad, 'out_port': out_port} pkt.prepare_printing('print_ofp_statReqFlowAggregate', stats) elif stat_type == 3: @@ -801,12 +802,12 @@ def parse_StatsRes(pkt): flow_raw = pkt.this_packet[start:start+104] flow = unpack('!H6sQQQQQQQQQQQQ', flow_raw) port = {'type': stat_type, 'port_no': flow[0], 'pad': flow[1], - 'rx_packets': flow[2], 'tx_packets': flow[3], - 'rx_bytes': flow[4], 'tx_bytes': flow[5], - 'rx_dropped': flow[6], 'tx_dropped': flow[7], - 'rx_errors': flow[8], 'tx_errors': flow[9], - 'rx_frame_err': flow[10], 'rx_over_err': flow[11], - 'rx_crc_err': flow[12], 'collisions': flow[13]} + 'rx_packets': flow[2], 'tx_packets': flow[3], + 'rx_bytes': flow[4], 'tx_bytes': flow[5], + 'rx_dropped': flow[6], 'tx_dropped': flow[7], + 'rx_errors': flow[8], 'tx_errors': flow[9], + 'rx_frame_err': flow[10], 'rx_over_err': flow[11], + 'rx_crc_err': flow[12], 'collisions': flow[13]} ports.append(port) @@ -841,16 +842,15 @@ def parse_StatsRes(pkt): vendor_flow = {'type': stat_type, 'vendor_id': flow[0]} pkt.prepare_printing('print_ofp_statResVendor', vendor_flow) - pkt.prepare_printing('print_ofp_statResVendorData', pkt.this_packet[start+4:]) - #start = start + 4 - #data = [] - #count = len(packet[0:]) + # start = start + 4 + # data = [] + # count = len(packet[0:]) - #import hexdump - #hexdump.hexdump(pkt.this_packet[start:]) - #print + # import hexdump + # hexdump.hexdump(pkt.this_packet[start:]) + # print # while (start < count): # flow_raw = pkt.this_packet[start:start+1] # flow = unpack('!B', flow_raw) @@ -890,7 +890,7 @@ def parse_QueueGetConfigRes(pkt): queue = unpack('!H6s', queue_raw) queueConfRes = {'port': queue[0], 'pad': queue[1]} - pkt.prepare_printing('print_queueRea', queueConfRea) + pkt.prepare_printing('print_queueRes', queueConfRes) start = 8 while (pkt.this_packet[start:] > 0): diff --git a/of10/prints.py b/of10/prints.py index cf21bb4..ad2f269 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -1,7 +1,6 @@ ''' Prints for OpenFlow 1.0 only ''' - import of10.dissector import of10.parser import gen.prints @@ -48,6 +47,14 @@ def print_arp(pkt): gen.prints.print_arp(pkt.of_body['print_arp']) +def print_vlan(pkt): + gen.prints.print_vlan(pkt.of_body['print_vlan']) + + +def print_string(pkt): + print pkt.of_body['print_string']['message'] + + def print_type_unknown(pkt): string = '%s OpenFlow OFP_Type %s unknown \n' print string % (pkt.of_h['xid'], pkt.of_h['type']) @@ -86,6 +93,7 @@ def print_of_feature_res_caps(pkt): print of10.dissector.get_feature_res_capabilities(i), print + def print_of_feature_res_actions(pkt): actions = pkt.of_body['print_of_feature_res_actions'] print ('FeatureRes - Actions:'), @@ -152,7 +160,7 @@ def print_of_feature_res_ports(pkt): def print_ofp_match(pkt): ofmatch = pkt.of_body['print_ofp_match'] - print 'Match -' , + print 'Match -', for K in ofmatch: value = ofmatch[K] if K is 'dl_vlan': @@ -503,11 +511,12 @@ def print_ofp_statResVendor(pkt): def print_ofp_statResVendorData(pkt): data = pkt.of_body['print_ofp_statResVendorData'] - #print 'StatRes Vendor Data: %s' % (data) + # print 'StatRes Vendor Data: %s' % (data) print ('StatRes Vendor Data: ') import hexdump hexdump.hexdump(data) + def print_ofp_getConfigRes(pkt): print ('OpenFlow GetConfigRes - Flag: %s Miss_send_len: %s' % (pkt.of_body['print_ofp_getConfigRes']['flag'], From cda0720e4bd184a27a157ded08208616cbf9c460 Mon Sep 17 00:00:00 2001 From: sdn Date: Fri, 5 Feb 2016 15:45:33 -0500 Subject: [PATCH 08/88] Consolidate a single data process for both PacketIn and PacketOut --- example_filter.json | 2 +- of10/parser.py | 142 ++++++++++++++++++++++---------------------- 2 files changed, 71 insertions(+), 73 deletions(-) diff --git a/example_filter.json b/example_filter.json index 5e2b916..09b5cf1 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,7 +2,7 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 10, 13 + 16, 17 ] }, "1.3": { diff --git a/of10/parser.py b/of10/parser.py index 249182f..05b728c 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -225,29 +225,6 @@ def parse_SetConfig(pkt): # ****************** PacketIn ************************ -def _parse_ethernet_lldp_PacketInOut(packet, start): - # Ethernet - eth = gen.tcpip.get_ethernet_frame(packet[start:start+14], 1) - start = start + 14 - etype = '0x0000' - vlan = {} - # VLAN or not - if eth['protocol'] in [33024]: - vlan = gen.tcpip.get_ethernet_vlan(packet[start:start+2]) - start = start + 2 - # If VLAN exists, there is a next eth['protocol'] - etype = gen.tcpip.get_next_etype(packet[start:start+2]) - start = start + 2 - else: - etype = eth['protocol'] - # LLDP - lldp = {} - if etype in [35020, 35138]: - lldp = gen.tcpip.get_lldp(packet[start:]) - return eth, vlan, lldp, start - eth['protocol'] = etype - return eth, vlan, {}, start - def _parse_other_types(packet, start, eth, pkt): # OESS FVD @@ -282,6 +259,72 @@ def _print_packetIn(of_xid, packetIn, eth, vlan, lldp): of10.prints.print_packetInOut_lldp(of_xid, lldp) +def process_data(pkt, start): + ''' + This funcion aims to dissect PacketIn and PacketOut data + It assumes it is + Ethernet [vlan] (BDDP|LLDP|ARP|IP) [TCP|UDP] + ''' + + # Ethernet + eth = gen.tcpip.get_ethernet_frame(pkt.this_packet[start:start+14], 1) + pkt.prepare_printing('print_layer2_pktIn', eth) + + # VLAN or not - ETYPE 0x8100 or 33024 + start = start + 14 + etype = '0x0000' + vlan = {} + if eth['protocol'] in [33024]: + vlan = gen.tcpip.get_ethernet_vlan(pkt.this_packet[start:start+2]) + pkt.prepare_printing('print_vlan', vlan) + start = start + 2 + # If VLAN exists, there is a next eth['protocol'] + etype = gen.tcpip.get_next_etype(pkt.this_packet[start:start+2]) + start = start + 2 + else: + etype = eth['protocol'] + + # LLDP - ETYPE 0x88CC or 35020 + # BBDP - ETYPE 0x8942 or 35138 + lldp = {} + if etype in [35020, 35138]: + lldp = gen.tcpip.get_lldp(pkt.this_packet[start:]) + if len(lldp) is 0: + message = {'message': 'LLDP Packet MalFormed'} + pkt.prepare_printing('print_string', message) + else: + pkt.prepare_printing('print_lldp', lldp) + if pkt.of_h['type'] is 13: + gen.proxies.support_fsfw(pkt.print_options, lldp) + return + + # OESS FVD - ETYPE 0x88B6 or 34998 + if etype in [34998]: + message = {'message': 'OESS FVD'} + pkt.prepare_printing('print_string', message) + return + + # IP - ETYPE 0x800 or 2048 + if etype in [2048]: + ip = gen.tcpip.get_ip_packet(pkt.this_packet, start) + pkt.prepare_printing('print_layer3', ip) + if ip['protocol'] is 6: + tcp = gen.tcpip.get_tcp_stream(pkt.this_packet, start+ip['length']) + pkt.prepare_printing('print_tcp', tcp) + return + + # ARP - ETYPE 0x806 or 2054 + if etype in [2054]: + arp = gen.tcpip.get_arp(pkt.this_packet[start:]) + pkt.prepare_printing('print_arp', arp) + return + + string = 'Ethertype %s not dissected' % hex(eth['protocol']) + message = {'message': string} + pkt.prepare_printing('print_string', message) + return + + def parse_PacketIn(pkt): # buffer_id(32), total_len(16), in_port(16), reason(8), pad(8) pkt_raw = pkt.this_packet[0:10] @@ -292,30 +335,8 @@ def parse_PacketIn(pkt): pkt.prepare_printing('print_packetIn', packetIn) - eth, vlan, lldp, offset = _parse_ethernet_lldp_PacketInOut(pkt.this_packet, - 10) - - pkt.prepare_printing('print_layer2_pktIn', eth) - if len(vlan) > 0: - pkt.prepare_printing('print_vlan', vlan) - - if len(lldp) == 0: - _parse_other_types(pkt.this_packet[offset:], 0, eth, pkt) - else: - pkt.prepare_printing('print_lldp', lldp) - - # If we have filters (-F) - # filters = sanitizer['packetIn_filter'] - - # if len(filters) > 0: - # if filters['switch_dpid'] == "any": - # _print_packetIn(of_xid, packetIn, eth, vlan, lldp) - # elif filters['switch_dpid'] == lldp['c_id']: - # if (filters['in_port'] == "any" or - # filters['in_port'] == lldp['in_port']): - # _print_packetIn(of_xid, packetIn, eth, vlan, lldp) - # else: - # _print_packetIn(of_xid, packetIn, eth, vlan, lldp) + # process data + process_data(pkt, 10) return 1 @@ -375,31 +396,8 @@ def parse_PacketOut(pkt): if len(pkt.this_packet[start:]) == 0: return 1 - # Ethernet - eth = gen.tcpip.get_ethernet_frame(pkt.this_packet[start:start+14], 1) - pkt.prepare_printing('print_layer2_pktIn', eth) - start = start + 14 - etype = '0x0000' - # VLAN or not - if eth['protocol'] in [33024]: - vlan = gen.tcpip.get_ethernet_vlan(pkt.this_packet[start:start+2]) - if len(vlan) > 0: - pkt.prepare_printing('print_vlan', vlan) - start = start + 2 - # If VLAN exists, there is a next eth['protocol'] - etype = gen.tcpip.get_next_etype(pkt.this_packet[start:start+2]) - start = start + 2 - else: - etype = eth['protocol'] - if etype in [35020, 35138]: - # LLDP TLV - lldp = gen.tcpip.get_lldp(pkt.this_packet[start:]) - if len(lldp) is 0: - print 'LLDP Packet MalFormed' - else: - # Support for FSFW/Proxy - gen.proxies.support_fsfw(pkt.print_options, lldp) - pkt.prepare_printing('print_lldp', lldp) + # process body + process_data(pkt, start) return 1 From 16b0baa267d3843e969b695311ac9faaec164f76 Mon Sep 17 00:00:00 2001 From: sdn Date: Fri, 5 Feb 2016 22:12:03 -0500 Subject: [PATCH 09/88] Changing approach to two classes: Packet and OFMessage --- gen/packet.py | 182 +++++++++++++++++++++++++++++++------------------ gen/proxies.py | 7 +- gen/tcpip.py | 11 ++- of10/parser.py | 148 +++++++++++++++------------------------- of10/prints.py | 32 +-------- ofp_sniffer.py | 34 ++------- 6 files changed, 192 insertions(+), 222 deletions(-) diff --git a/gen/packet.py b/gen/packet.py index 4545ec3..795e8fe 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -11,27 +11,98 @@ OF_HEADER_SIZE = 8 +class OFMessage: + ''' + Used to all all data regarding an OpenFlow message + ''' + def __init__(self, pkt): + self.main_packet = pkt + self.packet = pkt.this_packet + self.of_h = {} + self.of_body = {} + self.printing_seq = [] + self.offset = 0 + self.print_options = self.main_packet.print_options + self.sanitizer = self.main_packet.sanitizer + + def seq_of_print(self, function): + self.printing_seq.append(function) + + def process_openflow_header(self): + self.of_h = get_openflow_header(self.packet, self.offset) + self.offset += 8 + self.packet = self.packet[8:] + + def process_openflow_body(self): + self.process_openflow_header() + # debug + # print self.of_h['type'] + if self.of_h['version'] is 1: + if not process_ofp_type(self): + of10.prints.print_type_unknown(self) + return + + def prepare_printing(self, string, values): + self.of_body[string] = values + self.seq_of_print(string) + + def print_packet(self): + if not self.check_filters(): + gen.prints.print_openflow_header(self.of_h) + if self.of_h['version'] is 1: + of10.prints.print_body(self) + # elif self.of_h['version'] is 4: + # print of13.prints.print_body(self) + print + + def check_filters(self): + # Was -F submitted? + if self.print_options['filters'] is 0: + return False + # Check if there is any limitation for printing + name_version = gen.tcpip.get_ofp_version(self.of_h['version']) + supported_versions = [] + for version in self.sanitizer['allowed_of_versions']: + supported_versions.append(version) + if name_version not in supported_versions: + return True + + # OF Types to be ignored through json file (-F) + rejected_types = self.sanitizer['allowed_of_versions'][name_version] + if self.of_h['type'] in rejected_types['rejected_of_types']: + return True + + class Packet: ''' Used to save all data about the packet ''' def __init__(self, packet, print_options, sanitizer): - self.l1 = {} - self.l2 = {} - self.l3 = {} - self.l4 = {} - self.of_h = {} - self.of_body = {} + # Raw packet self.packet = packet - self.openflow_packet = False + + # Controls self.offset = 0 + self.openflow_packet = False + self.qtd_of_msg = 1 + self.cur_msg = 0 + + # Filters self.print_options = print_options self.sanitizer = sanitizer - self.printing_seq = [] - def seq_of_print(self, function): - self.printing_seq.append(function) + # TCP/IP header + self.l1 = {} + self.l2 = {} + self.l3 = {} + self.l4 = {} + + # OpenFlow messages Array + # As multiple OpenFlow messages per packet is support + # an array needs to be created + self.ofmsgs = [] + # Header TCP/IP def process_header(self, captured_size, truncated_size, now): self.process_l1(captured_size, truncated_size, now) self.process_l2() @@ -42,8 +113,6 @@ def process_header(self, captured_size, truncated_size, now): if self.l4['flag_psh'] == TCP_FLAG_PUSH: self.openflow_packet = True - return self.openflow_packet - def process_l1(self, captured_size, truncated_size, now): self.l1 = {'caplen': captured_size, 'truncate_len': truncated_size, 'time': now} @@ -59,65 +128,46 @@ def process_l3(self): def process_l4(self): self.l4 = get_tcp_stream(self.packet, self.offset) self.offset += self.l4['length'] - # Avoid this: - self.print_options['device_ip'] = self.l3['d_addr'] - self.print_options['device_port'] = self.l4['dest_port'] - - def process_openflow_header(self): - self.of_h = get_openflow_header(self.packet, self.offset) - self.offset += 8 def get_remaining_bytes(self): return self.l1['caplen'] - self.offset - def process_openflow_body(self): - self.remaining_bytes = self.get_remaining_bytes() - self.start = self.offset - while (self.remaining_bytes >= 8): - self.process_openflow_header() - self.remaining_bytes -= self.of_h['length'] - self.start += OF_HEADER_SIZE - self.end = self.of_h['length'] - OF_HEADER_SIZE - self.this_packet = self.packet[self.start:self.start+self.end] - # debug - # print self.of_h['type'] - if self.of_h['version'] is 1: - if not process_ofp_type(self): - of10.prints.print_type_unknown(self) - return - else: - # Print packets - self.print_packet() - self.start += (self.of_h['length'] - OF_HEADER_SIZE) - # print + def get_of_message_length(self): + of_h = get_openflow_header(self.packet, self.offset) + print of_h['type'] + print self.l1['caplen'] + return of_h['length'] - def prepare_printing(self, string, values): - self.of_body[string] = values - self.seq_of_print(string) + # OpenFlow messages + @property + def of_h(self): + return self.ofmsgs[self.cur_msg].of_h - def print_packet(self): - if not self.check_filters(): - gen.prints.print_headers(self) - gen.prints.print_openflow_header(self.of_h) - if self.of_h['version'] is 1: - of10.prints.print_body(self) -# elif self.of_h['version'] is 4: -# print of13.prints.print_body(self) - print + @property + def of_body(self): + return self.ofmsgs[self.cur_msg].of_body - def check_filters(self): - # Was -F submitted? - if self.print_options['filters'] is 0: - return False - # Check if there is any limitation for printing - name_version = gen.tcpip.get_ofp_version(self.of_h['version']) - supported_versions = [] - for version in self.sanitizer['allowed_of_versions']: - supported_versions.append(version) - if name_version not in supported_versions: - return True + def process_openflow_messages(self): + self.remaining_bytes = self.get_remaining_bytes() + while (self.remaining_bytes >= 8): + # self.this_packet is the OpenFlow message + # let's remove the current OpenFlow message from the packet + length = self.get_of_message_length() + self.this_packet = self.packet[self.offset:self.offset+length] + # Instantiate the OpenFlow message in the ofmsgs array + # Process the content, using cur_msg position of the array of msgs + self.ofmsgs.insert(self.cur_msg, OFMessage(self)) + self.ofmsgs[self.cur_msg].process_openflow_body() + self.remaining_bytes -= length + self.offset += length + # If there is another OpenFlow message, instantiate another OFMsg + if (self.remaining_bytes >= 8): + self.cur_msg += 1 + self.qtd_of_msg += 1 + return - # OF Types to be ignored through json file (-F) - rejected_types = self.sanitizer['allowed_of_versions'][name_version] - if self.of_h['type'] in rejected_types['rejected_of_types']: - return True + def print_packet(self): + gen.prints.print_headers(self) + for msg in self.ofmsgs: + msg.print_packet() + #print diff --git a/gen/proxies.py b/gen/proxies.py index 4fb66bb..1bfd682 100644 --- a/gen/proxies.py +++ b/gen/proxies.py @@ -8,11 +8,12 @@ "24389406000000": "mct01"} -def support_fsfw(print_options, lldp): +def support_fsfw(pkt, lldp): + global NET - ip = print_options['device_ip'] - port = print_options['device_port'] + ip = pkt.main_packet.l3['d_addr'] + port = pkt.main_packet.l4['dest_port'] dpid = lldp['c_id'].split(':')[1] name = get_name_dpid(dpid) diff --git a/gen/tcpip.py b/gen/tcpip.py index 49cb479..3c85eca 100644 --- a/gen/tcpip.py +++ b/gen/tcpip.py @@ -179,10 +179,17 @@ def get_lldp(packet): length = p_length - 1 # Get P_ID port_raw = packet[start+3:start+3+length] - string = '!%ss' % length + # string = '!%ss' % length + if length is 1: + string = '!B' + elif length is 2: + string = '!H' + elif length is 4: + string = '!L' + else: + string = '!%ss' % length port = unpack(string, port_raw) p_id = port[0] - start = start + 3 + length # TTL diff --git a/of10/parser.py b/of10/parser.py index 05b728c..33646c4 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -70,7 +70,7 @@ def parse_Hello(pkt): # ************** Error ***************** def parse_Error(pkt): - of_error = pkt.this_packet[0:4] + of_error = pkt.packet[0:4] ofe = unpack('!HH', of_error) error = {'type': ofe[0], 'code': ofe[1]} @@ -92,7 +92,7 @@ def parse_EchoRes(pkt): # ************ Vendor ****************** def parse_Vendor(pkt): - of_vendor = pkt.this_packet[0:4] + of_vendor = pkt.packet[0:4] ofv = unpack('!L', of_vendor) pkt.prepare_printing('print_of_vendor', ofv[0]) @@ -171,7 +171,7 @@ def _parse_phy_ports(packet): def parse_FeatureRes(pkt): - of_fres = pkt.this_packet[0:24] + of_fres = pkt.packet[0:24] ofrs = unpack('!8sLB3sLL', of_fres) f_res = {'datapath_id': ofrs[0], 'n_buffers': ofrs[1], 'n_tbls': ofrs[2], 'pad': ofrs[3]} @@ -188,8 +188,8 @@ def parse_FeatureRes(pkt): # Ports description? start = 24 - while len(pkt.this_packet[start:]) > 0: - ports = _parse_phy_ports(pkt.this_packet[start:start+48]) + while len(pkt.packet[start:]) > 0: + ports = _parse_phy_ports(pkt.packet[start:start+48]) pkt.prepare_printing('print_of_feature_res_ports', ports) start = start + 48 @@ -212,53 +212,19 @@ def _parse_SetGetConfig(packet, h_size): def parse_GetConfigRes(pkt): - getConfig = _parse_SetGetConfig(pkt.this_packet, 0) + getConfig = _parse_SetGetConfig(pkt.packet, 0) pkt.prepare_printing('print_ofp_getConfigRes', getConfig) return 1 # ******************* SetConfig ********************** def parse_SetConfig(pkt): - setConfig = _parse_SetGetConfig(pkt.this_packet, 0) + setConfig = _parse_SetGetConfig(pkt.packet, 0) pkt.prepare_printing('print_ofp_setConfig', setConfig) return 1 # ****************** PacketIn ************************ - -def _parse_other_types(packet, start, eth, pkt): - # OESS FVD - if eth['protocol'] in [34998]: - message = {'message': 'OESS FVD'} - pkt.prepare_printing('print_string', message) - elif eth['protocol'] in [35020]: - # If it gets here, means that the LLDP packet is MalFormed - message = {'message': 'LLDP Packet MalFormed'} - pkt.prepare_printing('print_string', message) - elif eth['protocol'] in [2048]: - ip = gen.tcpip.get_ip_packet(packet, start) - pkt.prepare_printing('print_layer3', ip) - if ip['protocol'] is 6: - tcp = gen.tcpip.get_tcp_stream(packet, start + ip['length']) - pkt.prepare_printing('print_tcp', tcp) - elif eth['protocol'] in [2054]: - arp = gen.tcpip.get_arp(packet[start:]) - pkt.prepare_printing('print_arp', arp) - else: - string = 'Ethertype %s not dissected' % hex(eth['protocol']) - message = {'message': string} - pkt.prepare_printing('print_string', message) - - -def _print_packetIn(of_xid, packetIn, eth, vlan, lldp): - of10.prints.print_ofp_packetIn(of_xid, packetIn) - of10.prints.print_packetInOut_layer2(of_xid, eth) - if len(vlan) != 0: - of10.prints.print_packetInOut_vlan(of_xid, vlan) - if len(lldp) != 0: - of10.prints.print_packetInOut_lldp(of_xid, lldp) - - def process_data(pkt, start): ''' This funcion aims to dissect PacketIn and PacketOut data @@ -267,7 +233,7 @@ def process_data(pkt, start): ''' # Ethernet - eth = gen.tcpip.get_ethernet_frame(pkt.this_packet[start:start+14], 1) + eth = gen.tcpip.get_ethernet_frame(pkt.packet[start:start+14], 1) pkt.prepare_printing('print_layer2_pktIn', eth) # VLAN or not - ETYPE 0x8100 or 33024 @@ -275,11 +241,11 @@ def process_data(pkt, start): etype = '0x0000' vlan = {} if eth['protocol'] in [33024]: - vlan = gen.tcpip.get_ethernet_vlan(pkt.this_packet[start:start+2]) + vlan = gen.tcpip.get_ethernet_vlan(pkt.packet[start:start+2]) pkt.prepare_printing('print_vlan', vlan) start = start + 2 # If VLAN exists, there is a next eth['protocol'] - etype = gen.tcpip.get_next_etype(pkt.this_packet[start:start+2]) + etype = gen.tcpip.get_next_etype(pkt.packet[start:start+2]) start = start + 2 else: etype = eth['protocol'] @@ -288,14 +254,14 @@ def process_data(pkt, start): # BBDP - ETYPE 0x8942 or 35138 lldp = {} if etype in [35020, 35138]: - lldp = gen.tcpip.get_lldp(pkt.this_packet[start:]) + lldp = gen.tcpip.get_lldp(pkt.packet[start:]) if len(lldp) is 0: message = {'message': 'LLDP Packet MalFormed'} pkt.prepare_printing('print_string', message) else: pkt.prepare_printing('print_lldp', lldp) if pkt.of_h['type'] is 13: - gen.proxies.support_fsfw(pkt.print_options, lldp) + gen.proxies.support_fsfw(pkt, lldp) return # OESS FVD - ETYPE 0x88B6 or 34998 @@ -306,16 +272,16 @@ def process_data(pkt, start): # IP - ETYPE 0x800 or 2048 if etype in [2048]: - ip = gen.tcpip.get_ip_packet(pkt.this_packet, start) + ip = gen.tcpip.get_ip_packet(pkt.packet, start) pkt.prepare_printing('print_layer3', ip) if ip['protocol'] is 6: - tcp = gen.tcpip.get_tcp_stream(pkt.this_packet, start+ip['length']) + tcp = gen.tcpip.get_tcp_stream(pkt.packet, start+ip['length']) pkt.prepare_printing('print_tcp', tcp) return # ARP - ETYPE 0x806 or 2054 if etype in [2054]: - arp = gen.tcpip.get_arp(pkt.this_packet[start:]) + arp = gen.tcpip.get_arp(pkt.packet[start:]) pkt.prepare_printing('print_arp', arp) return @@ -327,7 +293,7 @@ def process_data(pkt, start): def parse_PacketIn(pkt): # buffer_id(32), total_len(16), in_port(16), reason(8), pad(8) - pkt_raw = pkt.this_packet[0:10] + pkt_raw = pkt.packet[0:10] p_in = unpack('!LHHBB', pkt_raw) reason = of10.dissector.get_packetIn_reason(p_in[3]) packetIn = {'buffer_id': p_in[0], 'total_len': p_in[1], 'in_port': p_in[2], @@ -343,10 +309,10 @@ def parse_PacketIn(pkt): # ******************** FlowRemoved *************************** def parse_FlowRemoved(pkt): - ofmatch = _parse_OFMatch(pkt.this_packet, 0) + ofmatch = _parse_OFMatch(pkt.packet, 0) pkt.prepare_printing('print_ofp_match', ofmatch) - of_rem_body = pkt.this_packet[40:40+40] + of_rem_body = pkt.packet[40:40+40] ofrem = unpack('!QHBBLLHBBQQ', of_rem_body) cookie = ofrem[0] if ofrem[0] > 0 else 0 cookie = '0x' + format(cookie, '02x') @@ -364,13 +330,13 @@ def parse_FlowRemoved(pkt): # ******************* PortStatus ***************************** def parse_PortStatus(pkt): - port_raw = pkt.this_packet[0:8] + port_raw = pkt.packet[0:8] port = unpack('!B7s', port_raw) reason = of10.dissector.get_portStatus_reason(port[0]) p_status = {'reason': reason, 'pad': port[1]} pkt.prepare_printing('print_portStatus', p_status) - ports = _parse_phy_ports(pkt.this_packet[8:64]) + ports = _parse_phy_ports(pkt.packet[8:64]) pkt.prepare_printing('print_of_feature_res_ports', ports) return 1 @@ -378,7 +344,7 @@ def parse_PortStatus(pkt): # ******************* PacketOut ***************************** def parse_PacketOut(pkt): # buffer_id(32), in_port(16), actions_len(16) - pkt_raw = pkt.this_packet[0:8] + pkt_raw = pkt.packet[0:8] p_out = unpack('!LHH', pkt_raw) packetOut = {'buffer_id': p_out[0], 'in_port': p_out[1], 'actions_len': p_out[2]} @@ -387,13 +353,13 @@ def parse_PacketOut(pkt): # Actions start = 8 total = start+packetOut['actions_len'] - actions_dict = _parse_OFAction(pkt.this_packet[start:total], 0) + actions_dict = _parse_OFAction(pkt.packet[start:total], 0) pkt.prepare_printing('print_actions', actions_dict) start = start + packetOut['actions_len'] # Check if we still have content in the PacketOut - if len(pkt.this_packet[start:]) == 0: + if len(pkt.packet[start:]) == 0: return 1 # process body @@ -593,17 +559,15 @@ def _parse_OFAction(packet, start): def parse_FlowMod(pkt): - ofmatch = _parse_OFMatch(pkt.this_packet, 0) + ofmatch = _parse_OFMatch(pkt.packet, 0) pkt.prepare_printing("print_ofp_match", ofmatch) - ofbody = _parse_OFBody(pkt.this_packet, 0) + ofbody = _parse_OFBody(pkt.packet, 0) pkt.prepare_printing("print_ofp_body", ofbody) - # ofactions = [] - # Actions: Header = 4 , plus each possible action actions_start = 64 - actions_dict = _parse_OFAction(pkt.this_packet, actions_start) + actions_dict = _parse_OFAction(pkt.packet, actions_start) pkt.prepare_printing('print_actions', actions_dict) return 1 @@ -612,7 +576,7 @@ def parse_FlowMod(pkt): # ********************* PortMod **************************** def parse_PortMod(pkt): # port(16), hw_addr(48), config(32), mask(32), advertise(32), pad(32) - pmod_raw = pkt.this_packet[0:24] + pmod_raw = pkt.packet[0:24] pmod = unpack('!H6sLLLL', pmod_raw) config = _parse_phy_config(pmod[2]) @@ -632,7 +596,7 @@ def parse_StatsReq(pkt): ''' # Get type = 16bits # Get flags = 16bits - of_stat_req = pkt.this_packet[0:4] + of_stat_req = pkt.packet[0:4] ofstat = unpack('!HH', of_stat_req) stat_type = ofstat[0] # FLags were not defined yet. Ignoring. @@ -648,9 +612,9 @@ def parse_StatsReq(pkt): elif stat_type == 1 or stat_type == 2: # Flow(1) or Aggregate(2) # Fields: match(40), table_id(8), pad(8), out_port(16) - of_match = _parse_OFMatch(pkt.this_packet, start) + of_match = _parse_OFMatch(pkt.packet, start) # 44 Bytes (40B from Match, 4 from header) - of_stat_req = pkt.this_packet[start+40:start+40+4] + of_stat_req = pkt.packet[start+40:start+40+4] ofstat = unpack('!BBH', of_stat_req) table_id = ofstat[0] pad = ofstat[1] @@ -667,7 +631,7 @@ def parse_StatsReq(pkt): elif stat_type == 4: # Port # Fields: port_number(16), pad(48) - of_stat_req = pkt.this_packet[start:start+8] + of_stat_req = pkt.packet[start:start+8] ofstat = unpack('!H6s', of_stat_req) port_number = ofstat[0] pad = ofstat[1] @@ -677,7 +641,7 @@ def parse_StatsReq(pkt): elif stat_type == 5: # Queue # Fields: port_number(16), pad(16), queue_id(32) - of_stat_req = pkt.this_packet[start:start+8] + of_stat_req = pkt.packet[start:start+8] ofstat = unpack('!HHL', of_stat_req) port_number = ofstat[0] pad = ofstat[1] @@ -689,7 +653,7 @@ def parse_StatsReq(pkt): elif stat_type == 65535: # Vendor # Fields: vendor_id(32) + data - of_stat_req = pkt.this_packet[start:start+4] + of_stat_req = pkt.packet[start:start+4] ofstat = unpack('!L', of_stat_req) vendor_id = ofstat[0] stats = {'type': stat_type, 'vendor_id': vendor_id} @@ -705,7 +669,7 @@ def parse_StatsReq(pkt): def parse_StatsRes(pkt): # Get type = 16bits # Get flags = 16bits - of_stat_req = pkt.this_packet[0:4] + of_stat_req = pkt.packet[0:4] ofstat = unpack('!HH', of_stat_req) stat_type = ofstat[0] # flags = ofstat[1] @@ -716,7 +680,7 @@ def parse_StatsRes(pkt): # Description # Fields: mfr_desc(2048), hw_desc(2048), sw_desc(2048), serial_num(256), # dp_desc(2048) - desc_raw = pkt.this_packet[start:start+1056] + desc_raw = pkt.packet[start:start+1056] desc = unpack('!256s256s256s32s256s', desc_raw) stats = {'mfr_desc': desc[0], 'hw_desc': desc[1], @@ -731,15 +695,15 @@ def parse_StatsRes(pkt): # Fields: length(16), table_id(8), pad(8), match(40), duration_sec(32), # duration_nsec(32), priority(16), idle_timeout(16), hard_timeout(16), # pad(48), cookie(64), packet_count(64), byte_count(64), actions[] - count = len(pkt.this_packet[0:]) - 4 + count = len(pkt.packet[0:]) - 4 flows = [] while (count > 0): - flow_raw = pkt.this_packet[start:start+4] + flow_raw = pkt.packet[start:start+4] flow = unpack('!HBB', flow_raw) res_flow = {'length': flow[0], 'table_id': flow[1], 'pad': flow[2]} - of_match = _parse_OFMatch(pkt.this_packet, start+4) + of_match = _parse_OFMatch(pkt.packet, start+4) - flow_raw = pkt.this_packet[start+44:start+44+44] + flow_raw = pkt.packet[start+44:start+44+44] flow = unpack('!LLHHH6sQQQ', flow_raw) res_flow.update({'duration_sec': flow[0], 'duration_nsec': flow[1], 'priority': flow[2], 'idle_timeout': flow[3], @@ -750,7 +714,7 @@ def parse_StatsRes(pkt): # Process Actions[] end = res_flow['length'] - (4 + 40 + 44) - actions = pkt.this_packet[start+88:start+88+end] + actions = pkt.packet[start+88:start+88+end] actions_dict = _parse_OFAction(actions, 0) stats = {'type': stat_type, 'match': of_match, @@ -768,7 +732,7 @@ def parse_StatsRes(pkt): elif stat_type == 2: # Aggregate(2) # Fields: packet_count(64), byte_count(64), flow_count(32), pad(32) - flow_raw = pkt.this_packet[start:start+24] + flow_raw = pkt.packet[start:start+24] flow = unpack('!QQLL', flow_raw) res_flow = {'type': stat_type, 'packet_count': flow[0], 'byte_count': flow[1], 'flow_count': flow[2], @@ -780,7 +744,7 @@ def parse_StatsRes(pkt): # Fields: table_id(8), pad(24), name(256), wildcards(32), # max_entries(32), active_count(32), lookup_count(64), # matched_count(64) - flow_raw = pkt.this_packet[start:start+64] + flow_raw = pkt.packet[start:start+64] flow = unpack('!B3s32sLLLQQ', flow_raw) res_flow = {'type': stat_type, 'table_id': flow[0], 'pad': flow[1], 'name': flow[2], 'wildcards': flow[3], @@ -794,10 +758,10 @@ def parse_StatsRes(pkt): # rx_bytes(64), tx_bytes(64), rx_dropped(64), tx_dropped(64), # rx_errors(64), tx_errors(64), rx_frame_err(64), rx_over_err(64), # rx_crc_err(64), collisions(64) - count = len(pkt.this_packet[0:]) - 4 + count = len(pkt.packet[0:]) - 4 ports = [] while (count > 0): - flow_raw = pkt.this_packet[start:start+104] + flow_raw = pkt.packet[start:start+104] flow = unpack('!H6sQQQQQQQQQQQQ', flow_raw) port = {'type': stat_type, 'port_no': flow[0], 'pad': flow[1], 'rx_packets': flow[2], 'tx_packets': flow[3], @@ -818,10 +782,10 @@ def parse_StatsRes(pkt): # Queue # Fields: length(16), pad(16), queue_id(32), tx_bytes(64), # tx_packets(64), tx_errors(64) - count = len(pkt.this_packet[0:]) - 4 + count = len(pkt.packet[0:]) - 4 queues = [] while (count > 0): - flow_raw = pkt.this_packet[start:start+32] + flow_raw = pkt.packet[start:start+32] flow = unpack('!HHLQQQ', flow_raw) queue = {'length': flow[0], 'pad': flow[1], 'queue_id': flow[2], 'tx_bytes': flow[3], 'tx_packets': flow[4], @@ -835,22 +799,22 @@ def parse_StatsRes(pkt): elif stat_type == 65535: # Vendor # Fields: vendor_id(32), data(?) - flow_raw = pkt.this_packet[start:start+4] + flow_raw = pkt.packet[start:start+4] flow = unpack('!L', flow_raw) vendor_flow = {'type': stat_type, 'vendor_id': flow[0]} pkt.prepare_printing('print_ofp_statResVendor', vendor_flow) pkt.prepare_printing('print_ofp_statResVendorData', - pkt.this_packet[start+4:]) + pkt.packet[start+4:]) # start = start + 4 # data = [] # count = len(packet[0:]) # import hexdump - # hexdump.hexdump(pkt.this_packet[start:]) + # hexdump.hexdump(pkt.packet[start:]) # print # while (start < count): - # flow_raw = pkt.this_packet[start:start+1] + # flow_raw = pkt.packet[start:start+1] # flow = unpack('!B', flow_raw) # data.append(str(flow[0])) # start = start + 1 @@ -875,7 +839,7 @@ def parse_BarrierRes(pkt): # ******************* QueueGetConfigReq ******************* def parse_QueueGetConfigReq(pkt): - queue_raw = pkt.this_packet[0:4] + queue_raw = pkt.packet[0:4] queue = unpack('!HH', queue_raw) queueConfReq = {'port': queue[0], 'pad': queue[1]} pkt.prepare_printing('print_queueReq', queueConfReq) @@ -884,17 +848,17 @@ def parse_QueueGetConfigReq(pkt): # ****************** QueueGetConfigRes ******************** def parse_QueueGetConfigRes(pkt): - queue_raw = pkt.this_packet[0:8] + queue_raw = pkt.packet[0:8] queue = unpack('!H6s', queue_raw) queueConfRes = {'port': queue[0], 'pad': queue[1]} pkt.prepare_printing('print_queueRes', queueConfRes) start = 8 - while (pkt.this_packet[start:] > 0): + while (pkt.packet[start:] > 0): # Queues - it could be multiple # queue_id(32), length(16), pad(16) - queue_raw = pkt.this_packet[start:start+8] + queue_raw = pkt.packet[start:start+8] queue = unpack('!LHH', queue_raw) queues = {'queue_id': queue[0], 'length': queue[1], 'pad': queue[2]} of10.prints.print_queues(queues) @@ -903,10 +867,10 @@ def parse_QueueGetConfigRes(pkt): # Look of properties # property(16), length(16), pad(32), rate(16), pad(48) - properties = pkt.this_packet[q_start:q_start+queues['length']-8] + properties = pkt.packet[q_start:q_start+queues['length']-8] while (len(properties[q_start:]) > 0): - prop_raw = pkt.this_packet[q_start:q_start+8] + prop_raw = pkt.packet[q_start:q_start+8] prop = unpack('!HHLH6s', prop_raw) properties = {'type': prop[0], 'length': prop[1], 'pad': prop[2], 'rate': prop[3], 'pad2': prop[4]} diff --git a/of10/prints.py b/of10/prints.py index ad2f269..71a469c 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -56,8 +56,8 @@ def print_string(pkt): def print_type_unknown(pkt): - string = '%s OpenFlow OFP_Type %s unknown \n' - print string % (pkt.of_h['xid'], pkt.of_h['type']) + string = 'OpenFlow OFP_Type %s unknown \n' + print string % (pkt.of_h['type']) def print_of_hello(pkt): @@ -555,20 +555,6 @@ def print_packetInOut_vlan(of_xid, vlan): def print_packetIn(pkt): packetIn = pkt.of_body['print_packetIn'] - - # If we have filters (-F) - # filters = pkt.sanitizer['packetIn_filter'] - - # if len(filters) > 0: - # if filters['switch_dpid'] == "any": - # should_print = True _print_packetIn(of_xid, packetIn, eth, vlan, lldp) - # elif filters['switch_dpid'] == lldp['c_id']: - # if (filters['in_port'] == "any" or - # filters['in_port'] == lldp['in_port']): - # _print_packetIn(of_xid, packetIn, eth, vlan, lldp) - # else: - # _print_packetIn(of_xid, packetIn, eth, vlan, lldp) - print ('PacketIn: buffer_id: %s total_len: %s in_port: %s reason: %s ' 'pad: %s' % (hex(packetIn['buffer_id']), packetIn['total_len'], @@ -576,20 +562,6 @@ def print_packetIn(pkt): packetIn['pad'])) -# a print_lldp function was created on gen.prints -# remove this -def print_packetInOut_lldp(of_xid, lldp): - print ('%s LLDP: Chassis Type(%s) Length: %s SubType: %s ID: %s\n' - '%s LLDP: Port Type(%s) Length: %s SubType: %s ID: %s\n' - '%s LLDP: TTL(%s) Length: %s Seconds: %s\n' - '%s LLDP: END(%s) Length: %s' % - (of_xid, lldp['c_type'], lldp['c_length'], lldp['c_subtype'], - green(lldp['c_id']), of_xid, lldp['p_type'], lldp['p_length'], - lldp['p_subtype'], green(lldp['p_id']), of_xid, lldp['t_type'], - lldp['t_length'], lldp['t_ttl'], of_xid, lldp['e_type'], - lldp['e_length'])) - - def print_packetOut(pkt): packetOut = pkt.of_body['print_packetOut'] print ('PacketOut: buffer_id: %s in_port: %s actions_len: %s' % diff --git a/ofp_sniffer.py b/ofp_sniffer.py index 46317d5..b8a8ed7 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -38,6 +38,7 @@ def main(argv): main_filter = " port 6633 " cap.setfilter(main_filter + infilter) + ctr = 1 # start sniffing packets while(1): (header, packet) = cap.next() @@ -45,8 +46,10 @@ def main(argv): pkt = Packet(packet, print_options, sanitizer) pkt.process_header(header.getlen(), header.getcaplen(), time) if pkt.openflow_packet: - pkt.process_openflow_body() - # Prints + print 'Packet #' + str(ctr) + ctr += 1 + pkt.process_openflow_messages() + pkt.print_packet() del pkt except KeyboardInterrupt: @@ -57,32 +60,5 @@ def main(argv): return -#def sanitizer_filters(of_header, date, getlen, caplen, header_size, -# eth, ip, tcp, sanitizer): -# ''' -# If -F was provided, use filters specified -# ''' -# if (of_header['version'] == -1): -# print ('h_size : %s - caplen: %s ' % (header_size, caplen)) -# print_headers(1, date, getlen, caplen, eth, ip, tcp) -# print 'OpenFlow header not complete. Ignoring packet.' -# return 0 -# -# # OF Versions supported through json file (-F) -# name_version = of10.dissector.get_ofp_version(of_header['version']) -# supported_versions = [] -# for version in sanitizer['allowed_of_versions']: -# supported_versions.append(version) -# if name_version not in supported_versions: -# return 0 -# -# # OF Types to be ignored through json file (-F) -# rejected_types = sanitizer['allowed_of_versions'][name_version] -# if of_header['type'] in rejected_types['rejected_of_types']: -# return 0 -# -# return 1 - - if __name__ == "__main__": main(sys.argv) From cf36fbab0bc0347a50ee8dc68870cc765ea2ccdc Mon Sep 17 00:00:00 2001 From: sdn Date: Sat, 6 Feb 2016 12:32:33 -0500 Subject: [PATCH 10/88] New approach working fine for OF 1.0. No filters yet --- example_filter.json | 2 +- gen/cli.py | 12 ++++++--- gen/packet.py | 63 +++++++++++++++++++++++++++++++++++---------- gen/prints.py | 5 ++++ gen/tcpip.py | 1 + of10/prints.py | 2 +- ofp_sniffer.py | 22 +++++++++------- 7 files changed, 78 insertions(+), 29 deletions(-) diff --git a/example_filter.json b/example_filter.json index 09b5cf1..1f1a59c 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,7 +2,7 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 16, 17 + 13 ] }, "1.3": { diff --git a/gen/cli.py b/gen/cli.py index a84eb2b..df717a9 100644 --- a/gen/cli.py +++ b/gen/cli.py @@ -3,7 +3,7 @@ import json -VERSION = '0.2' +VERSION = '0.3-dev' NO_COLOR = False @@ -23,6 +23,7 @@ def usage(file): '\t -o or --print-ovs : print using ovs-ofctl format\n' '\t -h or --help : prints this guidance\n' '\t -c or --no-colors: removes colors\n' + '\t -d or --debug: enable debug\n' '\t -v or --version : prints version\n') % file) sys.exit(0) @@ -44,9 +45,10 @@ def read_sanitizer(sanitizer_file): def get_params(argv): # Handle all input params - letters = 'f:F:i:r:p:ohvc' + letters = 'f:F:i:r:p:ohvcd' keywords = ['print=', 'pcap-filter=', 'sanitizer-file=', 'interface=', - 'src-file=', 'print-ovs', 'help', 'version', 'no-colors'] + 'src-file=', 'print-ovs', 'help', 'version', 'no-colors', + 'debug'] # Default Values input_filter, sanitizer_file, dev, captured_file = '', '', 'eth0', '' @@ -57,7 +59,7 @@ def get_params(argv): print str(err) usage(argv[0]) - print_options = {'min': 1, 'ovs': 0, 'colors': 0, 'filters': 0} + print_options = {'min': 1, 'debug': 0, 'ovs': 0, 'colors': 0, 'filters': 0} for option, param in opts: if option in ['-p', '--print']: @@ -84,6 +86,8 @@ def get_params(argv): elif option in ['-c', '--no-colors']: global NO_COLOR NO_COLOR = True + elif option in ['-d', '--debub']: + print_options['debug'] = 1 else: usage(argv[0]) diff --git a/gen/packet.py b/gen/packet.py index 795e8fe..b4b037e 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -33,21 +33,32 @@ def process_openflow_header(self): self.offset += 8 self.packet = self.packet[8:] + def handle_malformed_pkts(self): + string = ('!!! MalFormed Packet - Packet Len: %s Informed: %s ' + 'Missing: %s Bytes - Probably Reached MTU? !!!' % + (len(self.packet), self.of_h['length'], + self.of_h['length'] - len(self.packet))) + message = {'message': string} + self.prepare_printing('print_string', message) + def process_openflow_body(self): self.process_openflow_header() - # debug - # print self.of_h['type'] if self.of_h['version'] is 1: - if not process_ofp_type(self): - of10.prints.print_type_unknown(self) - return + try: + if not process_ofp_type(self): + of10.prints.print_type_unknown(self) + return 1 + except: + self.handle_malformed_pkts() + return -1 + return 0 def prepare_printing(self, string, values): self.of_body[string] = values self.seq_of_print(string) def print_packet(self): - if not self.check_filters(): + # if not self.check_filters(): gen.prints.print_openflow_header(self.of_h) if self.of_h['version'] is 1: of10.prints.print_body(self) @@ -134,8 +145,6 @@ def get_remaining_bytes(self): def get_of_message_length(self): of_h = get_openflow_header(self.packet, self.offset) - print of_h['type'] - print self.l1['caplen'] return of_h['length'] # OpenFlow messages @@ -153,21 +162,47 @@ def process_openflow_messages(self): # self.this_packet is the OpenFlow message # let's remove the current OpenFlow message from the packet length = self.get_of_message_length() + if length < 8: + # MalFormed Packet + return 0 self.this_packet = self.packet[self.offset:self.offset+length] # Instantiate the OpenFlow message in the ofmsgs array # Process the content, using cur_msg position of the array of msgs self.ofmsgs.insert(self.cur_msg, OFMessage(self)) - self.ofmsgs[self.cur_msg].process_openflow_body() + version = self.ofmsgs[self.cur_msg].process_openflow_body() + if version is 0: + return 0 + elif version is -1: + break self.remaining_bytes -= length self.offset += length # If there is another OpenFlow message, instantiate another OFMsg if (self.remaining_bytes >= 8): self.cur_msg += 1 self.qtd_of_msg += 1 - return + + return 1 def print_packet(self): - gen.prints.print_headers(self) - for msg in self.ofmsgs: - msg.print_packet() - #print + if not self.check_filters(): + gen.prints.print_headers(self) + for msg in self.ofmsgs: + msg.print_packet() + + def check_filters(self): + # Was -F submitted? + if self.print_options['filters'] is 0: + return False + # Check if there is any limitation for printing + name_version = gen.tcpip.get_ofp_version(self.of_h['version']) + supported_versions = [] + for version in self.sanitizer['allowed_of_versions']: + supported_versions.append(version) + if name_version not in supported_versions: + return True + # OF Types to be ignored through json file (-F) + rejected_types = self.sanitizer['allowed_of_versions'][name_version] + if self.of_h['type'] in rejected_types['rejected_of_types']: + return True + + return False diff --git a/gen/prints.py b/gen/prints.py index 449e7e0..5d4487b 100644 --- a/gen/prints.py +++ b/gen/prints.py @@ -12,6 +12,11 @@ import gen.tcpip +def debug(pkt, string): + if pkt.print_options['debug'] is 1: + print 'DEBUG: %s' % string + + def red(string): if gen.cli.NO_COLOR is True: return string diff --git a/gen/tcpip.py b/gen/tcpip.py index 3c85eca..35a5068 100644 --- a/gen/tcpip.py +++ b/gen/tcpip.py @@ -57,6 +57,7 @@ def get_arp(packet): 'src_ip': arp[6], 'dst_mac': arp[7], 'dst_ip': arp[8]} return arp_frame + def get_ip_packet(packet, eth_length): ''' Returns IP Header fields diff --git a/of10/prints.py b/of10/prints.py index 71a469c..241b3af 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -190,7 +190,7 @@ def print_ofp_body(pkt): def print_ofp_flow_removed(pkt): ofrem = pkt.of_body['print_ofp_flow_removed'] - string = ('Body - Cookie: %s Priority: %s Reason: %s Pad: %s ' + string = ('Body - Cookie: %s Priority: %s Reason: %s Pad: %s\nBody - ' 'Duration Secs/NSecs: %s/%s Idle Timeout: %s Pad2/Pad3: %s/%s' ' Packet Count: %s Byte Count: %s') diff --git a/ofp_sniffer.py b/ofp_sniffer.py index b8a8ed7..b328cad 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -42,15 +42,19 @@ def main(argv): # start sniffing packets while(1): (header, packet) = cap.next() - time = datetime.datetime.now() - pkt = Packet(packet, print_options, sanitizer) - pkt.process_header(header.getlen(), header.getcaplen(), time) - if pkt.openflow_packet: - print 'Packet #' + str(ctr) - ctr += 1 - pkt.process_openflow_messages() - pkt.print_packet() - del pkt + if len(packet) >= 62: + time = datetime.datetime.now() + pkt = Packet(packet, print_options, sanitizer) + pkt.process_header(header.getlen(), header.getcaplen(), time) + if pkt.openflow_packet: + print 'Packet #' + str(ctr) + result = pkt.process_openflow_messages() + if result is 1: + pkt.print_packet() + del pkt + elif len(packet) is 0: + sys.exit(0) + ctr += 1 except KeyboardInterrupt: print 'Exiting...' From 378bc2db9c7ff0ad06fcdb10d9f9ad1242937ce9 Mon Sep 17 00:00:00 2001 From: sdn Date: Sat, 6 Feb 2016 17:58:35 -0500 Subject: [PATCH 11/88] Fixed FeatureRes --- example_filter.json | 2 +- gen/packet.py | 3 +- gen/prints.py | 14 +++++-- of10/parser.py | 5 ++- of10/prints.py | 95 +++++++++++++++++++++++---------------------- ofp_sniffer.py | 3 +- 6 files changed, 65 insertions(+), 57 deletions(-) diff --git a/example_filter.json b/example_filter.json index 1f1a59c..c45a712 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,7 +2,7 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 13 + 11, 14, 18, 19, 10, 13, 16, 17 ] }, "1.3": { diff --git a/gen/packet.py b/gen/packet.py index b4b037e..5738bfe 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -88,11 +88,12 @@ class Packet: ''' Used to save all data about the packet ''' - def __init__(self, packet, print_options, sanitizer): + def __init__(self, packet, print_options, sanitizer, ctr): # Raw packet self.packet = packet # Controls + self.position = ctr self.offset = 0 self.openflow_packet = False self.qtd_of_msg = 1 diff --git a/gen/prints.py b/gen/prints.py index 5d4487b..135ffb3 100644 --- a/gen/prints.py +++ b/gen/prints.py @@ -67,24 +67,30 @@ def get_ip_from_long(long_ip): def print_headers(pkt): if pkt.print_options['min'] == 1: - print_minimal(pkt.l1['time'], pkt.l1['caplen'], pkt.l3, pkt.l4) + print_minimal(pkt.position, pkt.l1['time'], pkt.l1['caplen'], pkt.l3, + pkt.l4) else: + print_position(pkt.position) print_layer1(pkt.l1['time'], pkt.l1['caplen'], pkt.l1['truncate_len']) print_layer2(pkt.l2) print_layer3(pkt.l3) print_tcp(pkt.l4) -def print_minimal(date, getlen, ip, tcp): - string = '%s %s:%s -> %s:%s Size: %s Bytes' +def print_minimal(position, date, getlen, ip, tcp): + string = 'Packet #%s - %s %s:%s -> %s:%s Size: %s Bytes' source = gen.proxies.get_ip_name(ip['s_addr'], tcp['source_port']) dest = gen.proxies.get_ip_name(ip['d_addr'], tcp['dest_port']) - print string % (date, cyan(source), cyan(tcp['source_port']), + print string % (position, date, cyan(source), cyan(tcp['source_port']), cyan(dest), cyan(tcp['dest_port']), getlen) +def print_position(position): + print ('Position # %s' % position) + + def print_layer1(date, getlen, caplen): print ('%s: captured %d bytes, truncated to %d bytes' % (date, getlen, caplen)) diff --git a/of10/parser.py b/of10/parser.py index 33646c4..d0266b0 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -188,11 +188,12 @@ def parse_FeatureRes(pkt): # Ports description? start = 24 + ports_array = [] while len(pkt.packet[start:]) > 0: ports = _parse_phy_ports(pkt.packet[start:start+48]) - pkt.prepare_printing('print_of_feature_res_ports', ports) + ports_array.append(ports) start = start + 48 - + pkt.prepare_printing('print_of_feature_res_ports', ports_array) return 1 diff --git a/of10/prints.py b/of10/prints.py index 241b3af..3f39bc8 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -109,53 +109,54 @@ def _dont_print_0(printed): def print_of_feature_res_ports(pkt): - ports = pkt.of_body['print_of_feature_res_ports'] - print ('FeatureRes - port_id: %s hw_addr: %s name: %s' % ( - green(ports['port_id']), green(ports['hw_addr']), - green(ports['name']))) - print ('FeatureRes - config:'), - printed = False - for i in ports['config']: - print of10.dissector.get_phy_config(i), - printed = True - else: - printed = _dont_print_0(printed) - print - print ('FeatureRes - state:'), - for i in ports['state']: - print of10.dissector.get_phy_state(i), - printed = True - else: - printed = _dont_print_0(printed) - print - print ('FeatureRes - curr:'), - for i in ports['curr']: - print of10.dissector.get_phy_feature(i), - printed = True - else: - printed = _dont_print_0(printed) - print - print ('FeatureRes - advertised:'), - for i in ports['advertised']: - print of10.dissector.get_phy_feature(i), - printed = True - else: - printed = _dont_print_0(printed) - print - print ('FeatureRes - supported:'), - for i in ports['supported']: - print of10.dissector.get_phy_feature(i), - printed = True - else: - printed = _dont_print_0(printed) - print - print ('FeatureRes - peer:'), - for i in ports['peer']: - print of10.dissector.get_phy_feature(i), - printed = True - else: - printed = _dont_print_0(printed) - print + ports_array = pkt.of_body['print_of_feature_res_ports'] + for ports in ports_array: + print ('FeatureRes - port_id: %s hw_addr: %s name: %s' % ( + green(ports['port_id']), green(ports['hw_addr']), + green(ports['name']))) + print ('FeatureRes - config:'), + printed = False + for i in ports['config']: + print of10.dissector.get_phy_config(i), + printed = True + else: + printed = _dont_print_0(printed) + print + print ('FeatureRes - state:'), + for i in ports['state']: + print of10.dissector.get_phy_state(i), + printed = True + else: + printed = _dont_print_0(printed) + print + print ('FeatureRes - curr:'), + for i in ports['curr']: + print of10.dissector.get_phy_feature(i), + printed = True + else: + printed = _dont_print_0(printed) + print + print ('FeatureRes - advertised:'), + for i in ports['advertised']: + print of10.dissector.get_phy_feature(i), + printed = True + else: + printed = _dont_print_0(printed) + print + print ('FeatureRes - supported:'), + for i in ports['supported']: + print of10.dissector.get_phy_feature(i), + printed = True + else: + printed = _dont_print_0(printed) + print + print ('FeatureRes - peer:'), + for i in ports['peer']: + print of10.dissector.get_phy_feature(i), + printed = True + else: + printed = _dont_print_0(printed) + print def print_ofp_match(pkt): diff --git a/ofp_sniffer.py b/ofp_sniffer.py index b328cad..df4b06f 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -44,10 +44,9 @@ def main(argv): (header, packet) = cap.next() if len(packet) >= 62: time = datetime.datetime.now() - pkt = Packet(packet, print_options, sanitizer) + pkt = Packet(packet, print_options, sanitizer, ctr) pkt.process_header(header.getlen(), header.getcaplen(), time) if pkt.openflow_packet: - print 'Packet #' + str(ctr) result = pkt.process_openflow_messages() if result is 1: pkt.print_packet() From 4d83f996e2f5e1993112a8f758e731349c67159a Mon Sep 17 00:00:00 2001 From: sdn Date: Mon, 8 Feb 2016 12:59:55 -0500 Subject: [PATCH 12/88] Support for filters and OpenFlow 1.0 completed. --- example_filter.json | 2 +- gen/filters.py | 33 ++++++++++++++++++++++++++++ gen/packet.py | 52 ++++++++++----------------------------------- of10/dissector.py | 1 + of10/prints.py | 2 +- 5 files changed, 47 insertions(+), 43 deletions(-) create mode 100644 gen/filters.py diff --git a/example_filter.json b/example_filter.json index c45a712..f55e1c3 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,7 +2,7 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 11, 14, 18, 19, 10, 13, 16, 17 + 0, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 17, 18 ] }, "1.3": { diff --git a/gen/filters.py b/gen/filters.py new file mode 100644 index 0000000..a1be6f8 --- /dev/null +++ b/gen/filters.py @@ -0,0 +1,33 @@ +''' + Filters to be used +''' +import gen.tcpip + + +def filter_OF_version(pkt): + # Was -F submitted? + if pkt.print_options['filters'] is 0: + return False + + # Check if the OpenFlow version is allowed + name_version = gen.tcpip.get_ofp_version(pkt.of_h['version']) + supported_versions = [] + for version in pkt.sanitizer['allowed_of_versions']: + supported_versions.append(version) + if name_version not in supported_versions: + return True + return False + + +def filter_OF_type(pkt): + # Was -F submitted? + if pkt.print_options['filters'] is 0: + return False + + name_version = gen.tcpip.get_ofp_version(pkt.of_h['version']) + # OF Types to be ignored through json file (-F) + rejected_types = pkt.sanitizer['allowed_of_versions'][name_version] + if pkt.of_h['type'] in rejected_types['rejected_of_types']: + return True + + return False diff --git a/gen/packet.py b/gen/packet.py index 5738bfe..fe0e1a2 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -3,6 +3,7 @@ from of10.parser import process_ofp_type import gen.prints import of10.prints +import gen.filters IP_PROTOCOL = 8 @@ -46,7 +47,8 @@ def process_openflow_body(self): if self.of_h['version'] is 1: try: if not process_ofp_type(self): - of10.prints.print_type_unknown(self) + # of10.prints.print_type_unknown(self) + return 0 return 1 except: self.handle_malformed_pkts() @@ -57,8 +59,11 @@ def prepare_printing(self, string, values): self.of_body[string] = values self.seq_of_print(string) - def print_packet(self): - # if not self.check_filters(): + def print_packet(self, pkt): + if not gen.filters.filter_OF_type(self): + if pkt.printed_header is False: + gen.prints.print_headers(pkt) + pkt.printed_header = True gen.prints.print_openflow_header(self.of_h) if self.of_h['version'] is 1: of10.prints.print_body(self) @@ -66,23 +71,6 @@ def print_packet(self): # print of13.prints.print_body(self) print - def check_filters(self): - # Was -F submitted? - if self.print_options['filters'] is 0: - return False - # Check if there is any limitation for printing - name_version = gen.tcpip.get_ofp_version(self.of_h['version']) - supported_versions = [] - for version in self.sanitizer['allowed_of_versions']: - supported_versions.append(version) - if name_version not in supported_versions: - return True - - # OF Types to be ignored through json file (-F) - rejected_types = self.sanitizer['allowed_of_versions'][name_version] - if self.of_h['type'] in rejected_types['rejected_of_types']: - return True - class Packet: ''' @@ -98,6 +86,7 @@ def __init__(self, packet, print_options, sanitizer, ctr): self.openflow_packet = False self.qtd_of_msg = 1 self.cur_msg = 0 + self.printed_header = False # Filters self.print_options = print_options @@ -185,25 +174,6 @@ def process_openflow_messages(self): return 1 def print_packet(self): - if not self.check_filters(): - gen.prints.print_headers(self) + if not gen.filters.filter_OF_version(self): for msg in self.ofmsgs: - msg.print_packet() - - def check_filters(self): - # Was -F submitted? - if self.print_options['filters'] is 0: - return False - # Check if there is any limitation for printing - name_version = gen.tcpip.get_ofp_version(self.of_h['version']) - supported_versions = [] - for version in self.sanitizer['allowed_of_versions']: - supported_versions.append(version) - if name_version not in supported_versions: - return True - # OF Types to be ignored through json file (-F) - rejected_types = self.sanitizer['allowed_of_versions'][name_version] - if self.of_h['type'] in rejected_types['rejected_of_types']: - return True - - return False + msg.print_packet(self) diff --git a/of10/dissector.py b/of10/dissector.py index 4070aec..c7c1a40 100644 --- a/of10/dissector.py +++ b/of10/dissector.py @@ -130,6 +130,7 @@ def get_vlan(vlan): except: return vlan + def get_ofp_flags(flag): flags = {0: 'NoFlagSet(0)', 1: 'SendFlowRem(1)', diff --git a/of10/prints.py b/of10/prints.py index 3f39bc8..c68d0b5 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -417,7 +417,7 @@ def print_ofp_statResDesc(pkt): def print_ofp_statResFlowArray(pkt): flows = pkt.of_body['print_ofp_statResFlowArray'] if len(flows) == 0: - print ('StatRes Type: Flow(1)\nNo Content') + print ('StatRes Type: Flow(1)\nNo Flows') return for flow_stats in flows: From 165d4f813f9a892dafd1c927bb9ba9060a9f31db Mon Sep 17 00:00:00 2001 From: sdn Date: Mon, 8 Feb 2016 19:25:43 -0500 Subject: [PATCH 13/88] Support for OF 1.3 added: Hello, Error, EchoReq, EchoRes, FeatureReq, FeatureRes, GetConfigReq, GetConfigRes, SetConfig, BarrierReq and BarrierRes. Support for FlowMod: OXM Matches ready, working on Instructions now --- gen/packet.py | 15 ++- of13/parser.py | 332 +++++++++++++++++++++++++------------------------ of13/prints.py | 125 ++++++++++++------- 3 files changed, 264 insertions(+), 208 deletions(-) diff --git a/gen/packet.py b/gen/packet.py index fe0e1a2..254c96f 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -1,9 +1,11 @@ from gen.tcpip import get_ethernet_frame, get_ip_packet, get_tcp_stream, \ get_openflow_header from of10.parser import process_ofp_type +from of13.parser import process_ofp_type13 import gen.prints import of10.prints import gen.filters +import of13.prints IP_PROTOCOL = 8 @@ -53,6 +55,15 @@ def process_openflow_body(self): except: self.handle_malformed_pkts() return -1 + if self.of_h['version'] is 4: + try: + if not process_ofp_type13(self): + # of10.prints.print_type_unknown(self) + return 0 + return 1 + except: + self.handle_malformed_pkts() + return -1 return 0 def prepare_printing(self, string, values): @@ -67,8 +78,8 @@ def print_packet(self, pkt): gen.prints.print_openflow_header(self.of_h) if self.of_h['version'] is 1: of10.prints.print_body(self) - # elif self.of_h['version'] is 4: - # print of13.prints.print_body(self) + elif self.of_h['version'] is 4: + of13.prints.print_body(self) print diff --git a/of13/parser.py b/of13/parser.py index 3432b61..7ab4349 100644 --- a/of13/parser.py +++ b/of13/parser.py @@ -3,133 +3,134 @@ import netaddr -def process_ofp_type13(of_type, packet, h_size, of_xid, print_options, - sanitizer): - if of_type == 0: - result = parse_Hello(packet, h_size, of_xid) - elif of_type == 1: - result = parse_Error(packet, h_size, of_xid) - elif of_type == 2: - result = parse_EchoReq(packet, h_size, of_xid) - elif of_type == 3: - result = parse_EchoRes(packet, h_size, of_xid) - elif of_type == 4: - result = parse_Experimenter(packet, h_size, of_xid) - elif of_type == 5: - result = parse_FeatureReq(packet, h_size, of_xid) - elif of_type == 6: - result = parse_FeatureRes(packet, h_size, of_xid) - elif of_type == 7: - result = parse_GetConfigReq(packet, h_size, of_xid) - elif of_type == 8: - result = parse_GetConfigRes(packet, h_size, of_xid) - elif of_type == 9: - result = parse_SetConfig(packet, h_size, of_xid) - elif of_type == 10: - result = parse_PacketIn(packet, h_size, of_xid, sanitizer) - elif of_type == 11: - result = parse_FlowRemoved(packet, h_size, of_xid) - elif of_type == 12: - result = parse_PortStatus(packet, h_size, of_xid) - elif of_type == 13: - result = parse_PacketOut(packet, h_size, of_xid, sanitizer, - print_options) - elif of_type == 14: - result = parse_FlowMod(packet, h_size, of_xid, print_options) - elif of_type == 15: - result = parse_GroupMod(packet, h_size, of_xid) - elif of_type == 16: - result = parse_PortMod(packet, h_size, of_xid) - elif of_type == 17: - result = parse_TableMod(packet, h_size, of_xid) - elif of_type == 18: - result = parse_MultipartReq(packet, h_size, of_xid) - elif of_type == 19: - result = parse_MultipartRes(packet, h_size, of_xid) - elif of_type == 20: - result = parse_BarrierReq(packet, h_size, of_xid) - elif of_type == 21: - result = parse_BarrierRes(packet, h_size, of_xid) - elif of_type == 22: - result = parse_QueueGetConfigReq(packet, h_size, of_xid) - elif of_type == 23: - result = parse_QueueGetConfigRes(packet, h_size, of_xid) - elif of_type == 24: - result = parse_RoleReq(packet, h_size, of_xid) - elif of_type == 25: - result = parse_RoleRes(packet, h_size, of_xid) - elif of_type == 26: - result = parse_GetAsyncReq(packet, h_size, of_xid) - elif of_type == 27: - result = parse_GetAsyncRes(packet, h_size, of_xid) - elif of_type == 28: - result = parse_SetAsync(packet, h_size, of_xid) - elif of_type == 29: - result = parse_MeterMod(packet, h_size, of_xid) +def process_ofp_type13(pkt): + if pkt.of_h['type'] == 0: + result = parse_Hello(pkt) + elif pkt.of_h['type'] == 1: + result = parse_Error(pkt) + elif pkt.of_h['type'] == 2: + result = parse_EchoReq(pkt) + elif pkt.of_h['type'] == 3: + result = parse_EchoRes(pkt) + elif pkt.of_h['type'] == 4: + result = parse_Experimenter(pkt) + elif pkt.of_h['type'] == 5: + result = parse_FeatureReq(pkt) + elif pkt.of_h['type'] == 6: + result = parse_FeatureRes(pkt) + elif pkt.of_h['type'] == 7: + result = parse_GetConfigReq(pkt) + elif pkt.of_h['type'] == 8: + result = parse_GetConfigRes(pkt) + elif pkt.of_h['type'] == 9: + result = parse_SetConfig(pkt) + elif pkt.of_h['type'] == 10: + result = parse_PacketIn(pkt) + elif pkt.of_h['type'] == 11: + result = parse_FlowRemoved(pkt) + elif pkt.of_h['type'] == 12: + result = parse_PortStatus(pkt) + elif pkt.of_h['type'] == 13: + result = parse_PacketOut(pkt) + elif pkt.of_h['type'] == 14: + result = parse_FlowMod(pkt) + elif pkt.of_h['type'] == 15: + result = parse_GroupMod(pkt) + elif pkt.of_h['type'] == 16: + result = parse_PortMod(pkt) + elif pkt.of_h['type'] == 17: + result = parse_TableMod(pkt) + elif pkt.of_h['type'] == 18: + result = parse_MultipartReq(pkt) + elif pkt.of_h['type'] == 19: + result = parse_MultipartRes(pkt) + elif pkt.of_h['type'] == 20: + result = parse_BarrierReq(pkt) + elif pkt.of_h['type'] == 21: + result = parse_BarrierRes(pkt) + elif pkt.of_h['type'] == 22: + result = parse_QueueGetConfigReq(pkt) + elif pkt.of_h['type'] == 23: + result = parse_QueueGetConfigRes(pkt) + elif pkt.of_h['type'] == 24: + result = parse_RoleReq(pkt) + elif pkt.of_h['type'] == 25: + result = parse_RoleRes(pkt) + elif pkt.of_h['type'] == 26: + result = parse_GetAsyncReq(pkt) + elif pkt.of_h['type'] == 27: + result = parse_GetAsyncRes(pkt) + elif pkt.of_h['type'] == 28: + result = parse_SetAsync(pkt) + elif pkt.of_h['type'] == 29: + result = parse_MeterMod(pkt) else: return 0 return result # *************** Hello ***************** -def parse_Hello(packet, h_size, of_xid): +def parse_Hello(pkt): - def process_bitmap(of_xid, bitmap): - of13.prints.print_hello_bitmap(of_xid, bitmap) - - start = h_size + start = 0 count = 0 - while len(packet[start:]) > 0: + while len(pkt.packet[start:]) > 0: # Get element[] count += 1 - elem_raw = packet[start:start+4] - el_type, el_length = unpack('!HH', elem_raw) - of13.prints.print_hello_elememnts(of_xid, el_type, el_length, count) + elem_raw = pkt.packet[start:start+4] + hello_raw = unpack('!HH', elem_raw) + hello = {'type': hello_raw[0], 'length': hello_raw[1], 'count': count} + pkt.prepare_printing('print_hello_elements', hello) - bitmaps = packet[start+4:start+el_length] + bitmaps = pkt.packet[start+4:start+hello['length']] start_bit = 0 + bmps = [] while len(bitmaps[start_bit:]) > 0: - bitmap_raw = packet[start_bit:start_bit+4] + bitmap_raw = pkt.packet[start_bit:start_bit+4] bitmap = unpack('!L', bitmap_raw) - process_bitmap(of_xid, bitmap[0]) + bmps.append(bitmap[0]) start_bit = start_bit + 4 - start = start + el_length + pkt.prepare_printing('print_hello_bitmap', bmps) + + start = start + hello['length'] return 1 # ************** Error ***************** -def parse_Error(packet, h_size, of_xid): - of_error = packet[h_size:h_size+4] +def parse_Error(pkt): + of_error = pkt.packet[0:4] ofe = unpack('!HH', of_error) ofe_type = ofe[0] ofe_code = ofe[1] - nameCode, typeCode = of13.dissector.get_ofp_error(ofe_type, ofe_code) - of13.prints.print_of_error(of_xid, nameCode, typeCode) + codes = {} + codes['name'], codes['type'] = of13.dissector.get_ofp_error(ofe_type, + ofe_code) + pkt.prepare_printing('print_of_error', codes) return 1 # ************ EchoReq ***************** -def parse_EchoReq(packet, h_size, of_xid): - of13.prints.print_echoreq(of_xid) +def parse_EchoReq(pkt): + pkt.prepare_printing('print_echoreq', None) return 1 # ************ EchoRes ***************** -def parse_EchoRes(packet, h_size, of_xid): - of13.prints.print_echores(of_xid) +def parse_EchoRes(pkt): + pkt.prepare_printing('print_echores', None) return 1 -def parse_Experimenter(packet, h_size, of_xid): +def parse_Experimenter(pkt): return 0 -def parse_FeatureReq(packet, h_size, of_xid): - of13.prints.print_of_feature_req(of_xid) +def parse_FeatureReq(pkt): + pkt.prepare_printing('print_of_feature_req', None) return 1 @@ -149,8 +150,8 @@ def _parse_capabilities(capabilities): return _parse_bitmask(capabilities, caps) -def parse_FeatureRes(packet, h_size, of_xid): - of_fres = packet[h_size:h_size+24] +def parse_FeatureRes(pkt): + of_fres = pkt.packet[0:24] ofrs = unpack('!8sLBBHLL', of_fres) caps = [] caps = _parse_capabilities(ofrs[5]) @@ -159,13 +160,13 @@ def parse_FeatureRes(packet, h_size, of_xid): 'auxiliary_id': ofrs[3], 'pad': ofrs[4], 'caps': caps, 'reserved': ofrs[6]} - of13.prints.print_of_feature_res(of_xid, f_res) + pkt.prepare_printing('print_of_feature_res', f_res) return 1 # ***************** GetConfigReq ********************* -def parse_GetConfigReq(packet, h_size, of_xid): - of13.prints.print_of_getconfig_req(of_xid) +def parse_GetConfigReq(pkt): + pkt.prepare_printing('print_of_getconfig_req', None) return 1 @@ -178,32 +179,34 @@ def _parse_SetGetConfig(packet, h_size): return flag, miss_send_len -def parse_GetConfigRes(packet, h_size, of_xid): - flag, miss_send_len = _parse_SetGetConfig(packet, h_size) - of13.prints.print_of_getConfigRes(of_xid, flag, miss_send_len) +def parse_GetConfigRes(pkt): + configres = {} + configres['flag'], configres['miss'] = _parse_SetGetConfig(pkt.packet, 0) + pkt.prepare_printing('print_of_getConfigRes', configres) return 1 # ******************* SetConfig ********************** -def parse_SetConfig(packet, h_size, of_xid): - flag, miss_send_len = _parse_SetGetConfig(packet, h_size) - of13.prints.print_of_setConfig(of_xid, flag, miss_send_len) +def parse_SetConfig(pkt): + setconfig = {} + setconfig['flag'], setconfig['miss'] = _parse_SetGetConfig(pkt.packet, 0) + pkt.prepare_printing('print_of_setConfig', setconfig) return 1 -def parse_PacketIn(packet, h_size, of_xid, sanitizer): +def parse_PacketIn(pkt): return 0 -def parse_FlowRemoved(packet, h_size, of_xid): +def parse_FlowRemoved(pkt): return 0 -def parse_PortStatus(packet, h_size, of_xid): +def parse_PortStatus(pkt): return 0 -def parse_PacketOut(packet, h_size, of_xid, sanitizer, print_options): +def parse_PacketOut(pkt): return 0 @@ -260,34 +263,27 @@ def unpack_oxm_content(content_length, oxm_content, oxm): return oxm -def print_oxm(of_xid, oxm, content_length, x_content): +def prepare_oxm(pkt, oxm, x_content): + content_length = len(x_content) oxm = unpack_oxm_content(content_length, x_content, oxm) - - of13.prints.print_match_generic(of_xid, oxm) - of13.prints.print_match(oxm) - - -def print_padding(padding): - for i in range(0, padding): - print '\b0', - print + return oxm -def _parse_matches(of_xid, packet, start): - matches_raw = packet[start:start+4] - matches = unpack('!HH', matches_raw) - m_type = matches[0] - m_length = matches[1] +def _parse_matches(pkt, start): + matches_raw = pkt.packet[start:start+4] + matches = {} + matches['type'], matches['length'] = unpack('!HH', matches_raw) - of13.prints.print_match_type(of_xid, m_type, m_length) + pkt.prepare_printing('print_match_type', matches) - length_oxm = (m_length - 4) - padding = (((m_length + 7)/8*8 - m_length)) + length_oxm = (matches['length'] - 4) + padding = (((matches['length'] + 7)/8*8 - matches['length'])) start = start + 4 - oxms = packet[start:start+length_oxm] + oxms = pkt.packet[start:start+length_oxm] start_2 = 0 + oxm_array = [] while len(oxms[start_2:]) > 0: oxm_raw = oxms[start_2:start_2+4] oxm = unpack('!L', oxm_raw) @@ -299,18 +295,23 @@ def _parse_matches(of_xid, packet, start): 'length': x_length} oxm_content = oxms[start_2+4:start_2+4+x_length] - print_oxm(of_xid, oxm_tlv, len(oxm_content), oxm_content) + # insert print_oxm into an array for printing. + oxm_processed = prepare_oxm(pkt, oxm_tlv, oxm_content) + oxm_array.append(oxm_processed) start_2 = start_2 + 4 + x_length - print ('%s Flow Matches - Padding: ' % of_xid), - print_padding(padding) + pkt.prepare_printing('print_match', oxm_array) + + pads = {'message': padding} + pkt.prepare_printing('print_padding', pads) # Return offset for Instructions return start + length_oxm + padding -def _parse_actions(of_xid, packet, length): - print '%s Actions: ' % (of_xid) +def _parse_actions(packet, length): + return + print 'Actions: ' def _inst_goto_table(packet, start, i_len): @@ -325,13 +326,15 @@ def _inst_write_actions(packet, start, i_len): print -def _inst_apply_actions(of_xid, packet, start, i_len): - print 'APPLY_ACTIONS' +def _inst_apply_actions(pkt, start, i_len): + string = {'message': 'APPLY_ACTIONS'} + pkt.prepare_printing('print_string', string) - apply_raw = packet[start:start+4] + apply_raw = pkt.packet[start:start+4] apply_padding = unpack('!L', apply_raw) - print '%s Padding: %s' % (of_xid, apply_padding[0]) - _parse_actions(of_xid, packet[start+4:], i_len-8) + string = {'message': apply_padding[0]} + pkt.prepare_printing('print_padding', string) + _parse_actions(pkt.packet[start+4:], i_len-8) def _inst_clear_actions(packet, start, i_len): @@ -346,39 +349,40 @@ def _inst_experimenter(packet, start, i_len): print -def _parse_instructions(of_xid, packet, instructions_start): +def _parse_instructions(pkt, instructions_start): start = instructions_start - while len(packet[start:]) > 0: - instructions_raw = packet[instructions_start:instructions_start+4] + while len(pkt.packet[start:]) > 0: + instructions_raw = pkt.packet[instructions_start:instructions_start+4] instructions = unpack('!HH', instructions_raw) i_type = instructions[0] i_len = instructions[1] start = start + 4 - print ('%s Instructions:' % of_xid), + string = {'message': 'Instructions:'} + pkt.prepare_printing('print_instruction', string) # Call proper instruction if i_type == 1: - _inst_goto_table(packet, start, i_len) + _inst_goto_table(pkt, start, i_len) elif i_type == 2: - _inst_write_metadata(packet, start, i_len) + _inst_write_metadata(pkt, start, i_len) elif i_type == 3: - _inst_write_actions(packet, start, i_len) + _inst_write_actions(pkt, start, i_len) elif i_type == 4: - _inst_apply_actions(of_xid, packet, start, i_len) + _inst_apply_actions(pkt, start, i_len) elif i_type == 5: - _inst_clear_actions(packet, start, i_len) + _inst_clear_actions(pkt, start, i_len) elif i_type == 6: - _inst_meter(packet, start, i_len) + _inst_meter(pkt, start, i_len) elif i_type == 65535: - _inst_experimenter(packet, start, i_len) + _inst_experimenter(pkt, start, i_len) start = start + i_len - 4 -def parse_FlowMod(packet, h_size, of_xid, print_options): - flow_mod_raw = packet[h_size:h_size+40] +def parse_FlowMod(pkt): + flow_mod_raw = pkt.packet[0:40] ofmod = unpack('!QQBBHHHLLLHH', flow_mod_raw) cookie = ofmod[0] if ofmod[0] > 0 else 0 @@ -395,72 +399,72 @@ def parse_FlowMod(packet, h_size, of_xid, print_options): 'out_port': port, 'out_group': ofmod[9], 'flags': ofmod[10], 'padding': ofmod[11]} - of13.prints.print_flow_mod(of_xid, flow_mod) + pkt.prepare_printing('print_flow_mod', flow_mod) - instructions_start = _parse_matches(of_xid, packet, h_size+40) + instructions_start = _parse_matches(pkt, 40) - _parse_instructions(of_xid, packet, instructions_start) + _parse_instructions(pkt, instructions_start) return 1 -def parse_GroupMod(packet, h_size, of_xid): +def parse_GroupMod(pkt): return 0 -def parse_PortMod(packet, h_size, of_xid): +def parse_PortMod(pkt): return 0 -def parse_TableMod(packet, h_size, of_xid): +def parse_TableMod(pkt): return 0 -def parse_MultipartReq(packet, h_size, of_xid): +def parse_MultipartReq(pkt): return 0 -def parse_MultipartRes(packet, h_size, of_xid): +def parse_MultipartRes(pkt): return 0 -def parse_BarrierReq(packet, h_size, of_xid): - of13.prints.print_of_BarrierReq(of_xid) +def parse_BarrierReq(pkt): + pkt.prepare_printing('print_of_BarrierReq', None) return 1 -def parse_BarrierRes(packet, h_size, of_xid): - of13.prints.print_of_BarrierReply(of_xid) +def parse_BarrierRes(pkt): + pkt.prepare_printing('print_of_BarrierReply', None) return 1 -def parse_QueueGetConfigReq(packet, h_size, of_xid): +def parse_QueueGetConfigReq(pkt): return 0 -def parse_QueueGetConfigRes(packet, h_size, of_xid): +def parse_QueueGetConfigRes(pkt): return 0 -def parse_RoleReq(packet, h_size, of_xid): +def parse_RoleReq(pkt): return 0 -def parse_RoleRes(packet, h_size, of_xid): +def parse_RoleRes(pkt): return 0 -def parse_GetAsyncReq(packet, h_size, of_xid): +def parse_GetAsyncReq(pkt): return 0 -def parse_GetAsyncRes(packet, h_size, of_xid): +def parse_GetAsyncRes(pkt): return 0 -def parse_SetAsync(packet, h_size, of_xid): +def parse_SetAsync(pkt): return 0 -def parse_MeterMod(packet, h_size, of_xid): +def parse_MeterMod(pkt): return 0 diff --git a/of13/prints.py b/of13/prints.py index 4f9a569..d7f0de8 100644 --- a/of13/prints.py +++ b/of13/prints.py @@ -17,85 +17,106 @@ def datapath_id(string): return gen.prints.datapath_id(string) -def print_hello_elememnts(of_xid, el_type, el_length, count): - print ('%s Hello - Element: %s Type: %s Length: %s' % - (of_xid, count, el_type, el_length)) +def print_string(pkt): + print pkt.of_body['print_string']['message'] -def print_hello_bitmap(of_xid, bitmap): - print ('%s Hello - Bitmap: %s' % (of_xid, hex(bitmap))) +def print_hello_elements(pkt): + hello = pkt.of_body['print_hello_elements'] + print ('Hello - Element: %s Type: %s Length: %s' % + (hello['count'], hello['type'], hello['length'])) -def print_of_error(of_xid, nameCode, typeCode): - print ('%s OpenFlow Error - Type: %s Code: %s' % - (of_xid, red(nameCode), red(typeCode))) +def print_hello_bitmap(pkt): + bitmaps = pkt.of_body['print_hello_bitmap'] + for bitmap in bitmaps: + print ('Hello - Bitmap: %s' % (hex(bitmap))) -def print_echoreq(of_xid): - print ('%s OpenFlow Echo Request' % (of_xid)) +def print_of_error(pkt): + codes = pkt.of_body['print_of_error'] + print ('OpenFlow Error - Type: %s Code: %s' % + (red(codes['name']), red(codes['type']))) -def print_echores(of_xid): - print ('%s OpenFlow Echo Reply' % (of_xid)) +def print_echoreq(pkt): + print 'OpenFlow Echo Request' -def print_of_feature_req(of_xid): - print '%s OpenFlow Feature Request' % of_xid +def print_echores(pkt): + print 'OpenFlow Echo Reply' -def print_of_feature_res(of_xid, f_res): - print '%s OpenFlow Feature Reply' % of_xid +def print_of_feature_req(pkt): + print 'OpenFlow Feature Request' + + +def print_of_feature_res(pkt): + f_res = pkt.of_body['print_of_feature_res'] + print 'OpenFlow Feature Reply' dpid = datapath_id(f_res['datapath_id']) - print ('%s FeatureRes - datapath_id: %s n_buffers: %s n_tbls: %s ' + print ('FeatureRes - datapath_id: %s n_buffers: %s n_tbls: %s ' 'Auxiliary_ID: %s , pad: %s' - % (of_xid, green(dpid), f_res['n_buffers'], f_res['n_tbls'], + % (green(dpid), f_res['n_buffers'], f_res['n_tbls'], f_res['auxiliary_id'], f_res['pad'])) - print ('%s FeatureRes - Capabilities:' % of_xid), + print ('FeatureRes - Capabilities:'), for i in f_res['caps']: print of13.dissector.get_feature_res_capabilities(i), print -def print_of_getconfig_req(of_xid): - print '%s OpenFlow GetConfig Request' % of_xid +def print_of_getconfig_req(pkt): + print 'OpenFlow GetConfig Request' -def print_of_getConfigRes(of_xid, flag, miss): - print ('%s OpenFlow GetConfigRes - Flag: %s Miss_send_len: %s' % - (of_xid, flag, miss)) +def print_of_getConfigRes(pkt): + configres = pkt.of_body['print_of_getConfigRes'] + print ('OpenFlow GetConfigRes - Flag: %s Miss_send_len: %s' % + (configres['flag'], configres['miss'])) -def print_of_setConfig(of_xid, flag, miss): - print ('%s OpenFlow SetConfig - Flag: %s Miss_send_len: %s' % - (of_xid, flag, miss)) +def print_of_setConfig(pkt): + setconf = pkt.of_body['print_of_setConfig'] + print ('OpenFlow SetConfig - Flag: %s Miss_send_len: %s' % + (setconf['flag'], setconf['miss'])) -def print_flow_mod(of_xid, fmod): - string = ('%s FlowMod - Cookie/Mask: %s/%s Table_id: %s Command: %s ' - 'Idle/Hard Timeouts: %s/%s\n%s FlowMod - Priority: %s ' +def print_flow_mod(pkt): + fmod = pkt.of_body['print_flow_mod'] + string = ('FlowMod - Cookie/Mask: %s/%s Table_id: %s Command: %s ' + 'Idle/Hard Timeouts: %s/%s\nFlowMod - Priority: %s ' 'Buffer ID: %s Out Port: %s Out Group: %s Flags: %s Pad: %s') command = green(of13.dissector.get_of_command(fmod['command'])) flags = green(of13.dissector.get_of_flags(fmod['flags'])) port = green(of13.dissector.get_phy_port_id(fmod['out_port'])) - print string % (of_xid, fmod['cookie'], fmod['cookie_mask'], + print string % (fmod['cookie'], fmod['cookie_mask'], fmod['table_id'], command, fmod['idle_timeout'], - fmod['hard_timeout'], of_xid, fmod['priority'], + fmod['hard_timeout'], fmod['priority'], fmod['buffer_id'], port, fmod['out_group'], flags, fmod['padding']) -def print_match_type(of_xid, m_type, m_length): - print '%s Flow Matches - Type: %s Length: %s' % (of_xid, m_type, m_length) +def print_match_type(pkt): + matches = pkt.of_body['print_match_type'] + print ('Flow Matches - Type: %s Length: %s' % + (matches['type'], matches['length'])) + +def print_match(pkt): + oxm_array = pkt.of_body['print_match'] + for oxm in oxm_array: + print_match_generic(oxm) + print_match_oxm(oxm) -def print_match_generic(of_xid, oxm): - print ('%s OXM Match: Class: %s Length: %s HasMask: %s Field: %s:' % - (of_xid, hex(oxm['class']), oxm['length'], oxm['hasmask'], + +def print_match_generic(oxm): + print ('OXM Match: Class: %s Length: %s HasMask: %s Field: %s:' % + (hex(oxm['class']), oxm['length'], oxm['hasmask'], green(of13.dissector.get_flow_match_fields(oxm['field'])))), -def print_match(oxm): +def print_match_oxm(oxm): if oxm['hasmask'] == 0: if oxm['field'] in [0]: oxm['value'] = oxm['value'] & 0xffff @@ -135,9 +156,29 @@ def print_match(oxm): print ('%s/%s' % (green(oxm['value']), green(oxm['mask']))) -def print_of_BarrierReq(of_xid): - print '%s OpenFlow Barrier Request' % of_xid +def print_padding(pkt): + padding = pkt.of_body['print_padding'] + if padding['message'] is 0: + print ('Padding: 0') + else: + print ('Padding: '), + for i in range(0, padding['message']): + print '\b0', + print + + +def print_instruction(pkt): + print ('Instructions:'), + + +def print_of_BarrierReq(pkt): + print 'OpenFlow Barrier Request' + + +def print_of_BarrierReply(pkt): + print 'OpenFlow Barrier Reply' -def print_of_BarrierReply(of_xid): - print '%s OpenFlow Barrier Reply' % of_xid +def print_body(pkt): + for f in pkt.printing_seq: + eval(f)(pkt) From aa8e6602d363f96b5d8de5c38ac3ef50eef9bc06 Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Wed, 16 Dec 2015 12:40:51 -0500 Subject: [PATCH 14/88] Bug Fixes for PortStatus and PacketOut/LLDP --- example_filter.json | 2 +- gen/cli.py | 23 ++++++++++- gen/proxies.py | 6 ++- gen/tcpip.py | 6 ++- of10/parser.py | 4 +- of10/prints.py | 98 ++++++++++++++++++++++----------------------- ofp_sniffer.py | 12 +----- 7 files changed, 84 insertions(+), 67 deletions(-) diff --git a/example_filter.json b/example_filter.json index f55e1c3..5e2b916 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,7 +2,7 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 0, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 17, 18 + 10, 13 ] }, "1.3": { diff --git a/gen/cli.py b/gen/cli.py index df717a9..050b4fa 100644 --- a/gen/cli.py +++ b/gen/cli.py @@ -1,6 +1,7 @@ import sys import getopt import json +import pcapy VERSION = '0.3-dev' @@ -43,6 +44,24 @@ def read_sanitizer(sanitizer_file): return (json_content) +def start_capture(capfile, infilter, dev): + try: + if len(capfile) > 0: + print "Using file %s " % capfile + cap = pcapy.open_offline(capfile) + else: + print "Sniffing device %s" % dev + cap = pcapy.open_live(dev, 65536, 1, 0) + + main_filter = " port 6633 " + cap.setfilter(main_filter + infilter) + return cap + + except Exception as exception: + print exception + return -1 + + def get_params(argv): # Handle all input params letters = 'f:F:i:r:p:ohvcd' @@ -100,4 +119,6 @@ def get_params(argv): print_options['filters'] = 1 sanitizer = read_sanitizer(sanitizer_file) - return print_options, input_filter, sanitizer, dev, captured_file + cap = start_capture(captured_file, input_filter, dev) + + return cap, print_options, sanitizer diff --git a/gen/proxies.py b/gen/proxies.py index 1bfd682..405db91 100644 --- a/gen/proxies.py +++ b/gen/proxies.py @@ -22,7 +22,11 @@ def support_fsfw(pkt, lldp): def get_name_dpid(dpid): - return '%s' % name.get(dpid) + sw_name = name.get(dpid) + if sw_name is not None: + return sw_name + + return 'OFswitch' def get_ip_name(ip, port): diff --git a/gen/tcpip.py b/gen/tcpip.py index 35a5068..4f83cb5 100644 --- a/gen/tcpip.py +++ b/gen/tcpip.py @@ -204,12 +204,13 @@ def get_lldp(packet): start = start + 4 # Loop to get User-Specific TLVs - while len(packet[start:]) > 0: + while len(packet[start:]) > 2: next_raw = packet[start:start+2] nraw = unpack('!H', next_raw) n_type = nraw[0] >> 9 n_length = nraw[0] & 0xFF length = n_length - 4 + if n_type == 0: break elif n_type == 127: @@ -224,7 +225,8 @@ def get_lldp(packet): string = '!%ss' % length content = unpack(string, content_raw) c_id = content[0] - start = start + length + + start = start + n_length + 2 # END end_raw = packet[start:start+2] diff --git a/of10/parser.py b/of10/parser.py index d0266b0..41d7f4c 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -193,7 +193,7 @@ def parse_FeatureRes(pkt): ports = _parse_phy_ports(pkt.packet[start:start+48]) ports_array.append(ports) start = start + 48 - pkt.prepare_printing('print_of_feature_res_ports', ports_array) + pkt.prepare_printing('print_of_ports', ports_array) return 1 @@ -338,7 +338,7 @@ def parse_PortStatus(pkt): pkt.prepare_printing('print_portStatus', p_status) ports = _parse_phy_ports(pkt.packet[8:64]) - pkt.prepare_printing('print_of_feature_res_ports', ports) + pkt.prepare_printing('print_of_ports', ports) return 1 diff --git a/of10/prints.py b/of10/prints.py index c68d0b5..ab61867 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -108,55 +108,55 @@ def _dont_print_0(printed): return False -def print_of_feature_res_ports(pkt): - ports_array = pkt.of_body['print_of_feature_res_ports'] - for ports in ports_array: - print ('FeatureRes - port_id: %s hw_addr: %s name: %s' % ( - green(ports['port_id']), green(ports['hw_addr']), - green(ports['name']))) - print ('FeatureRes - config:'), - printed = False - for i in ports['config']: - print of10.dissector.get_phy_config(i), - printed = True - else: - printed = _dont_print_0(printed) - print - print ('FeatureRes - state:'), - for i in ports['state']: - print of10.dissector.get_phy_state(i), - printed = True - else: - printed = _dont_print_0(printed) - print - print ('FeatureRes - curr:'), - for i in ports['curr']: - print of10.dissector.get_phy_feature(i), - printed = True - else: - printed = _dont_print_0(printed) - print - print ('FeatureRes - advertised:'), - for i in ports['advertised']: - print of10.dissector.get_phy_feature(i), - printed = True - else: - printed = _dont_print_0(printed) - print - print ('FeatureRes - supported:'), - for i in ports['supported']: - print of10.dissector.get_phy_feature(i), - printed = True - else: - printed = _dont_print_0(printed) - print - print ('FeatureRes - peer:'), - for i in ports['peer']: - print of10.dissector.get_phy_feature(i), - printed = True - else: - printed = _dont_print_0(printed) - print +def print_port_field(port, field): + port_id = '%s' % green(port['port_id']) + printed = False + + print ('Port_id: %s - %s curr:' % (port_id, field)), + for i in port[field]: + print of10.dissector.get_phy_feature(i), + printed = True + else: + printed = _dont_print_0(printed) + print + + +def print_ofp_phy_port(port): + port_id = '%s' % green(port['port_id']) + + print ('Port_id: %s - hw_addr: %s name: %s' % ( + port_id, green(port['hw_addr']), green(port['name']))) + + print ('Port_id: %s - config:' % port_id), + printed = False + for i in port['config']: + print of10.dissector.get_phy_config(i), + printed = True + else: + printed = _dont_print_0(printed) + print + + print ('Port_id: %s - state:' % port_id), + for i in port['state']: + print of10.dissector.get_phy_state(i), + printed = True + else: + printed = _dont_print_0(printed) + print + + following_fields = ['curr', 'advertised', 'supported', 'peer'] + + for field in following_fields: + print_port_field(port, field) + + +def print_of_ports(pkt): + ports = pkt.of_body['print_of_ports'] + if type(ports) is not list: + print_ofp_phy_port(ports) + else: + for port in ports: + print_ofp_phy_port(port) def print_ofp_match(pkt): diff --git a/ofp_sniffer.py b/ofp_sniffer.py index df4b06f..7b6fbb5 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -26,18 +26,8 @@ def main(argv): ''' This is the main function ''' - print_options, infilter, sanitizer, dev, capfile = gen.cli.get_params(argv) + cap, print_options, sanitizer = gen.cli.get_params(argv) try: - if len(capfile) > 0: - print "Using file %s " % capfile - cap = pcapy.open_offline(capfile) - else: - print "Sniffing device %s" % dev - cap = pcapy.open_live(dev, 65536, 1, 0) - - main_filter = " port 6633 " - cap.setfilter(main_filter + infilter) - ctr = 1 # start sniffing packets while(1): From 55939c5f063c4e7e2ed0e27c8e31d08fe99303bc Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Thu, 11 Feb 2016 17:16:15 -0800 Subject: [PATCH 15/88] Fixed LLDP for Type 127 Changed the approach for packet capture. Instead of cap.next, migrated to cap.loop. This change was made because of the "time out" when using Ubuntu and VirtualBox --- gen/tcpip.py | 5 ++--- ofp_sniffer.py | 38 +++++++++++++++++++++----------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/gen/tcpip.py b/gen/tcpip.py index 4f83cb5..ef59010 100644 --- a/gen/tcpip.py +++ b/gen/tcpip.py @@ -203,6 +203,7 @@ def get_lldp(packet): t_ttl = ttl[1] start = start + 4 + # Loop to get User-Specific TLVs while len(packet[start:]) > 2: next_raw = packet[start:start+2] @@ -210,7 +211,6 @@ def get_lldp(packet): n_type = nraw[0] >> 9 n_length = nraw[0] & 0xFF length = n_length - 4 - if n_type == 0: break elif n_type == 127: @@ -219,9 +219,8 @@ def get_lldp(packet): # Skip the OUI - 3 bytes subtype_raw = packet[start+5:start+6] subtype = unpack('!B', subtype_raw) - start = start + 6 if subtype[0] == 2: - content_raw = packet[start:start+length] + content_raw = packet[start+6:start+6+length] string = '!%ss' % length content = unpack(string, content_raw) c_id = content[0] diff --git a/ofp_sniffer.py b/ofp_sniffer.py index 7b6fbb5..d062a08 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -22,28 +22,31 @@ from gen.packet import Packet +ctr = 1 + + +def process_packet(header, packet): + global ctr + if len(packet) >= 62: + time = datetime.datetime.now() + pkt = Packet(packet, print_options, sanitizer, ctr) + pkt.process_header(header.getlen(), header.getcaplen(), time) + if pkt.openflow_packet: + result = pkt.process_openflow_messages() + if result is 1: + pkt.print_packet() + del pkt + elif len(packet) is 0: + sys.exit(0) + ctr += 1 + + def main(argv): ''' This is the main function ''' - cap, print_options, sanitizer = gen.cli.get_params(argv) try: - ctr = 1 - # start sniffing packets - while(1): - (header, packet) = cap.next() - if len(packet) >= 62: - time = datetime.datetime.now() - pkt = Packet(packet, print_options, sanitizer, ctr) - pkt.process_header(header.getlen(), header.getcaplen(), time) - if pkt.openflow_packet: - result = pkt.process_openflow_messages() - if result is 1: - pkt.print_packet() - del pkt - elif len(packet) is 0: - sys.exit(0) - ctr += 1 + cap.loop(-1, process_packet) except KeyboardInterrupt: print 'Exiting...' @@ -54,4 +57,5 @@ def main(argv): if __name__ == "__main__": + cap, print_options, sanitizer = gen.cli.get_params(sys.argv) main(sys.argv) From 4a9d739d913c1c014467e020c72523a43e781c81 Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Sat, 12 Mar 2016 08:35:01 -0800 Subject: [PATCH 16/88] Adding the Packet.py --- example_filter.json | 2 +- gen/Packet.py | 257 ++++++++++++++++++++++++++++++++++++++++++++ gen/cli.py | 5 +- gen/packet.py | 5 +- gen/proxies.py | 7 +- of10/prints.py | 2 +- ofp_sniffer.py | 14 ++- 7 files changed, 276 insertions(+), 16 deletions(-) create mode 100644 gen/Packet.py diff --git a/example_filter.json b/example_filter.json index 5e2b916..2518274 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,7 +2,7 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 10, 13 + 0, 2, 3, 5, 6, 10, 12, 13, 16, 17 ] }, "1.3": { diff --git a/gen/Packet.py b/gen/Packet.py new file mode 100644 index 0000000..c30c0fc --- /dev/null +++ b/gen/Packet.py @@ -0,0 +1,257 @@ +import of10.prints as prints +import gen.prints + + +class OFPHeader: + + def __init__(self): + self.version = 1 + self.oftype = None + self.lenght = None + self.xid = None + + def prints(self): + gen.prints.print_openflow_header(self) + + +class OFPT_HELLO: + + def __init__(self): + self.ofp_header = OFPHeader() + self.data = None + + def prints(self): + self.ofp_header.prints() + prints.print_of_hello(self.data) + + +class OFPT_ERROR: + + def __init__(self): + self.ofp_header = OFPHeader() + self.ertype = None + self.code = None + + def prints(self): + self.ofp_header.prints() + prints.print_of_error(self) + + +class OFPT_ECHO_REQ: + + def __init__(self): + self.ofp_header = OFPHeader() + self.data = None + + def prints(self): + prints.print_echoreq(self) + + +class OFPT_ECHO_RES: + + def __init__(self): + self.ofp_header = OFPHeader() + self.data = None + + def prints(self): + prints.print_echoreq(self) + + +class OFPT_VENDOR: + + def __init__(self): + self.ofp_header = OFPHeader() + self.vendor = None + self.data = None + + +class OFPT_FEATURE_REQ: + + def __init__(self): + self.ofp_header = OFPHeader() + + +class OFPT_FEATURE_RES: + + def __init__(self): + self.ofp_header = OFPHeader() + self.datapath_id = None + self.n_buffers = None + self.n_tbls = None + self.pad = [] # 0-3 Bytes + self.capabilities = None + self.actions = None + self.ports = [] # class ofp_phy_port + + +class OFPT_GET_CONFIG_REQ: + + def __init__(self): + self.ofp_header = OFPHeader() + + +class OFPT_GET_CONFIG_RES: + + def __init__(self): + self.ofp_header = OFPHeader() + self.flags = None + self.miss_send_len = None + + +class OFPT_SET_CONFIG: + + def __init__(self): + self.ofp_header = OFPHeader() + self.flags = None + self.miss_send_len = None + + +class OFPT_PACKET_OUT: + + def __init__(self): + self.ofp_header = OFPHeader() + self.buffer_id = None + self.in_port = None + self.actions_len = None + self.data = None + + +class OFPF_FLOW_REMOVED: + + def __init__(self): + self.ofp_header = OFPHeader() + self.match = None + self.cookie = None + self.priority = None + self.reason = None + self.pad = [] # 0 - 1 Bytes + self.duration_sec = None + self.duration_nsec = None + self.idle_timeout = None + self.pad2 = [] # 0 - 2 Bytes + self.packet_count = None + self.byte_count = None + + +class OFPT_PORT_STATUS: + + def __init__(self): + self.ofp_header = OFPHeader() + self.reason = None + self.pad = [] # 0 - 7 Bytes + self.desc = None # Class ofp_phy_port + + +class OFPT_PACKET_IN: + + def __init__(self): + self.ofp_header = OFPHeader() + self.buffer_id = None + self.total_len = None + self.in_port = None + self.reason = None + self.pad = None + self.data = None + + +class OFPT_FLOW_MOD: + + def __init__(self): + self.ofp_header = OFPHeader() + self.match = ofp_match() + self.cookie = None + self.command = None + self.idle_timeout = None + self.hard_timeout = None + self.priority = None + self.buffer_id = None + self.out_port = None + self.flags = None + self.actions = [] # Class ofp_action_header + + +class OFPT_PORT_MOD: + + def __init__(self): + self.ofp_header = OFPHeader() + self.port_no = None + self.hw_addr = None + self.config = None + self.mask = None + self.advertise = None + self.pad = None + + +class OFPT_STATS_REQ: + + def __init__(self): + self.ofp_header = OFPHeader() + + +class OFPT_STATS_RES: + + def __init__(self): + self.ofp_header = OFPHeader() + + +class OFPT_BARRIER_REQ: + + def __init__(self): + self.ofp_header = OFPHeader() + + +class OFPT_BARRIER_RES: + + def __init__(self): + self.ofp_header = OFPHeader() + + +class OFPT_QUEUE_GET_CONFIG_REQ: + + def __init__(self): + self.ofp_header = OFPHeader() + self.port = None + self.pad = [] # 0 - 2 Bytes + + +class OFPT_QUEUE_GET_CONFIG_RES: + + def __init__(self): + self.ofp_header = OFPHeader() + self.port = None + self.pad = [] # 0 - 6 Bytes + self.queues = [] # Class ofp_packet_queue + + +# Auxiliary Data Structures +class ofp_phy_port: + + def __init__(self): + self.port_id = None + self.hw_addr = None + self.config = None + self.state = None + self.curr = None + self.advertised = None + self.supported = None + self.peer = None + + +class ofp_match: + + def __init__(self): + self.wildcards = None + self.in_port = None + self.dl_src = None + self.dl_dst = None + self.dl_vlan = None + self.dl_vlan_pcp = None + self.pad1 = [] # 0 - 1 Bytes + self.dl_type = None + self.nw_tos = None + self.nw_proto = None + self.pad2 = [] # 0 - 2 Bytes + self.nw_src = None + self.nw_dst = None + self.tp_src = None + self.tp_dst = None diff --git a/gen/cli.py b/gen/cli.py index 050b4fa..d982ac9 100644 --- a/gen/cli.py +++ b/gen/cli.py @@ -53,8 +53,9 @@ def start_capture(capfile, infilter, dev): print "Sniffing device %s" % dev cap = pcapy.open_live(dev, 65536, 1, 0) - main_filter = " port 6633 " - cap.setfilter(main_filter + infilter) + if len(infilter) is 0: + infilter = " port 6633 " + cap.setfilter(infilter) return cap except Exception as exception: diff --git a/gen/packet.py b/gen/packet.py index 254c96f..3f740af 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -27,6 +27,8 @@ def __init__(self, pkt): self.offset = 0 self.print_options = self.main_packet.print_options self.sanitizer = self.main_packet.sanitizer + # + self.message = None def seq_of_print(self, function): self.printing_seq.append(function) @@ -52,7 +54,8 @@ def process_openflow_body(self): # of10.prints.print_type_unknown(self) return 0 return 1 - except: + except Exception as e: + print e self.handle_malformed_pkts() return -1 if self.of_h['version'] is 4: diff --git a/gen/proxies.py b/gen/proxies.py index 405db91..064a26a 100644 --- a/gen/proxies.py +++ b/gen/proxies.py @@ -9,13 +9,14 @@ def support_fsfw(pkt, lldp): - global NET ip = pkt.main_packet.l3['d_addr'] port = pkt.main_packet.l4['dest_port'] - dpid = lldp['c_id'].split(':')[1] - + try: + dpid = lldp['c_id'].split(':')[1] + except: + dpid = lldp['c_id'] name = get_name_dpid(dpid) NET[ip, port] = name return diff --git a/of10/prints.py b/of10/prints.py index ab61867..d58e5de 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -32,7 +32,7 @@ def print_layer2_pktIn(pkt): def print_tcp(pkt): - gen.prints.print_tcp(pkt.l4) + gen.prints.print_tcp(pkt.of_body['print_tcp']) def print_layer3(pkt): diff --git a/ofp_sniffer.py b/ofp_sniffer.py index d062a08..931e608 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -45,17 +45,15 @@ def main(argv): ''' This is the main function ''' - try: - cap.loop(-1, process_packet) + cap.loop(-1, process_packet) + return +if __name__ == "__main__": + cap, print_options, sanitizer = gen.cli.get_params(sys.argv) + try: + main(sys.argv) except KeyboardInterrupt: print 'Exiting...' sys.exit(0) except Exception as exception: print exception - return - - -if __name__ == "__main__": - cap, print_options, sanitizer = gen.cli.get_params(sys.argv) - main(sys.argv) From dd7507929e498abb048b1adf1cc51bcc459b4447 Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Tue, 5 Apr 2016 18:18:10 -0400 Subject: [PATCH 17/88] Rename Packet.py to packet2.py --- gen/{Packet.py => packet2.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename gen/{Packet.py => packet2.py} (100%) diff --git a/gen/Packet.py b/gen/packet2.py similarity index 100% rename from gen/Packet.py rename to gen/packet2.py From ddcfe62612547ccf311d388631b5de5923de6224 Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Wed, 6 Apr 2016 13:44:59 -0400 Subject: [PATCH 18/88] New core for packet capture. Not fully implemented yet. --- TODO | 13 + gen/packet.py | 87 +++-- gen/packet2.py | 257 --------------- gen/prints.py | 18 +- of10/packet.py | 432 +++++++++++++++++++++++++ of10/parser.py | 854 +++++++++++++++++++++++-------------------------- of10/prints.py | 199 ++++++------ ofp_sniffer.py | 23 +- 8 files changed, 1014 insertions(+), 869 deletions(-) create mode 100644 TODO delete mode 100644 gen/packet2.py create mode 100644 of10/packet.py diff --git a/TODO b/TODO new file mode 100644 index 0000000..1a2abac --- /dev/null +++ b/TODO @@ -0,0 +1,13 @@ +TODO: + +Print data from Hello, EchoReq, EchoRes +Handle Vendor +Handle Pads + +packetIn - data +how to handle data? + +packetOut - data +how to handle data? + + diff --git a/gen/packet.py b/gen/packet.py index 3f740af..8e50357 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -1,12 +1,14 @@ from gen.tcpip import get_ethernet_frame, get_ip_packet, get_tcp_stream, \ get_openflow_header -from of10.parser import process_ofp_type -from of13.parser import process_ofp_type13 +# from of13.parser import process_ofp_type13 import gen.prints import of10.prints import gen.filters import of13.prints +# new approach +import of10.packet + IP_PROTOCOL = 8 TCP_PROTOCOL = 6 @@ -15,9 +17,9 @@ class OFMessage: - ''' + """ Used to all all data regarding an OpenFlow message - ''' + """ def __init__(self, pkt): self.main_packet = pkt self.packet = pkt.this_packet @@ -29,14 +31,34 @@ def __init__(self, pkt): self.sanitizer = self.main_packet.sanitizer # self.message = None + # new approad + self.ofp = None def seq_of_print(self, function): self.printing_seq.append(function) def process_openflow_header(self): + # remove line below self.of_h = get_openflow_header(self.packet, self.offset) + # keep line below + of_header = get_openflow_header(self.packet, self.offset) + # instantiate packet + if of_header['version'] is 1: + self.ofp = of10.packet.instantiate(self, of_header) + # If type is not recognized, return 0 + if type(self.ofp) is type(int()): + print 'Debug: Type not recognized' + self.offset += 8 + self.packet = self.packet[8:] + return 0 + # elif self.of_h is 4: + # of13.packet.instantiate_class(self) + else: + return 0 + self.offset += 8 self.packet = self.packet[8:] + return 1 def handle_malformed_pkts(self): string = ('!!! MalFormed Packet - Packet Len: %s Informed: %s ' @@ -47,26 +69,26 @@ def handle_malformed_pkts(self): self.prepare_printing('print_string', message) def process_openflow_body(self): - self.process_openflow_header() - if self.of_h['version'] is 1: + if not self.process_openflow_header(): + return 0 + # are those options needed? + if self.ofp.version is 1: try: - if not process_ofp_type(self): - # of10.prints.print_type_unknown(self) - return 0 + self.ofp.process_msg(self.packet) return 1 except Exception as e: print e self.handle_malformed_pkts() return -1 - if self.of_h['version'] is 4: - try: - if not process_ofp_type13(self): - # of10.prints.print_type_unknown(self) - return 0 - return 1 - except: - self.handle_malformed_pkts() - return -1 + # if self.ofp.version is 4: + # try: + # if not process_ofp_type13(self): + # # of10.prints.print_type_unknown(self) + # return 0 + # return 1 + # except: + # self.handle_malformed_pkts() + # return -1 return 0 def prepare_printing(self, string, values): @@ -78,18 +100,19 @@ def print_packet(self, pkt): if pkt.printed_header is False: gen.prints.print_headers(pkt) pkt.printed_header = True - gen.prints.print_openflow_header(self.of_h) - if self.of_h['version'] is 1: - of10.prints.print_body(self) - elif self.of_h['version'] is 4: - of13.prints.print_body(self) + gen.prints.print_openflow_header(self.ofp) + # if self.of_h['version'] is 1: + # of10.prints.print_body(self) + self.ofp.prints() + #elif self.of_h['version'] is 4: + # of13.prints.print_body(self) print class Packet: - ''' + """ Used to save all data about the packet - ''' + """ def __init__(self, packet, print_options, sanitizer, ctr): # Raw packet self.packet = packet @@ -162,7 +185,7 @@ def of_body(self): def process_openflow_messages(self): self.remaining_bytes = self.get_remaining_bytes() - while (self.remaining_bytes >= 8): + while self.remaining_bytes >= 8: # self.this_packet is the OpenFlow message # let's remove the current OpenFlow message from the packet length = self.get_of_message_length() @@ -173,7 +196,9 @@ def process_openflow_messages(self): # Instantiate the OpenFlow message in the ofmsgs array # Process the content, using cur_msg position of the array of msgs self.ofmsgs.insert(self.cur_msg, OFMessage(self)) + version = self.ofmsgs[self.cur_msg].process_openflow_body() + if version is 0: return 0 elif version is -1: @@ -181,13 +206,15 @@ def process_openflow_messages(self): self.remaining_bytes -= length self.offset += length # If there is another OpenFlow message, instantiate another OFMsg - if (self.remaining_bytes >= 8): + if self.remaining_bytes >= 8: self.cur_msg += 1 self.qtd_of_msg += 1 return 1 def print_packet(self): - if not gen.filters.filter_OF_version(self): - for msg in self.ofmsgs: - msg.print_packet(self) + # fix it + #if not gen.filters.filter_OF_version(self): + + for msg in self.ofmsgs: + msg.print_packet(self) diff --git a/gen/packet2.py b/gen/packet2.py deleted file mode 100644 index c30c0fc..0000000 --- a/gen/packet2.py +++ /dev/null @@ -1,257 +0,0 @@ -import of10.prints as prints -import gen.prints - - -class OFPHeader: - - def __init__(self): - self.version = 1 - self.oftype = None - self.lenght = None - self.xid = None - - def prints(self): - gen.prints.print_openflow_header(self) - - -class OFPT_HELLO: - - def __init__(self): - self.ofp_header = OFPHeader() - self.data = None - - def prints(self): - self.ofp_header.prints() - prints.print_of_hello(self.data) - - -class OFPT_ERROR: - - def __init__(self): - self.ofp_header = OFPHeader() - self.ertype = None - self.code = None - - def prints(self): - self.ofp_header.prints() - prints.print_of_error(self) - - -class OFPT_ECHO_REQ: - - def __init__(self): - self.ofp_header = OFPHeader() - self.data = None - - def prints(self): - prints.print_echoreq(self) - - -class OFPT_ECHO_RES: - - def __init__(self): - self.ofp_header = OFPHeader() - self.data = None - - def prints(self): - prints.print_echoreq(self) - - -class OFPT_VENDOR: - - def __init__(self): - self.ofp_header = OFPHeader() - self.vendor = None - self.data = None - - -class OFPT_FEATURE_REQ: - - def __init__(self): - self.ofp_header = OFPHeader() - - -class OFPT_FEATURE_RES: - - def __init__(self): - self.ofp_header = OFPHeader() - self.datapath_id = None - self.n_buffers = None - self.n_tbls = None - self.pad = [] # 0-3 Bytes - self.capabilities = None - self.actions = None - self.ports = [] # class ofp_phy_port - - -class OFPT_GET_CONFIG_REQ: - - def __init__(self): - self.ofp_header = OFPHeader() - - -class OFPT_GET_CONFIG_RES: - - def __init__(self): - self.ofp_header = OFPHeader() - self.flags = None - self.miss_send_len = None - - -class OFPT_SET_CONFIG: - - def __init__(self): - self.ofp_header = OFPHeader() - self.flags = None - self.miss_send_len = None - - -class OFPT_PACKET_OUT: - - def __init__(self): - self.ofp_header = OFPHeader() - self.buffer_id = None - self.in_port = None - self.actions_len = None - self.data = None - - -class OFPF_FLOW_REMOVED: - - def __init__(self): - self.ofp_header = OFPHeader() - self.match = None - self.cookie = None - self.priority = None - self.reason = None - self.pad = [] # 0 - 1 Bytes - self.duration_sec = None - self.duration_nsec = None - self.idle_timeout = None - self.pad2 = [] # 0 - 2 Bytes - self.packet_count = None - self.byte_count = None - - -class OFPT_PORT_STATUS: - - def __init__(self): - self.ofp_header = OFPHeader() - self.reason = None - self.pad = [] # 0 - 7 Bytes - self.desc = None # Class ofp_phy_port - - -class OFPT_PACKET_IN: - - def __init__(self): - self.ofp_header = OFPHeader() - self.buffer_id = None - self.total_len = None - self.in_port = None - self.reason = None - self.pad = None - self.data = None - - -class OFPT_FLOW_MOD: - - def __init__(self): - self.ofp_header = OFPHeader() - self.match = ofp_match() - self.cookie = None - self.command = None - self.idle_timeout = None - self.hard_timeout = None - self.priority = None - self.buffer_id = None - self.out_port = None - self.flags = None - self.actions = [] # Class ofp_action_header - - -class OFPT_PORT_MOD: - - def __init__(self): - self.ofp_header = OFPHeader() - self.port_no = None - self.hw_addr = None - self.config = None - self.mask = None - self.advertise = None - self.pad = None - - -class OFPT_STATS_REQ: - - def __init__(self): - self.ofp_header = OFPHeader() - - -class OFPT_STATS_RES: - - def __init__(self): - self.ofp_header = OFPHeader() - - -class OFPT_BARRIER_REQ: - - def __init__(self): - self.ofp_header = OFPHeader() - - -class OFPT_BARRIER_RES: - - def __init__(self): - self.ofp_header = OFPHeader() - - -class OFPT_QUEUE_GET_CONFIG_REQ: - - def __init__(self): - self.ofp_header = OFPHeader() - self.port = None - self.pad = [] # 0 - 2 Bytes - - -class OFPT_QUEUE_GET_CONFIG_RES: - - def __init__(self): - self.ofp_header = OFPHeader() - self.port = None - self.pad = [] # 0 - 6 Bytes - self.queues = [] # Class ofp_packet_queue - - -# Auxiliary Data Structures -class ofp_phy_port: - - def __init__(self): - self.port_id = None - self.hw_addr = None - self.config = None - self.state = None - self.curr = None - self.advertised = None - self.supported = None - self.peer = None - - -class ofp_match: - - def __init__(self): - self.wildcards = None - self.in_port = None - self.dl_src = None - self.dl_dst = None - self.dl_vlan = None - self.dl_vlan_pcp = None - self.pad1 = [] # 0 - 1 Bytes - self.dl_type = None - self.nw_tos = None - self.nw_proto = None - self.pad2 = [] # 0 - 2 Bytes - self.nw_src = None - self.nw_dst = None - self.tp_src = None - self.tp_dst = None diff --git a/gen/prints.py b/gen/prints.py index 135ffb3..ed2768f 100644 --- a/gen/prints.py +++ b/gen/prints.py @@ -135,20 +135,20 @@ def print_tcp(tcp): tcp['flag_rst'], tcp['flag_syn'], tcp['flag_fyn'])) -def print_openflow_header(of): - version = gen.tcpip.get_ofp_version(of['version']) - name_version = '%s(%s)' % (version, of['version']) +def print_openflow_header(ofp): + version = gen.tcpip.get_ofp_version(ofp.version) + name_version = '%s(%s)' % (version, ofp.version) if version == '1.0': - name = of10.dissector.get_ofp_type(of['type']) - name_type = '%s(%s)' % (name, of['type']) + name = of10.dissector.get_ofp_type(ofp.type) + name_type = '%s(%s)' % (name, ofp.type) elif version == '1.3': - name = of13.dissector.get_ofp_type(of['type']) - name_type = '%s(%s)' % (name, of['type']) + name = of13.dissector.get_ofp_type(ofp.type) + name_type = '%s(%s)' % (name, ofp.type) else: - name_type = '%s' % (of['type']) + name_type = '%s' % (ofp.type) print ('OpenFlow Version: %s Type: %s Length: %s XID: %s' % - (name_version, yellow(name_type), of['length'], red(of['xid']))) + (name_version, yellow(name_type), ofp.length, red(ofp.xid))) def print_lldp(pkt): diff --git a/of10/packet.py b/of10/packet.py new file mode 100644 index 0000000..cca262f --- /dev/null +++ b/of10/packet.py @@ -0,0 +1,432 @@ +import prints as prints +import parser as parser + + +def instantiate(pkt, of_header): + if of_header['type'] == 0: + return OFPT_HELLO(of_header) + elif of_header['type'] == 1: + return OFPT_ERROR(of_header) + elif of_header['type'] == 2: + return OFPT_ECHO_REQ(of_header) + elif of_header['type'] == 3: + return OFPT_ECHO_RES(of_header) + elif of_header['type'] == 4: + return OFPT_VENDOR(of_header) + elif of_header['type'] == 5: + return OFPT_FEATURE_REQ(of_header) + elif of_header['type'] == 6: + return OFPT_FEATURE_RES(of_header) + elif of_header['type'] == 7: + return OFPT_GET_CONFIG_REQ(of_header) + elif of_header['type'] == 8: + return OFPT_GET_CONFIG_RES(of_header) + elif of_header['type'] == 9: + return OFPT_SET_CONFIG(of_header) + elif of_header['type'] == 10: + return OFPT_PACKET_IN(of_header) + elif of_header['type'] == 11: + return OFPF_FLOW_REMOVED(of_header) + elif of_header['type'] == 12: + return OFPT_PORT_STATUS(of_header) + elif of_header['type'] == 13: + return OFPT_PACKET_OUT(of_header) + elif of_header['type'] == 14: + return OFPT_FLOW_MOD(of_header) + elif of_header['type'] == 15: + return OFPT_PORT_MOD(of_header) + elif of_header['type'] == 16: + return OFPT_STATS_REQ(of_header) + elif of_header['type'] == 17: + return OFPT_STATS_RES(of_header) + elif of_header['type'] == 18: + return OFPT_BARRIER_REQ(of_header) + elif of_header['type'] == 19: + return OFPT_BARRIER_RES(of_header) + elif of_header['type'] == 20: + return OFPT_QUEUE_GET_CONFIG_REQ(of_header) + elif of_header['type'] == 21: + return OFPT_QUEUE_GET_CONFIG_RES(of_header) + else: + return 0 + + +class OFPHeader: + + def __init__(self, of_header): + self.version = 1 + self.type = of_header['type'] + self.length = of_header['length'] + self.xid = of_header['xid'] + + +class OFPT_HELLO(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.data = None + + def process_msg(self, packet): + parser.parse_Hello(self, packet) + + def prints(self): + prints.print_of_hello(self) + + +class OFPT_ERROR(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.type = None + self.code = None + + def process_msg(self, packet): + parser.parse_Error(self, packet) + + def prints(self): + prints.print_of_error(self) + + +class OFPT_ECHO_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.data = None + + def process_msg(self, packet): + parser.parse_EchoReq(self, packet) + + def prints(self): + prints.print_of_echoreq(self) + + +class OFPT_ECHO_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.data = None + + def process_msg(self, packet): + parser.parse_EchoRes(self, packet) + + def prints(self): + prints.print_of_echores(self) + + +class OFPT_VENDOR(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.vendor = None + self.data = None + + def process_msg(self, packet): + parser.parse_Vendor(self, packet) + + def prints(self): + prints.print_of_echores(self) + + +class OFPT_FEATURE_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + + def process_msg(self, packet): + parser.parse_FeatureReq(self, packet) + + def prints(self): + prints.print_of_feature_req(self) + + +class OFPT_FEATURE_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.datapath_id = None + self.n_buffers = None + self.n_tbls = None + self.pad = [] # 0-3 Bytes + self.capabilities = [] + self.actions = [] + self.ports = [] # array of class ofp_phy_port + + def process_msg(self, packet): + parser.parse_FeatureRes(self, packet) + + def prints(self): + prints.print_of_feature_res(self) + + +class OFPT_GET_CONFIG_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + + def process_msg(self, packet): + parser.parse_GetConfigReq(self, packet) + + def prints(self): + prints.print_of_getconfig_req(self) + + +class OFPT_GET_CONFIG_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.flags = None + self.miss_send_len = None + + def process_msg(self, packet): + parser.parse_GetConfigRes(self, packet) + + def prints(self): + prints.print_of_getconfig_req(self) + + +class OFPT_SET_CONFIG(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.flags = None + self.miss_send_len = None + + def process_msg(self, packet): + parser.parse_SetConfig(self, packet) + + def prints(self): + prints.print_ofp_setConfig(self) + + +class OFPT_PACKET_IN(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.buffer_id = None + self.total_len = None + self.in_port = None + self.reason = None + self.pad = None + self.data = None + + def process_msg(self, packet): + parser.parse_PacketIn(self, packet) + + def prints(self): + prints.print_of_packetIn(self) + + +class OFPF_FLOW_REMOVED(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.match = OFP_Match() + self.cookie = None + self.priority = None + self.reason = None + self.pad = None + self.duration_sec = None + self.duration_nsec = None + self.idle_timeout = None + self.pad2 = None + self.pad3 = None + self.packet_count = None + self.byte_count = None + + def process_msg(self, packet): + parser.parse_FlowRemoved(self, packet) + + def prints(self): + prints.print_ofp_flow_removed(self) + + +class OFPT_PORT_STATUS(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.reason = None + self.pad = [] # 0 - 7 Bytes + self.desc = OFP_Phy_port() + + def process_msg(self, packet): + parser.parse_PortStatus(self, packet) + + def prints(self): + prints.print_portStatus(self) + + +class OFPT_PACKET_OUT(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.buffer_id = None + self.in_port = None + self.actions_len = None + self.actions = [] + self.data = None + + def process_msg(self, packet): + parser.parse_PacketOut(self, packet) + + def prints(self): + prints.print_of_packetOut(self) + + +class OFPT_FLOW_MOD(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.match = OFP_Match() + self.cookie = None + self.command = None + self.idle_timeout = None + self.hard_timeout = None + self.priority = None + self.buffer_id = None + self.out_port = None + self.flags = None + self.actions = [] # Class ofp_action_header + + def process_msg(self, packet): + parser.parse_FlowMod(self, packet) + + def prints(self): + prints.print_of_FlowMod(self) + + +class OFPT_PORT_MOD(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.port_no = None + self.hw_addr = None + self.config = None + self.mask = None + self.advertise = None + self.pad = None + + def process_msg(self, packet): + parser.parse_PortMod(self, packet) + + def prints(self): + prints.print_of_PortMod(self) + + +class OFPT_STATS_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + + def process_msg(self, packet): + parser.parse_StatsReq(self, packet) + + def prints(self): + pass + + +class OFPT_STATS_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + + def process_msg(self, packet): + parser.parse_StatsRes(self, packet) + + def prints(self): + pass + + +class OFPT_BARRIER_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + + def process_msg(self, packet): + parser.parse_BarrierReq(self, packet) + + def prints(self): + pass + + +class OFPT_BARRIER_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + + def process_msg(self, packet): + parser.parse_BarrierReq(self, packet) + + def prints(self): + pass + + +class OFPT_QUEUE_GET_CONFIG_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.port = None + self.pad = [] # 0 - 2 Bytes + + def process_msg(self, packet): + parser.parse_QueueGetConfigReq(self, packet) + + def prints(self): + pass + + +class OFPT_QUEUE_GET_CONFIG_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.port = None + self.pad = [] # 0 - 6 Bytes + self.queues = [] # Class ofp_packet_queue + + def process_msg(self, packet): + parser.parse_QueueGetConfigRes(self, packet) + + def prints(self): + pass + + +# Auxiliary Data Structures +class OFP_Phy_port: + + def __init__(self): + self.port_id = None + self.hw_addr = None + self.config = None + self.state = None + self.curr = None + self.advertised = None + self.supported = None + self.peer = None + + +class OFP_Match: + + def __init__(self): + self.wildcards = None + self.in_port = None + self.dl_src = None + self.dl_dst = None + self.dl_vlan = None + self.dl_vlan_pcp = None + self.pad1 = None + self.dl_type = None + self.nw_tos = None + self.nw_proto = None + self.pad2 = None + self.nw_src = None + self.nw_dst = None + self.tp_src = None + self.tp_dst = None + + +class OFP_Action: + + def __init__(self): + self.type = None + self.length = None + self.payload = None + diff --git a/of10/parser.py b/of10/parser.py index 41d7f4c..ee525f0 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -1,6 +1,6 @@ -''' +""" Parser for OpenFlow 1.0 -''' +""" from struct import unpack import of10.dissector @@ -10,104 +10,43 @@ import gen.tcpip import of10.vendors import gen.proxies - - -def process_ofp_type(pkt): - if pkt.of_h['type'] == 0: - result = parse_Hello(pkt) - elif pkt.of_h['type'] == 1: - result = parse_Error(pkt) - elif pkt.of_h['type'] == 2: - result = parse_EchoReq(pkt) - elif pkt.of_h['type'] == 3: - result = parse_EchoRes(pkt) - elif pkt.of_h['type'] == 4: - result = parse_Vendor(pkt) - elif pkt.of_h['type'] == 5: - result = parse_FeatureReq(pkt) - elif pkt.of_h['type'] == 6: - result = parse_FeatureRes(pkt) - elif pkt.of_h['type'] == 7: - result = parse_GetConfigReq(pkt) - elif pkt.of_h['type'] == 8: - result = parse_GetConfigRes(pkt) - elif pkt.of_h['type'] == 9: - result = parse_SetConfig(pkt) - elif pkt.of_h['type'] == 10: - result = parse_PacketIn(pkt) - elif pkt.of_h['type'] == 11: - result = parse_FlowRemoved(pkt) - elif pkt.of_h['type'] == 12: - result = parse_PortStatus(pkt) - elif pkt.of_h['type'] == 13: - result = parse_PacketOut(pkt) - elif pkt.of_h['type'] == 14: - result = parse_FlowMod(pkt) - elif pkt.of_h['type'] == 15: - result = parse_PortMod(pkt) - elif pkt.of_h['type'] == 16: - result = parse_StatsReq(pkt) - elif pkt.of_h['type'] == 17: - result = parse_StatsRes(pkt) - elif pkt.of_h['type'] == 18: - result = parse_BarrierReq(pkt) - elif pkt.of_h['type'] == 19: - result = parse_BarrierRes(pkt) - elif pkt.of_h['type'] == 20: - result = parse_QueueGetConfigReq(pkt) - elif pkt.of_h['type'] == 21: - result = parse_QueueGetConfigRes(pkt) - else: - return 0 - return result - +from of10.packet import OFP_Phy_port +from of10.packet import OFP_Action # *************** Hello ***************** -def parse_Hello(pkt): - pkt.prepare_printing('print_of_hello', None) - return 1 +def parse_Hello(msg, packet): + msg.data = packet # ************** Error ***************** -def parse_Error(pkt): - of_error = pkt.packet[0:4] +def parse_Error(msg, packet): + of_error = packet[0:4] ofe = unpack('!HH', of_error) - - error = {'type': ofe[0], 'code': ofe[1]} - pkt.prepare_printing('print_of_error', error) - return 1 + msg.type = ofe[0] + msg.code = ofe[1] # ************ EchoReq ***************** -def parse_EchoReq(pkt): - pkt.prepare_printing('print_echoreq', None) - return 1 +def parse_EchoReq(msg, packet): + msg.data = packet # ************ EchoRes ***************** -def parse_EchoRes(pkt): - pkt.prepare_printing('print_echores', None) - return 1 +def parse_EchoRes(msg, packet): + msg.data = packet # ************ Vendor ****************** -def parse_Vendor(pkt): - of_vendor = pkt.packet[0:4] +def parse_Vendor(msg, packet): + of_vendor = packet[0:4] ofv = unpack('!L', of_vendor) - pkt.prepare_printing('print_of_vendor', ofv[0]) - - # Future - version 0.4 - # If code 8992 = NICIRA - # if ofv[0] == 8992: - # of10.vendors.parse_nicira(packet, h_size+4, of_xid) - - return 1 + msg.vendor = ofv[0] + msg.data = packet[4:] # *********** FeatureReq *************** -def parse_FeatureReq(pkt): - pkt.prepare_printing('print_of_feature_req', None) - return 1 +def parse_FeatureReq(msg, packet): + pass # *********** FeatureRes *************** @@ -158,49 +97,43 @@ def _parse_phy_ports(packet): supported = _parse_phy_curr(phy[7]) peer = _parse_phy_curr(phy[8]) - phy_ports = {'port_id': port_id, - 'hw_addr': hw_addr, - 'name': phy[2], - 'config': config, - 'state': state, - 'curr': curr, - 'advertised': advertised, - 'supported': supported, - 'peer': peer} - return phy_ports - - -def parse_FeatureRes(pkt): - of_fres = pkt.packet[0:24] + port = OFP_Phy_port() + port.port_id = port_id + port.hw_addr = hw_addr + port.name = phy[2] + port.config = config + port.state = state + port.curr = curr + port.advertised = advertised + port.supported = supported + port.peer = peer + return port + + +def parse_FeatureRes(msg, packet): + of_fres = packet[0:24] ofrs = unpack('!8sLB3sLL', of_fres) - f_res = {'datapath_id': ofrs[0], 'n_buffers': ofrs[1], 'n_tbls': ofrs[2], - 'pad': ofrs[3]} - pkt.prepare_printing('print_of_feature_res', f_res) - - # 'capabilities': ofrs[4], 'actions': ofrs[5]} - caps = [] - caps = _parse_capabilities(ofrs[4]) - pkt.prepare_printing('print_of_feature_res_caps', caps) - - actions = [] - actions = _parse_actions(ofrs[5]) - pkt.prepare_printing('print_of_feature_res_actions', actions) + msg.datapath_id = ofrs[0] + msg.n_buffers = ofrs[1] + msg.n_tbls = ofrs[2] + msg.pad = ofrs[3] + msg.capabilities = _parse_capabilities(ofrs[4]) + msg.actions = _parse_actions(ofrs[5]) # Ports description? start = 24 ports_array = [] - while len(pkt.packet[start:]) > 0: - ports = _parse_phy_ports(pkt.packet[start:start+48]) - ports_array.append(ports) + while len(packet[start:]) > 0: + port = _parse_phy_ports(packet[start:start+48]) + ports_array.append(port) start = start + 48 - pkt.prepare_printing('print_of_ports', ports_array) + msg.ports = ports_array return 1 # ***************** GetConfigReq ********************* -def parse_GetConfigReq(pkt): - pkt.prepare_printing('print_of_getconfig_req', pkt) - return 1 +def parse_GetConfigReq(msg, packet): + pass # ***************** GetConfigRes ******************** @@ -208,21 +141,16 @@ def _parse_SetGetConfig(packet, h_size): pkt_raw = packet[h_size:h_size+4] pkt_list = unpack('!HH', pkt_raw) flag = of10.dissector.get_configres_flags(pkt_list[0]) - miss_send_len = pkt_list[1] - return {'flag': flag, 'miss_send_len': miss_send_len} + return flag, pkt_list[1] -def parse_GetConfigRes(pkt): - getConfig = _parse_SetGetConfig(pkt.packet, 0) - pkt.prepare_printing('print_ofp_getConfigRes', getConfig) - return 1 +def parse_GetConfigRes(msg, packet): + msg.flags, msg.miss_send_len = _parse_SetGetConfig(packet, 0) # ******************* SetConfig ********************** -def parse_SetConfig(pkt): - setConfig = _parse_SetGetConfig(pkt.packet, 0) - pkt.prepare_printing('print_ofp_setConfig', setConfig) - return 1 +def parse_SetConfig(msg, packet): + msg.flags, msg.miss_send_len = _parse_SetGetConfig(packet, 0) # ****************** PacketIn ************************ @@ -292,79 +220,77 @@ def process_data(pkt, start): return -def parse_PacketIn(pkt): +def parse_PacketIn(msg, packet): # buffer_id(32), total_len(16), in_port(16), reason(8), pad(8) - pkt_raw = pkt.packet[0:10] + pkt_raw = packet[0:10] p_in = unpack('!LHHBB', pkt_raw) reason = of10.dissector.get_packetIn_reason(p_in[3]) - packetIn = {'buffer_id': p_in[0], 'total_len': p_in[1], 'in_port': p_in[2], - 'reason': reason, 'pad': p_in[4]} - - pkt.prepare_printing('print_packetIn', packetIn) + msg.buffer_id = p_in[0] + msg.total_len = p_in[1] + msg.in_port = p_in[2] + msg.reason = reason + msg.pad = p_in[4] # process data - process_data(pkt, 10) - - return 1 + # how to handle data? + # process_data(pkt, 10) # ******************** FlowRemoved *************************** -def parse_FlowRemoved(pkt): - ofmatch = _parse_OFMatch(pkt.packet, 0) - pkt.prepare_printing('print_ofp_match', ofmatch) +def parse_FlowRemoved(msg, packet): + _parse_OFMatch(msg, packet, 0) - of_rem_body = pkt.packet[40:40+40] + of_rem_body = packet[40:40+40] ofrem = unpack('!QHBBLLHBBQQ', of_rem_body) cookie = ofrem[0] if ofrem[0] > 0 else 0 cookie = '0x' + format(cookie, '02x') reason = of10.dissector.get_flow_removed_reason(ofrem[2]) - ofrem = {'cookie': cookie, 'priority': ofrem[1], 'reason': reason, - 'pad': ofrem[3], 'duration_sec': ofrem[4], - 'duration_nsec': ofrem[5], 'idle_timeout': ofrem[6], - 'pad2': ofrem[7], 'pad3': ofrem[8], - 'packet_count': ofrem[9], 'byte_count': ofrem[10]} - - pkt.prepare_printing('print_ofp_flow_removed', ofrem) - return 1 + msg.cookie = cookie + msg.priority = ofrem[1] + msg.reason = reason + msg.pad = ofrem[3] + msg.duration_sec = ofrem[4] + msg.duration_nsec = ofrem[5] + msg.idle_timeout = ofrem[6] + msg.pad2 = ofrem[7] + msg.pad3 = ofrem[8] + msg.packet_count = ofrem[9] + msg.byte_count = ofrem[10] # ******************* PortStatus ***************************** -def parse_PortStatus(pkt): - port_raw = pkt.packet[0:8] +def parse_PortStatus(msg, packet): + port_raw = packet[0:8] port = unpack('!B7s', port_raw) reason = of10.dissector.get_portStatus_reason(port[0]) - p_status = {'reason': reason, 'pad': port[1]} - pkt.prepare_printing('print_portStatus', p_status) - - ports = _parse_phy_ports(pkt.packet[8:64]) - pkt.prepare_printing('print_of_ports', ports) - return 1 + msg.reason = reason + msg.pad = port[1] + msg.desc = _parse_phy_ports(packet[8:64]) # ******************* PacketOut ***************************** -def parse_PacketOut(pkt): +def parse_PacketOut(msg, packet): # buffer_id(32), in_port(16), actions_len(16) - pkt_raw = pkt.packet[0:8] + pkt_raw = packet[0:8] p_out = unpack('!LHH', pkt_raw) - packetOut = {'buffer_id': p_out[0], 'in_port': p_out[1], - 'actions_len': p_out[2]} + msg.buffer_id = p_out[0] + msg.in_port = p_out[1] + msg.actions_len = p_out[2] - pkt.prepare_printing('print_packetOut', packetOut) # Actions start = 8 - total = start+packetOut['actions_len'] - actions_dict = _parse_OFAction(pkt.packet[start:total], 0) - pkt.prepare_printing('print_actions', actions_dict) + total = start+msg.actions_len + msg.action = _parse_OFAction(packet[start:total], 0) - start = start + packetOut['actions_len'] + start = start + msg.actions_len # Check if we still have content in the PacketOut - if len(pkt.packet[start:]) == 0: + if len(packet[start:]) == 0: return 1 # process body - process_data(pkt, start) + # process_data(pkt, start) return 1 @@ -403,7 +329,7 @@ def get_ip_from_long(long_ip): return (socket.inet_ntoa(struct.pack('!L', long_ip))) -def _parse_OFMatch(packet, h_size): +def _parse_OFMatch(msg, packet, h_size): of_match = packet[h_size:h_size+40] ofm = unpack('!LH6s6sHBBHBBHLLHH', of_match) wildcard = ofm[0] @@ -420,22 +346,24 @@ def _parse_OFMatch(packet, h_size): 'tp_dst': ofm[14]} if wildcard >= ((1 << 22) - 1): - ofmatch = {'wildcards': 4194303} - return ofmatch + msg.match.wildcards = 4194303 + return elif wildcard == 0: - ofmatch = {'wildcards': 0} - return ofmatch + msg.match.wildcards = 0 + return else: src_netmask = process_src_subnet(wildcard) if src_netmask == 0: ofmatch.pop('nw_src') else: ofmatch['nw_src'] = str(ofmatch['nw_src']) + '/' + str(src_netmask) + dst_netmask = process_dst_subnet(wildcard) if dst_netmask == 0: ofmatch.pop('nw_dst') else: ofmatch['nw_dst'] = str(ofmatch['nw_dst']) + '/' + str(dst_netmask) + for i in range(0, 8): mask = 2**i aux = wildcard & mask @@ -448,22 +376,29 @@ def _parse_OFMatch(packet, h_size): if aux != 0: ofmatch.pop(_process_wildcard(mask)) - return ofmatch + # Convert from Dict(ofmatch) to Class ofp_match + # For each item on ofmatch, associate the value to the equivalent on + # class ofp_match. For example, if there is an ofmatch['in_port'] + # msg.match.inport = ofmatch['in_port']. Others will be None + for match in ofmatch: + exec ('msg.match.%s=%s') % (match, ofmatch.get(match)) -def _parse_OFBody(packet, h_size): +def _parse_OFBody(msg, packet, h_size): of_mod_body = packet[h_size+40:h_size+40+24] ofmod = unpack('!QHHHHLHH', of_mod_body) ofmod_cookie = ofmod[0] if ofmod[0] > 0 else 0 ofmod_cookie = '0x' + format(ofmod_cookie, '02x') ofmod_buffer_id = '0x' + format(ofmod[5], '02x') - ofbody = {'cookie': ofmod_cookie, 'command': ofmod[1], - 'idle_timeout': ofmod[2], 'hard_timeout': ofmod[3], - 'priority': ofmod[4], 'buffer_id': ofmod[5], - 'buffer_id': ofmod_buffer_id, 'out_port': ofmod[6], - 'flags': ofmod[7]} - return ofbody + msg.cookie = ofmod_cookie + msg.command = ofmod[1] + msg.idle_timeout = ofmod[2] + msg.hard_timeout = ofmod[3] + msg.priority = ofmod[4] + msg.buffer_id = ofmod_buffer_id + msg.out_port = ofmod[6] + msg.flags = ofmod[7] def get_action(action_type, length, payload): @@ -532,6 +467,7 @@ def _parse_OFAction(packet, start): action_header = 4 # Add all actions to a list for future printing actions_list = [] + action = OFP_Action() while (1): ofp_action = packet[start:start + action_header] if len(ofp_action) > 0: @@ -548,9 +484,10 @@ def _parse_OFAction(packet, start): total_length = 4 ofa_action_payload = packet[start:start + 4] - actions_dict = {'type': ofa_type, 'length': ofa_length, - 'payload': ofa_action_payload} - actions_list.append(actions_dict) + action.type = ofa_type + action.length = ofa_length + action.payload = ofa_action_payload + actions_list.append(action) # Next packet would start at.. start = start + total_length else: @@ -559,324 +496,319 @@ def _parse_OFAction(packet, start): return actions_list -def parse_FlowMod(pkt): - ofmatch = _parse_OFMatch(pkt.packet, 0) - pkt.prepare_printing("print_ofp_match", ofmatch) - - ofbody = _parse_OFBody(pkt.packet, 0) - pkt.prepare_printing("print_ofp_body", ofbody) - +def parse_FlowMod(msg, packet): + _parse_OFMatch(msg, packet, 0) + _parse_OFBody(msg, packet, 0) # Actions: Header = 4 , plus each possible action actions_start = 64 - actions_dict = _parse_OFAction(pkt.packet, actions_start) - pkt.prepare_printing('print_actions', actions_dict) - - return 1 + msg.actions = _parse_OFAction(packet, actions_start) # ********************* PortMod **************************** -def parse_PortMod(pkt): +def parse_PortMod(msg, packet): # port(16), hw_addr(48), config(32), mask(32), advertise(32), pad(32) - pmod_raw = pkt.packet[0:24] + pmod_raw = packet[0:24] pmod = unpack('!H6sLLLL', pmod_raw) config = _parse_phy_config(pmod[2]) mask = _parse_phy_config(pmod[3]) advertise = _parse_phy_curr(pmod[4]) - portMod = {'port': pmod[0], 'hw_addr': pmod[1], 'config': config, - 'mask': mask, 'advertise': advertise, 'pad': pmod[5]} - pkt.prepare_printing('print_PortMod', portMod) - return 1 + msg.port_no = pmod[0] + msg.hw_addr = pmod[1] + msg.config = config + msg.mask = mask + msg.advertise = advertise + msg.pad = pmod[5] # ******************** StatReq **************************** -def parse_StatsReq(pkt): +def parse_StatsReq(msg, packet): ''' Process the StatsReq ''' # Get type = 16bits # Get flags = 16bits - of_stat_req = pkt.packet[0:4] - ofstat = unpack('!HH', of_stat_req) - stat_type = ofstat[0] - # FLags were not defined yet. Ignoring. - # flags = ofstat[1] - start = 4 - - # 7 Types available - if stat_type == 0: - # Description - # No extra fields - pkt.prepare_printing('print_ofp_statReqDesc', stat_type) - - elif stat_type == 1 or stat_type == 2: - # Flow(1) or Aggregate(2) - # Fields: match(40), table_id(8), pad(8), out_port(16) - of_match = _parse_OFMatch(pkt.packet, start) - # 44 Bytes (40B from Match, 4 from header) - of_stat_req = pkt.packet[start+40:start+40+4] - ofstat = unpack('!BBH', of_stat_req) - table_id = ofstat[0] - pad = ofstat[1] - out_port = ofstat[2] - stats = {'type': stat_type, 'match': of_match, 'table_id': table_id, - 'pad': pad, 'out_port': out_port} - pkt.prepare_printing('print_ofp_statReqFlowAggregate', stats) - - elif stat_type == 3: - # Table - # No extra fields - pkt.prepare_printing('print_ofp_statReqTable', stat_type) - - elif stat_type == 4: - # Port - # Fields: port_number(16), pad(48) - of_stat_req = pkt.packet[start:start+8] - ofstat = unpack('!H6s', of_stat_req) - port_number = ofstat[0] - pad = ofstat[1] - stats = {'type': stat_type, 'port_number': port_number, 'pad': pad} - pkt.prepare_printing('print_ofp_statReqPort', stats) - - elif stat_type == 5: - # Queue - # Fields: port_number(16), pad(16), queue_id(32) - of_stat_req = pkt.packet[start:start+8] - ofstat = unpack('!HHL', of_stat_req) - port_number = ofstat[0] - pad = ofstat[1] - queue_id = ofstat[2] - stats = {'type': stat_type, 'port_number': port_number, 'pad': pad, - 'queue_id': queue_id} - pkt.prepare_printing('print_ofp_statReqQueue', stats) - - elif stat_type == 65535: - # Vendor - # Fields: vendor_id(32) + data - of_stat_req = pkt.packet[start:start+4] - ofstat = unpack('!L', of_stat_req) - vendor_id = ofstat[0] - stats = {'type': stat_type, 'vendor_id': vendor_id} - pkt.prepare_printing('print_ofp_statReqVendor', stats) - - else: - print 'StatReq: Unknown Type: %s' % stat_type - - return 1 + pass + # of_stat_req = pkt.packet[0:4] + # ofstat = unpack('!HH', of_stat_req) + # stat_type = ofstat[0] + # # FLags were not defined yet. Ignoring. + # # flags = ofstat[1] + # start = 4 + # + # # 7 Types available + # if stat_type == 0: + # # Description + # # No extra fields + # pkt.prepare_printing('print_ofp_statReqDesc', stat_type) + # + # elif stat_type == 1 or stat_type == 2: + # # Flow(1) or Aggregate(2) + # # Fields: match(40), table_id(8), pad(8), out_port(16) + # of_match = _parse_OFMatch(pkt.packet, start) + # # 44 Bytes (40B from Match, 4 from header) + # of_stat_req = pkt.packet[start+40:start+40+4] + # ofstat = unpack('!BBH', of_stat_req) + # table_id = ofstat[0] + # pad = ofstat[1] + # out_port = ofstat[2] + # stats = {'type': stat_type, 'match': of_match, 'table_id': table_id, + # 'pad': pad, 'out_port': out_port} + # pkt.prepare_printing('print_ofp_statReqFlowAggregate', stats) + # + # elif stat_type == 3: + # # Table + # # No extra fields + # pkt.prepare_printing('print_ofp_statReqTable', stat_type) + # + # elif stat_type == 4: + # # Port + # # Fields: port_number(16), pad(48) + # of_stat_req = pkt.packet[start:start+8] + # ofstat = unpack('!H6s', of_stat_req) + # port_number = ofstat[0] + # pad = ofstat[1] + # stats = {'type': stat_type, 'port_number': port_number, 'pad': pad} + # pkt.prepare_printing('print_ofp_statReqPort', stats) + # + # elif stat_type == 5: + # # Queue + # # Fields: port_number(16), pad(16), queue_id(32) + # of_stat_req = pkt.packet[start:start+8] + # ofstat = unpack('!HHL', of_stat_req) + # port_number = ofstat[0] + # pad = ofstat[1] + # queue_id = ofstat[2] + # stats = {'type': stat_type, 'port_number': port_number, 'pad': pad, + # 'queue_id': queue_id} + # pkt.prepare_printing('print_ofp_statReqQueue', stats) + # + # elif stat_type == 65535: + # # Vendor + # # Fields: vendor_id(32) + data + # of_stat_req = pkt.packet[start:start+4] + # ofstat = unpack('!L', of_stat_req) + # vendor_id = ofstat[0] + # stats = {'type': stat_type, 'vendor_id': vendor_id} + # pkt.prepare_printing('print_ofp_statReqVendor', stats) + # + # else: + # print 'StatReq: Unknown Type: %s' % stat_type + # + # return 1 # *********************** StatsRes **************************** -def parse_StatsRes(pkt): +def parse_StatsRes(msg, packet): + pass # Get type = 16bits # Get flags = 16bits - of_stat_req = pkt.packet[0:4] - ofstat = unpack('!HH', of_stat_req) - stat_type = ofstat[0] - # flags = ofstat[1] - start = 4 - - # 7 Types available - if stat_type == 0: - # Description - # Fields: mfr_desc(2048), hw_desc(2048), sw_desc(2048), serial_num(256), - # dp_desc(2048) - desc_raw = pkt.packet[start:start+1056] - desc = unpack('!256s256s256s32s256s', desc_raw) - stats = {'mfr_desc': desc[0], - 'hw_desc': desc[1], - 'sw_desc': desc[2], - 'serial_num': desc[3], - 'dp_desc': desc[4], - 'type': stat_type} - pkt.prepare_printing('print_ofp_statResDesc', stats) - - elif stat_type == 1: - # Flow(1) - # Fields: length(16), table_id(8), pad(8), match(40), duration_sec(32), - # duration_nsec(32), priority(16), idle_timeout(16), hard_timeout(16), - # pad(48), cookie(64), packet_count(64), byte_count(64), actions[] - count = len(pkt.packet[0:]) - 4 - flows = [] - while (count > 0): - flow_raw = pkt.packet[start:start+4] - flow = unpack('!HBB', flow_raw) - res_flow = {'length': flow[0], 'table_id': flow[1], 'pad': flow[2]} - of_match = _parse_OFMatch(pkt.packet, start+4) - - flow_raw = pkt.packet[start+44:start+44+44] - flow = unpack('!LLHHH6sQQQ', flow_raw) - res_flow.update({'duration_sec': flow[0], 'duration_nsec': flow[1], - 'priority': flow[2], 'idle_timeout': flow[3], - 'hard_timeout': flow[4], 'pad2': flow[5], - 'cookie': flow[6], 'packet_count': flow[7], - 'byte_count': flow[8]}) - stats = {'type': stat_type, 'match': of_match, 'res_flow': res_flow} - - # Process Actions[] - end = res_flow['length'] - (4 + 40 + 44) - actions = pkt.packet[start+88:start+88+end] - actions_dict = _parse_OFAction(actions, 0) - - stats = {'type': stat_type, 'match': of_match, - 'res_flow': res_flow, 'print_actions': actions_dict} - - flows.append(stats) - - count = count - int(res_flow['length']) - start = start + int(res_flow['length']) - - # important to have a sequencial list here because there are multiple - # flows. So, print_ofp_statResFlow will print a list of flows. - pkt.prepare_printing('print_ofp_statResFlowArray', flows) - - elif stat_type == 2: - # Aggregate(2) - # Fields: packet_count(64), byte_count(64), flow_count(32), pad(32) - flow_raw = pkt.packet[start:start+24] - flow = unpack('!QQLL', flow_raw) - res_flow = {'type': stat_type, 'packet_count': flow[0], - 'byte_count': flow[1], 'flow_count': flow[2], - 'pad': flow[3]} - pkt.prepare_printing('print_ofp_statResAggregate', res_flow) - - elif stat_type == 3: - # Table - # Fields: table_id(8), pad(24), name(256), wildcards(32), - # max_entries(32), active_count(32), lookup_count(64), - # matched_count(64) - flow_raw = pkt.packet[start:start+64] - flow = unpack('!B3s32sLLLQQ', flow_raw) - res_flow = {'type': stat_type, 'table_id': flow[0], 'pad': flow[1], - 'name': flow[2], 'wildcards': flow[3], - 'max_entries': flow[4], 'active_count': flow[5], - 'lookup_count': flow[6], 'matched_count': flow[7]} - pkt.prepare_printing('print_ofp_statResTable', res_flow) - - elif stat_type == 4: - # Port - # Fields: port_number(16), pad(48), rx_packets(64), tx_packets(64), - # rx_bytes(64), tx_bytes(64), rx_dropped(64), tx_dropped(64), - # rx_errors(64), tx_errors(64), rx_frame_err(64), rx_over_err(64), - # rx_crc_err(64), collisions(64) - count = len(pkt.packet[0:]) - 4 - ports = [] - while (count > 0): - flow_raw = pkt.packet[start:start+104] - flow = unpack('!H6sQQQQQQQQQQQQ', flow_raw) - port = {'type': stat_type, 'port_no': flow[0], 'pad': flow[1], - 'rx_packets': flow[2], 'tx_packets': flow[3], - 'rx_bytes': flow[4], 'tx_bytes': flow[5], - 'rx_dropped': flow[6], 'tx_dropped': flow[7], - 'rx_errors': flow[8], 'tx_errors': flow[9], - 'rx_frame_err': flow[10], 'rx_over_err': flow[11], - 'rx_crc_err': flow[12], 'collisions': flow[13]} - - ports.append(port) - - count = count - 104 - start = start + 104 - - pkt.prepare_printing('print_ofp_statResPortArray', ports) - - elif stat_type == 5: - # Queue - # Fields: length(16), pad(16), queue_id(32), tx_bytes(64), - # tx_packets(64), tx_errors(64) - count = len(pkt.packet[0:]) - 4 - queues = [] - while (count > 0): - flow_raw = pkt.packet[start:start+32] - flow = unpack('!HHLQQQ', flow_raw) - queue = {'length': flow[0], 'pad': flow[1], 'queue_id': flow[2], - 'tx_bytes': flow[3], 'tx_packets': flow[4], - 'tx_errors': flow[5], 'type': stat_type} - queues.append(queue) - count = count - 32 - start = start + 32 - - pkt.prepare_printing('print_ofp_statResQueueArray', queues) - - elif stat_type == 65535: - # Vendor - # Fields: vendor_id(32), data(?) - flow_raw = pkt.packet[start:start+4] - flow = unpack('!L', flow_raw) - vendor_flow = {'type': stat_type, 'vendor_id': flow[0]} - pkt.prepare_printing('print_ofp_statResVendor', vendor_flow) - - pkt.prepare_printing('print_ofp_statResVendorData', - pkt.packet[start+4:]) - # start = start + 4 - # data = [] - # count = len(packet[0:]) - - # import hexdump - # hexdump.hexdump(pkt.packet[start:]) - # print - # while (start < count): - # flow_raw = pkt.packet[start:start+1] - # flow = unpack('!B', flow_raw) - # data.append(str(flow[0])) - # start = start + 1 - # pkt.prepare_printing('print_ofp_statResVendorData', ''.join(data)) - - else: - print ('StatRes: Unknown Type: %s' % (stat_type)) - return 1 + # of_stat_req = pkt.packet[0:4] + # ofstat = unpack('!HH', of_stat_req) + # stat_type = ofstat[0] + # # flags = ofstat[1] + # start = 4 + # + # # 7 Types available + # if stat_type == 0: + # # Description + # # Fields: mfr_desc(2048), hw_desc(2048), sw_desc(2048), serial_num(256), + # # dp_desc(2048) + # desc_raw = pkt.packet[start:start+1056] + # desc = unpack('!256s256s256s32s256s', desc_raw) + # stats = {'mfr_desc': desc[0], + # 'hw_desc': desc[1], + # 'sw_desc': desc[2], + # 'serial_num': desc[3], + # 'dp_desc': desc[4], + # 'type': stat_type} + # pkt.prepare_printing('print_ofp_statResDesc', stats) + # + # elif stat_type == 1: + # # Flow(1) + # # Fields: length(16), table_id(8), pad(8), match(40), duration_sec(32), + # # duration_nsec(32), priority(16), idle_timeout(16), hard_timeout(16), + # # pad(48), cookie(64), packet_count(64), byte_count(64), actions[] + # count = len(pkt.packet[0:]) - 4 + # flows = [] + # while (count > 0): + # flow_raw = pkt.packet[start:start+4] + # flow = unpack('!HBB', flow_raw) + # res_flow = {'length': flow[0], 'table_id': flow[1], 'pad': flow[2]} + # of_match = _parse_OFMatch(pkt.packet, start+4) + # + # flow_raw = pkt.packet[start+44:start+44+44] + # flow = unpack('!LLHHH6sQQQ', flow_raw) + # res_flow.update({'duration_sec': flow[0], 'duration_nsec': flow[1], + # 'priority': flow[2], 'idle_timeout': flow[3], + # 'hard_timeout': flow[4], 'pad2': flow[5], + # 'cookie': flow[6], 'packet_count': flow[7], + # 'byte_count': flow[8]}) + # stats = {'type': stat_type, 'match': of_match, 'res_flow': res_flow} + # + # # Process Actions[] + # end = res_flow['length'] - (4 + 40 + 44) + # actions = pkt.packet[start+88:start+88+end] + # actions_dict = _parse_OFAction(actions, 0) + # + # stats = {'type': stat_type, 'match': of_match, + # 'res_flow': res_flow, 'print_actions': actions_dict} + # + # flows.append(stats) + # + # count = count - int(res_flow['length']) + # start = start + int(res_flow['length']) + # + # # important to have a sequencial list here because there are multiple + # # flows. So, print_ofp_statResFlow will print a list of flows. + # pkt.prepare_printing('print_ofp_statResFlowArray', flows) + # + # elif stat_type == 2: + # # Aggregate(2) + # # Fields: packet_count(64), byte_count(64), flow_count(32), pad(32) + # flow_raw = pkt.packet[start:start+24] + # flow = unpack('!QQLL', flow_raw) + # res_flow = {'type': stat_type, 'packet_count': flow[0], + # 'byte_count': flow[1], 'flow_count': flow[2], + # 'pad': flow[3]} + # pkt.prepare_printing('print_ofp_statResAggregate', res_flow) + # + # elif stat_type == 3: + # # Table + # # Fields: table_id(8), pad(24), name(256), wildcards(32), + # # max_entries(32), active_count(32), lookup_count(64), + # # matched_count(64) + # flow_raw = pkt.packet[start:start+64] + # flow = unpack('!B3s32sLLLQQ', flow_raw) + # res_flow = {'type': stat_type, 'table_id': flow[0], 'pad': flow[1], + # 'name': flow[2], 'wildcards': flow[3], + # 'max_entries': flow[4], 'active_count': flow[5], + # 'lookup_count': flow[6], 'matched_count': flow[7]} + # pkt.prepare_printing('print_ofp_statResTable', res_flow) + # + # elif stat_type == 4: + # # Port + # # Fields: port_number(16), pad(48), rx_packets(64), tx_packets(64), + # # rx_bytes(64), tx_bytes(64), rx_dropped(64), tx_dropped(64), + # # rx_errors(64), tx_errors(64), rx_frame_err(64), rx_over_err(64), + # # rx_crc_err(64), collisions(64) + # count = len(pkt.packet[0:]) - 4 + # ports = [] + # while (count > 0): + # flow_raw = pkt.packet[start:start+104] + # flow = unpack('!H6sQQQQQQQQQQQQ', flow_raw) + # port = {'type': stat_type, 'port_no': flow[0], 'pad': flow[1], + # 'rx_packets': flow[2], 'tx_packets': flow[3], + # 'rx_bytes': flow[4], 'tx_bytes': flow[5], + # 'rx_dropped': flow[6], 'tx_dropped': flow[7], + # 'rx_errors': flow[8], 'tx_errors': flow[9], + # 'rx_frame_err': flow[10], 'rx_over_err': flow[11], + # 'rx_crc_err': flow[12], 'collisions': flow[13]} + # + # ports.append(port) + # + # count = count - 104 + # start = start + 104 + # + # pkt.prepare_printing('print_ofp_statResPortArray', ports) + # + # elif stat_type == 5: + # # Queue + # # Fields: length(16), pad(16), queue_id(32), tx_bytes(64), + # # tx_packets(64), tx_errors(64) + # count = len(pkt.packet[0:]) - 4 + # queues = [] + # while (count > 0): + # flow_raw = pkt.packet[start:start+32] + # flow = unpack('!HHLQQQ', flow_raw) + # queue = {'length': flow[0], 'pad': flow[1], 'queue_id': flow[2], + # 'tx_bytes': flow[3], 'tx_packets': flow[4], + # 'tx_errors': flow[5], 'type': stat_type} + # queues.append(queue) + # count = count - 32 + # start = start + 32 + # + # pkt.prepare_printing('print_ofp_statResQueueArray', queues) + # + # elif stat_type == 65535: + # # Vendor + # # Fields: vendor_id(32), data(?) + # flow_raw = pkt.packet[start:start+4] + # flow = unpack('!L', flow_raw) + # vendor_flow = {'type': stat_type, 'vendor_id': flow[0]} + # pkt.prepare_printing('print_ofp_statResVendor', vendor_flow) + # + # pkt.prepare_printing('print_ofp_statResVendorData', + # pkt.packet[start+4:]) + # # start = start + 4 + # # data = [] + # # count = len(packet[0:]) + # + # # import hexdump + # # hexdump.hexdump(pkt.packet[start:]) + # # print + # # while (start < count): + # # flow_raw = pkt.packet[start:start+1] + # # flow = unpack('!B', flow_raw) + # # data.append(str(flow[0])) + # # start = start + 1 + # # pkt.prepare_printing('print_ofp_statResVendorData', ''.join(data)) + # + # else: + # print ('StatRes: Unknown Type: %s' % (stat_type)) + # return 1 # ********************** BarrierReq *********************** -def parse_BarrierReq(pkt): - pkt.prepare_printing('print_of_BarrierReq', None) - return 1 +def parse_BarrierReq(msg, packet): + pass # ********************** BarrierRes *********************** -def parse_BarrierRes(pkt): - pkt.prepare_printing('print_of_BarrierReply', None) - return 1 +def parse_BarrierRes(msg, packet): + pass # ******************* QueueGetConfigReq ******************* -def parse_QueueGetConfigReq(pkt): - queue_raw = pkt.packet[0:4] - queue = unpack('!HH', queue_raw) - queueConfReq = {'port': queue[0], 'pad': queue[1]} - pkt.prepare_printing('print_queueReq', queueConfReq) - return 1 +def parse_QueueGetConfigReq(msg, packet): + queue_raw = packet[0:4] + # queue = unpack('!HH', queue_raw) + # queueConfReq = {'port': queue[0], 'pad': queue[1]} + # pkt.prepare_printing('print_queueReq', queueConfReq) + # return 1 # ****************** QueueGetConfigRes ******************** -def parse_QueueGetConfigRes(pkt): - queue_raw = pkt.packet[0:8] +def parse_QueueGetConfigRes(msg, packet): + queue_raw = packet[0:8] queue = unpack('!H6s', queue_raw) queueConfRes = {'port': queue[0], 'pad': queue[1]} - pkt.prepare_printing('print_queueRes', queueConfRes) - - start = 8 - while (pkt.packet[start:] > 0): - # Queues - it could be multiple - # queue_id(32), length(16), pad(16) - queue_raw = pkt.packet[start:start+8] - queue = unpack('!LHH', queue_raw) - queues = {'queue_id': queue[0], 'length': queue[1], 'pad': queue[2]} - of10.prints.print_queues(queues) - - q_start = start + 8 - - # Look of properties - # property(16), length(16), pad(32), rate(16), pad(48) - properties = pkt.packet[q_start:q_start+queues['length']-8] - - while (len(properties[q_start:]) > 0): - prop_raw = pkt.packet[q_start:q_start+8] - prop = unpack('!HHLH6s', prop_raw) - properties = {'type': prop[0], 'length': prop[1], - 'pad': prop[2], 'rate': prop[3], 'pad2': prop[4]} - of10.prints.print_queueRes_properties(properties) - - start = start + queues['length'] - - return 1 + # pkt.prepare_printing('print_queueRes', queueConfRes) + # + # start = 8 + # while (pkt.packet[start:] > 0): + # # Queues - it could be multiple + # # queue_id(32), length(16), pad(16) + # queue_raw = pkt.packet[start:start+8] + # queue = unpack('!LHH', queue_raw) + # queues = {'queue_id': queue[0], 'length': queue[1], 'pad': queue[2]} + # of10.prints.print_queues(queues) + + # q_start = start + 8 + # + # # Look of properties + # # property(16), length(16), pad(32), rate(16), pad(48) + # properties = pkt.packet[q_start:q_start+queues['length']-8] + # + # while (len(properties[q_start:]) > 0): + # prop_raw = pkt.packet[q_start:q_start+8] + # prop = unpack('!HHLH6s', prop_raw) + # properties = {'type': prop[0], 'length': prop[1], + # 'pad': prop[2], 'rate': prop[3], 'pad2': prop[4]} + # of10.prints.print_queueRes_properties(properties) + # + # start = start + queues['length'] + # + # return 1 diff --git a/of10/prints.py b/of10/prints.py index d58e5de..02a1441 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -5,6 +5,7 @@ import of10.parser import gen.prints import gen.packet +import gen.tcpip def red(string): @@ -60,46 +61,37 @@ def print_type_unknown(pkt): print string % (pkt.of_h['type']) -def print_of_hello(pkt): +def print_of_hello(msg): print 'OpenFlow Hello' -def print_of_error(pkt): - error = pkt.of_body['print_of_error'] - nCode, tCode = of10.dissector.get_ofp_error(error['type'], error['code']) +def print_of_error(msg): + nCode, tCode = of10.dissector.get_ofp_error(msg.type, msg.code) print ('OpenFlow Error - Type: %s Code: %s' % (red(nCode), red(tCode))) -def print_of_feature_req(pkt): +def print_of_feature_req(msg): print 'OpenFlow Feature Request' -def print_of_getconfig_req(pkt): +def print_of_getconfig_req(msg): print 'OpenFlow GetConfig Request' -def print_of_feature_res(pkt): - f_res = pkt.of_body['print_of_feature_res'] +def print_of_feature_res(msg): print 'OpenFlow Feature Reply' - dpid = datapath_id(f_res['datapath_id']) + dpid = datapath_id(msg.datapath_id) print ('FeatureRes - datapath_id: %s n_buffers: %s n_tbls: %s, pad: %s' - % (green(dpid), f_res['n_buffers'], f_res['n_tbls'], f_res['pad'])) - - -def print_of_feature_res_caps(pkt): - caps = pkt.of_body['print_of_feature_res_caps'] + % (green(dpid), msg.n_buffers, msg.n_tbls, msg.pad)) print ('FeatureRes - Capabilities:'), - for i in caps: + for i in msg.capabilities: print of10.dissector.get_feature_res_capabilities(i), print - - -def print_of_feature_res_actions(pkt): - actions = pkt.of_body['print_of_feature_res_actions'] print ('FeatureRes - Actions:'), - for i in actions: + for i in msg.actions: print of10.dissector.get_feature_res_actions(i), print + print_of_ports(msg) def _dont_print_0(printed): @@ -108,12 +100,13 @@ def _dont_print_0(printed): return False -def print_port_field(port, field): - port_id = '%s' % green(port['port_id']) +def print_port_field(port_id, variable, name): + port_id = '%s' % green(port_id) printed = False - print ('Port_id: %s - %s curr:' % (port_id, field)), - for i in port[field]: + print ('Port_id: %s - %s curr:' % (port_id, name)), + a = [] + for i in variable: print of10.dissector.get_phy_feature(i), printed = True else: @@ -122,14 +115,14 @@ def print_port_field(port, field): def print_ofp_phy_port(port): - port_id = '%s' % green(port['port_id']) + port_id = '%s' % green(port.port_id) print ('Port_id: %s - hw_addr: %s name: %s' % ( - port_id, green(port['hw_addr']), green(port['name']))) + port_id, green(port.hw_addr), green(port.name))) print ('Port_id: %s - config:' % port_id), printed = False - for i in port['config']: + for i in port.config: print of10.dissector.get_phy_config(i), printed = True else: @@ -137,21 +130,21 @@ def print_ofp_phy_port(port): print print ('Port_id: %s - state:' % port_id), - for i in port['state']: + for i in port.state: print of10.dissector.get_phy_state(i), printed = True else: printed = _dont_print_0(printed) print - following_fields = ['curr', 'advertised', 'supported', 'peer'] + # fix it + print_port_field(port.id, port.curr, 'curr') + print_port_field(port.id, port.advertised, 'advertised') + print_port_field(port.id, port.supported, 'supported') + print_port_field(port.id, port.peer, 'peer') - for field in following_fields: - print_port_field(port, field) - -def print_of_ports(pkt): - ports = pkt.of_body['print_of_ports'] +def print_of_ports(ports): if type(ports) is not list: print_ofp_phy_port(ports) else: @@ -159,52 +152,50 @@ def print_of_ports(pkt): print_ofp_phy_port(port) -def print_ofp_match(pkt): - ofmatch = pkt.of_body['print_ofp_match'] +def print_ofp_match(msg): print 'Match -', - for K in ofmatch: - value = ofmatch[K] - if K is 'dl_vlan': - value = of10.dissector.get_vlan(value) - elif K is 'wildcards': - value = hex(value) - elif K is 'dl_type': - value = gen.tcpip.get_ethertype(int(value, 16)) - - print ("%s: %s" % (K, green(value))), - + # Collect all variables from class ofp_match + # print those that are not 'None' + for match_item in msg.match.__dict__: + match_item_value = msg.match.__dict__[match_item] + if match_item_value is not None: + if match_item is 'dl_vlan': + match_item_value = of10.dissector.get_vlan(match_item_value) + elif match_item is 'wildcards': + match_item_value = hex(match_item_value) + elif match_item is 'dl_type': + match_item_value = gen.tcpip.get_ethertype(match_item_value) + + print ("%s: %s" % (match_item, green(match_item_value))), print -def print_ofp_body(pkt): - ofbody = pkt.of_body['print_ofp_body'] +def print_ofp_body(msg): string = ('Body - Cookie: %s Command: %s Idle/Hard Timeouts: ' '%s/%s\nBody - Priority: %s Buffer ID: %s Out Port: %s Flags: %s') - command = green(of10.dissector.get_ofp_command(ofbody['command'])) - flags = green(of10.dissector.get_ofp_flags(ofbody['flags'])) - out_port = green(of10.dissector.get_phy_port_id(ofbody['out_port'])) + command = green(of10.dissector.get_ofp_command(msg.command)) + flags = green(of10.dissector.get_ofp_flags(msg.flags)) + out_port = green(of10.dissector.get_phy_port_id(msg.out_port)) + + print string % (msg.cookie, command, msg.idle_timeout, msg.hard_timeout, + msg.priority, msg.buffer_id, out_port, flags) - print string % (ofbody['cookie'], command, ofbody['idle_timeout'], - ofbody['hard_timeout'], ofbody['priority'], - ofbody['buffer_id'], out_port, flags) +def print_ofp_flow_removed(msg): + print_ofp_match(msg) -def print_ofp_flow_removed(pkt): - ofrem = pkt.of_body['print_ofp_flow_removed'] string = ('Body - Cookie: %s Priority: %s Reason: %s Pad: %s\nBody - ' 'Duration Secs/NSecs: %s/%s Idle Timeout: %s Pad2/Pad3: %s/%s' ' Packet Count: %s Byte Count: %s') - print string % (ofrem['cookie'], ofrem['priority'], - red(ofrem['reason']), ofrem['pad'], ofrem['duration_sec'], - ofrem['duration_nsec'], ofrem['idle_timeout'], - ofrem['pad2'], ofrem['pad3'], ofrem['packet_count'], - ofrem['byte_count']) + print string % (msg.cookie, msg.priority, red(msg.reason), msg.pad, + msg.duration_sec, msg.duration_nsec, msg.idle_timeout, + msg.pad2, msg.pad3, msg.packet_count, msg.byte_count) -def print_actions(pkt): - for action in pkt.of_body['print_actions']: - print_ofp_action(action['type'], action['length'], action['payload']) +def print_actions(msg): + for action in msg.actions: + print_ofp_action(action.type, action.length, action.payload) def print_ofp_action(action_type, length, payload): @@ -321,10 +312,17 @@ def print_ofp_ovs(print_options, ofmatch, ofactions, ovs_command, prio): return -def _print_portMod_config_mask(array, name): +def print_of_FlowMod(msg): + print_ofp_match(msg) + print_ofp_body(msg) + print_actions(msg) + + +def _print_portMod_config_mask(variable, name): + print ('PortMod %s:' % (name)), printed = False - for i in array[name]: + for i in variable: print of10.dissector.get_phy_config(i), printed = True else: @@ -332,26 +330,24 @@ def _print_portMod_config_mask(array, name): print -def print_PortMod(pkt): - portMod = pkt.of_body['print_PortMod'] - print ('PortMod Port: %s HW Addr %s Pad: %s' % - (portMod['port'], eth_addr(portMod['hw_addr']), portMod['pad'])) - _print_portMod_config_mask(portMod, 'config') - _print_portMod_config_mask(portMod, 'mask') - _print_portMod_config_mask(portMod, 'advertise') +def print_of_PortMod(msg): + print ('PortMod Port_no: %s HW_Addr %s Pad: %s' % + (msg.port_no, eth_addr(msg.hw_addr), msg.pad)) + _print_portMod_config_mask(msg.config, 'config') + _print_portMod_config_mask(msg.mask, 'mask') + _print_portMod_config_mask(msg.advertise, 'advertise') -def print_of_BarrierReq(pkt): +def print_of_BarrierReq(msg): print 'OpenFlow Barrier Request' -def print_of_BarrierReply(pkt): +def print_of_BarrierReply(msg): print 'OpenFlow Barrier Reply' -def print_of_vendor(pkt): - of_vendor = pkt.of_body['print_of_vendor'] - vendor = of10.dissector.get_ofp_vendor(of_vendor) +def print_of_vendor(msg): + vendor = of10.dissector.get_ofp_vendor(msg.vendor) print ('OpenFlow Vendor: %s' % vendor) @@ -518,30 +514,29 @@ def print_ofp_statResVendorData(pkt): hexdump.hexdump(data) -def print_ofp_getConfigRes(pkt): +def print_ofp_getConfigRes(msg): print ('OpenFlow GetConfigRes - Flag: %s Miss_send_len: %s' % - (pkt.of_body['print_ofp_getConfigRes']['flag'], - pkt.of_body['print_ofp_getConfigRes']['miss_send_len'])) + (msg.flag, msg.miss_send_len)) def print_ofp_setConfig(pkt): print ('OpenFlow SetConfig - Flag: %s Miss_send_len: %s' % - (pkt.of_body['print_ofp_setConfig']['flag'], - pkt.of_body['print_ofp_setConfig']['miss_send_len'])) + (msg.flag, msg.miss_send_len)) -def print_echoreq(pkt): +def print_of_echoreq(msg): + # print data print 'OpenFlow Echo Request' -def print_echores(pkt): +def print_of_echores(msg): + # print data print 'OpenFlow Echo Reply' -def print_portStatus(pkt): - reason = pkt.of_body['print_portStatus']['reason'] - pad = pkt.of_body['print_portStatus']['pad'] - print ('OpenFlow PortStatus - Reason: %s Pad: %s' % (reason, pad)) +def print_portStatus(msg): + print ('OpenFlow PortStatus - Reason: %s Pad: %s' % (msg.reason, msg.pad)) + print_of_ports(msg.desc) def print_packetInOut_layer2(of_xid, eth): @@ -554,21 +549,25 @@ def print_packetInOut_vlan(of_xid, vlan): gen.prints.print_vlan(vlan) -def print_packetIn(pkt): - packetIn = pkt.of_body['print_packetIn'] +def print_data(data): + # what to do with data? + pass + + +def print_of_packetIn(msg): print ('PacketIn: buffer_id: %s total_len: %s in_port: %s reason: %s ' 'pad: %s' % - (hex(packetIn['buffer_id']), packetIn['total_len'], - green(packetIn['in_port']), green(packetIn['reason']), - packetIn['pad'])) + (hex(msg.buffer_id), msg.total_len, green(msg.in_port), green(msg.reason), + msg.pad)) + print_data(msg.data) -def print_packetOut(pkt): - packetOut = pkt.of_body['print_packetOut'] +def print_of_packetOut(msg): print ('PacketOut: buffer_id: %s in_port: %s actions_len: %s' % - (hex(packetOut['buffer_id']), - green(of10.dissector.get_phy_port_id(packetOut['in_port'])), - packetOut['actions_len'])) + (hex(msg.buffer_id), green(of10.dissector.get_phy_port_id(msg.in_port)), + msg.actions_len)) + print_actions(msg) + # print_data(msg.data) def print_queueReq(pkt): diff --git a/ofp_sniffer.py b/ofp_sniffer.py index 931e608..fab9545 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -''' +""" This code acts as an OpenFlow troubleshoot toolkit: it acts as a sniffer, a topology validator and as an OpenFlow message checker, to make sure the ONF standards are being followed. @@ -13,10 +13,9 @@ Current version: 0.3 Author: Jeronimo Bezerra +""" -''' import datetime -import pcapy import sys import gen.cli from gen.packet import Packet @@ -42,18 +41,18 @@ def process_packet(header, packet): def main(argv): - ''' + """ This is the main function - ''' + """ cap.loop(-1, process_packet) return if __name__ == "__main__": - cap, print_options, sanitizer = gen.cli.get_params(sys.argv) - try: +# try: + cap, print_options, sanitizer = gen.cli.get_params(sys.argv) main(sys.argv) - except KeyboardInterrupt: - print 'Exiting...' - sys.exit(0) - except Exception as exception: - print exception +# except KeyboardInterrupt: +# print 'Exiting...' +# sys.exit(0) +# except Exception as exception: +# print exception From 7e0a71b6cd11fe587beb25a5e67a53aae9879159 Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Mon, 11 Apr 2016 21:55:43 -0400 Subject: [PATCH 19/88] Match changed to receive only OFP_Match StatsReq ready --- example_filter.json | 2 +- of10/packet.py | 41 ++++++++++- of10/parser.py | 162 +++++++++++++++++++++----------------------- of10/prints.py | 101 +++++++++++++-------------- 4 files changed, 171 insertions(+), 135 deletions(-) diff --git a/example_filter.json b/example_filter.json index 2518274..6cd6fe6 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,7 +2,7 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 0, 2, 3, 5, 6, 10, 12, 13, 16, 17 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19 ] }, "1.3": { diff --git a/of10/packet.py b/of10/packet.py index cca262f..31380d6 100644 --- a/of10/packet.py +++ b/of10/packet.py @@ -316,12 +316,25 @@ class OFPT_STATS_REQ(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) + self.stat_type = None + self.flags = None + self.stats = None + + def instantiate(self, *args): + if self.stat_type in [1,2]: + self.stats = OFP_STATSRES_FLOWAGG(*args) + elif self.stat_type == 4: + self.stats = OFP_STATRES_PORT(*args) + elif self.stat_type == 5: + self.stats = OFP_STATRES_QUEUE(*args) + elif self.stat_type == 65535: + self.stats = OFP_STATRES_VENDOR(*args) def process_msg(self, packet): parser.parse_StatsReq(self, packet) def prints(self): - pass + prints.print_ofp_statReq(self) class OFPT_STATS_RES(OFPHeader): @@ -430,3 +443,29 @@ def __init__(self): self.length = None self.payload = None + +class OFP_STATSRES_FLOWAGG: + + def __init__(self, match, table_id, pad, out_port): + self.match = match + self.table_id = table_id + self.pad = pad + self.out_port = out_port + +class OFP_STATRES_PORT: + + def __init__(self, port_number, pad): + self.port_number = port_number + self.pad = pad + +class OFP_STATRES_QUEUE: + + def __init__(self, port_number, pad, queue_id): + self.port_number = port_number + self.pad = pad + self.queue_id = queue_id + +class OFP_STATRES_VENDOR: + + def __init__(self, vendor_id): + self.vendor_id = vendor_id \ No newline at end of file diff --git a/of10/parser.py b/of10/parser.py index ee525f0..7dcbfbf 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -12,6 +12,8 @@ import gen.proxies from of10.packet import OFP_Phy_port from of10.packet import OFP_Action +from of10.packet import OFP_Match + # *************** Hello ***************** def parse_Hello(msg, packet): @@ -140,8 +142,8 @@ def parse_GetConfigReq(msg, packet): def _parse_SetGetConfig(packet, h_size): pkt_raw = packet[h_size:h_size+4] pkt_list = unpack('!HH', pkt_raw) - flag = of10.dissector.get_configres_flags(pkt_list[0]) - return flag, pkt_list[1] + flags = of10.dissector.get_configres_flags(pkt_list[0]) + return flags, pkt_list[1] def parse_GetConfigRes(msg, packet): @@ -238,7 +240,7 @@ def parse_PacketIn(msg, packet): # ******************** FlowRemoved *************************** def parse_FlowRemoved(msg, packet): - _parse_OFMatch(msg, packet, 0) + msg.match = _parse_OFMatch(msg, packet, 0) of_rem_body = packet[40:40+40] ofrem = unpack('!QHBBLLHBBQQ', of_rem_body) @@ -330,6 +332,7 @@ def get_ip_from_long(long_ip): def _parse_OFMatch(msg, packet, h_size): + match_tmp = OFP_Match() of_match = packet[h_size:h_size+40] ofm = unpack('!LH6s6sHBBHBBHLLHH', of_match) wildcard = ofm[0] @@ -346,11 +349,13 @@ def _parse_OFMatch(msg, packet, h_size): 'tp_dst': ofm[14]} if wildcard >= ((1 << 22) - 1): - msg.match.wildcards = 4194303 - return + # msg.match.wildcards = 4194303 + match_tmp.wildcards = 4194303 + return match_tmp elif wildcard == 0: - msg.match.wildcards = 0 - return + # msg.match.wildcards = 0 + match_tmp.wildcards = 0 + return match_tmp else: src_netmask = process_src_subnet(wildcard) if src_netmask == 0: @@ -380,8 +385,15 @@ def _parse_OFMatch(msg, packet, h_size): # For each item on ofmatch, associate the value to the equivalent on # class ofp_match. For example, if there is an ofmatch['in_port'] # msg.match.inport = ofmatch['in_port']. Others will be None + require_str = ['dl_src', 'dl_dst', 'nw_src', 'nw_dst'] for match in ofmatch: - exec ('msg.match.%s=%s') % (match, ofmatch.get(match)) + if match in require_str: + action = 'match_tmp.%s="%s"' + else: + action = 'match_tmp.%s=%s' + exec (action) % (match, ofmatch.get(match)) + + return match_tmp def _parse_OFBody(msg, packet, h_size): @@ -408,7 +420,7 @@ def get_action(action_type, length, payload): return type_0[0], type_0[1] # 1 - SetVLANID. Returns VID and pad elif action_type == 1: - type_1 = unpack('!HH', payload) + type_1 = unpack('!H2s', payload) return type_1[0], type_1[1] # 2 - SetVLANPCP elif action_type == 2: @@ -439,11 +451,11 @@ def get_action(action_type, length, payload): return type_8[0], type_8[1] # 9 - SetTPSrc elif action_type == 9: - type_9 = unpack('!HH', payload) + type_9 = unpack('!H2s', payload) return type_9[0], type_9[1] # a - SetTPDst elif action_type == int('a', 16): - type_a = unpack('!HH', payload) + type_a = unpack('!H2s', payload) return type_a[0], type_a[1] # b - Enqueue elif action_type == int('b', 16): @@ -467,7 +479,6 @@ def _parse_OFAction(packet, start): action_header = 4 # Add all actions to a list for future printing actions_list = [] - action = OFP_Action() while (1): ofp_action = packet[start:start + action_header] if len(ofp_action) > 0: @@ -479,17 +490,18 @@ def _parse_OFAction(packet, start): start = start + action_header if ofa_type == 4 or ofa_type == 5 or ofa_type == int('b', 16): total_length = 12 - ofa_action_payload = packet[start:start + 12] else: total_length = 4 - ofa_action_payload = packet[start:start + 4] + ofa_action_payload = packet[start:start + total_length] + action = OFP_Action() action.type = ofa_type action.length = ofa_length action.payload = ofa_action_payload actions_list.append(action) # Next packet would start at.. start = start + total_length + del action else: break @@ -497,7 +509,7 @@ def _parse_OFAction(packet, start): def parse_FlowMod(msg, packet): - _parse_OFMatch(msg, packet, 0) + msg.match = _parse_OFMatch(msg, packet, 0) _parse_OFBody(msg, packet, 0) # Actions: Header = 4 , plus each possible action actions_start = 64 @@ -529,74 +541,58 @@ def parse_StatsReq(msg, packet): ''' # Get type = 16bits # Get flags = 16bits - pass - # of_stat_req = pkt.packet[0:4] - # ofstat = unpack('!HH', of_stat_req) - # stat_type = ofstat[0] - # # FLags were not defined yet. Ignoring. - # # flags = ofstat[1] - # start = 4 - # - # # 7 Types available - # if stat_type == 0: - # # Description - # # No extra fields - # pkt.prepare_printing('print_ofp_statReqDesc', stat_type) - # - # elif stat_type == 1 or stat_type == 2: - # # Flow(1) or Aggregate(2) - # # Fields: match(40), table_id(8), pad(8), out_port(16) - # of_match = _parse_OFMatch(pkt.packet, start) - # # 44 Bytes (40B from Match, 4 from header) - # of_stat_req = pkt.packet[start+40:start+40+4] - # ofstat = unpack('!BBH', of_stat_req) - # table_id = ofstat[0] - # pad = ofstat[1] - # out_port = ofstat[2] - # stats = {'type': stat_type, 'match': of_match, 'table_id': table_id, - # 'pad': pad, 'out_port': out_port} - # pkt.prepare_printing('print_ofp_statReqFlowAggregate', stats) - # - # elif stat_type == 3: - # # Table - # # No extra fields - # pkt.prepare_printing('print_ofp_statReqTable', stat_type) - # - # elif stat_type == 4: - # # Port - # # Fields: port_number(16), pad(48) - # of_stat_req = pkt.packet[start:start+8] - # ofstat = unpack('!H6s', of_stat_req) - # port_number = ofstat[0] - # pad = ofstat[1] - # stats = {'type': stat_type, 'port_number': port_number, 'pad': pad} - # pkt.prepare_printing('print_ofp_statReqPort', stats) - # - # elif stat_type == 5: - # # Queue - # # Fields: port_number(16), pad(16), queue_id(32) - # of_stat_req = pkt.packet[start:start+8] - # ofstat = unpack('!HHL', of_stat_req) - # port_number = ofstat[0] - # pad = ofstat[1] - # queue_id = ofstat[2] - # stats = {'type': stat_type, 'port_number': port_number, 'pad': pad, - # 'queue_id': queue_id} - # pkt.prepare_printing('print_ofp_statReqQueue', stats) - # - # elif stat_type == 65535: - # # Vendor - # # Fields: vendor_id(32) + data - # of_stat_req = pkt.packet[start:start+4] - # ofstat = unpack('!L', of_stat_req) - # vendor_id = ofstat[0] - # stats = {'type': stat_type, 'vendor_id': vendor_id} - # pkt.prepare_printing('print_ofp_statReqVendor', stats) - # - # else: - # print 'StatReq: Unknown Type: %s' % stat_type - # - # return 1 + of_stat_req = packet[0:4] + ofstat = unpack('!HH', of_stat_req) + msg.stat_type = ofstat[0] + msg.flags = ofstat[1] + + start = 4 + + # 7 Types available + if msg.stat_type == 0: + # Description + # No extra fields + pass + + elif msg.stat_type == 1 or msg.stat_type == 2: + # Flow(1) or Aggregate(2) + # Fields: match(40), table_id(8), pad(8), out_port(16) + match = _parse_OFMatch(msg, packet, start) + # 44 Bytes (40B from Match, 4 from header) + of_stat_req = packet[start+40:start+40+4] + table_id, pad, out_port = unpack('!BBH', of_stat_req) + msg.instantiate(match, table_id, pad, out_port) + + elif msg.stat_type == 3: + # Table + # No extra fields + pass + + elif msg.stat_type == 4: + # Port + # Fields: port_number(16), pad(48) + of_stat_req = packet[start:start+8] + port_number, pad = unpack('!H6s', of_stat_req) + msg.instantiate(port_number, pad) + + elif msg.stat_type == 5: + # Queue + # Fields: port_number(16), pad(16), queue_id(32) + of_stat_req = packet[start:start+8] + port_number, pad, queue_id = unpack('!HHL', of_stat_req) + msg.instantiate(port_number, pad, queue_id) + + elif msg.stat_type == 65535: + # Vendor + # Fields: vendor_id(32) + data + of_stat_req = packet[start:start+4] + vendor_id = unpack('!L', of_stat_req)[0] + msg.instantiate(vendor_id) + + else: + print 'StatReq: Unknown Type: %s' % msg.stat_type + + return 1 # *********************** StatsRes **************************** diff --git a/of10/prints.py b/of10/prints.py index 02a1441..4eec539 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -79,7 +79,6 @@ def print_of_getconfig_req(msg): def print_of_feature_res(msg): - print 'OpenFlow Feature Reply' dpid = datapath_id(msg.datapath_id) print ('FeatureRes - datapath_id: %s n_buffers: %s n_tbls: %s, pad: %s' % (green(dpid), msg.n_buffers, msg.n_tbls, msg.pad)) @@ -91,7 +90,7 @@ def print_of_feature_res(msg): for i in msg.actions: print of10.dissector.get_feature_res_actions(i), print - print_of_ports(msg) + print_of_ports(msg.ports) def _dont_print_0(printed): @@ -105,7 +104,6 @@ def print_port_field(port_id, variable, name): printed = False print ('Port_id: %s - %s curr:' % (port_id, name)), - a = [] for i in variable: print of10.dissector.get_phy_feature(i), printed = True @@ -138,10 +136,10 @@ def print_ofp_phy_port(port): print # fix it - print_port_field(port.id, port.curr, 'curr') - print_port_field(port.id, port.advertised, 'advertised') - print_port_field(port.id, port.supported, 'supported') - print_port_field(port.id, port.peer, 'peer') + print_port_field(port_id, port.curr, 'curr') + print_port_field(port_id, port.advertised, 'advertised') + print_port_field(port_id, port.supported, 'supported') + print_port_field(port_id, port.peer, 'peer') def print_of_ports(ports): @@ -152,12 +150,12 @@ def print_of_ports(ports): print_ofp_phy_port(port) -def print_ofp_match(msg): +def print_ofp_match(match): print 'Match -', # Collect all variables from class ofp_match # print those that are not 'None' - for match_item in msg.match.__dict__: - match_item_value = msg.match.__dict__[match_item] + for match_item in match.__dict__: + match_item_value = match.__dict__[match_item] if match_item_value is not None: if match_item is 'dl_vlan': match_item_value = of10.dissector.get_vlan(match_item_value) @@ -178,11 +176,11 @@ def print_ofp_body(msg): out_port = green(of10.dissector.get_phy_port_id(msg.out_port)) print string % (msg.cookie, command, msg.idle_timeout, msg.hard_timeout, - msg.priority, msg.buffer_id, out_port, flags) + green(msg.priority), msg.buffer_id, out_port, flags) def print_ofp_flow_removed(msg): - print_ofp_match(msg) + print_ofp_match(msg.match) string = ('Body - Cookie: %s Priority: %s Reason: %s Pad: %s\nBody - ' 'Duration Secs/NSecs: %s/%s Idle Timeout: %s Pad2/Pad3: %s/%s' @@ -313,7 +311,7 @@ def print_ofp_ovs(print_options, ofmatch, ofactions, ovs_command, prio): def print_of_FlowMod(msg): - print_ofp_match(msg) + print_ofp_match(msg.match) print_ofp_body(msg) print_actions(msg) @@ -351,56 +349,59 @@ def print_of_vendor(msg): print ('OpenFlow Vendor: %s' % vendor) -def print_ofp_statReqDesc(pkt): - print 'StatReq Type: Description(%s)' % pkt.of_body['print_ofp_statReqDesc'] +def print_ofp_statReq(msg): + if msg.stat_type == 0: + print_ofp_statReqDesc(msg) + elif msg.stat_type == 1 or msg.type == 2: + print_ofp_statReqFlowAggregate(msg) + elif msg.stat_type == 3: + print_ofp_statReqTable(msg) + elif msg.stat_type == 4: + print_ofp_statReqPort(msg) + elif msg.stat_type == 5: + print_ofp_statReqQueue(msg) + elif msg.stat_type == 65535: + print_ofp_statReqVendor(msg) -def print_ofp_statReqFlowAggregate(pkt): - stats = pkt.of_body['print_ofp_statReqFlowAggregate'] - if stats['type'] == 1: +def print_ofp_statReqDesc(msg): + print 'StatReq Type: Description(%s)' % msg.stat_type + + +def print_ofp_statReqFlowAggregate(msg): + if msg.stat_type == 1: type_name = 'Flow' else: type_name = 'Aggregate' - - print ('StatReq Type: %s(%s)' % (type_name, stats['type'])) - pkt.of_body['print_ofp_match'] = stats['match'] - print_ofp_match(pkt) - print ('StatReq Table_id: %s Pad: %d Out_Port: %s' % (stats['table_id'], - stats['pad'], stats['out_port'])) + print ('StatReq Type: %s(%s)' % (type_name, msg.stat_type)) + print_ofp_match(msg.stats.match) + out_port = of10.dissector.get_phy_port_id(msg.stats.out_port) + print ('StatReq Table_id: %s Pad: %d Out_Port: %s' % (msg.stats.table_id, + msg.stats.pad, out_port)) -def print_ofp_statReqTable(pkt): - print 'StatReq Type: Table(%s)' % pkt.of_body['print_ofp_statReqTable'] +def print_ofp_statReqTable(msg): + print 'StatReq Type: Table(%s)' % msg.stat_type -def print_ofp_statReqPort(pkt): - stats = pkt.of_body['print_ofp_statReqPort'] - stat_type = stats['type'] - port_number = of10.dissector.get_phy_port_id(stats['port_number']) - pad = stats['pad'] +def print_ofp_statReqPort(msg): + port_number = of10.dissector.get_phy_port_id(msg.stats.port_number) print ('StatReq Type: Port(%s): Port_Number: %s Pad: %s' % - (stat_type, green(port_number), pad)) + (msg.stat_type, green(port_number), msg.stats.pad)) -def print_ofp_statReqQueue(pkt): - stats = pkt.of_body['print_ofp_statReqQueue'] - stat_type = stats['type'] - port_number = of10.dissector.get_phy_port_id(stats['port_number']) - pad = stats['pad'] - queue_id = stats['queue_id'] +def print_ofp_statReqQueue(msg): + port_number = of10.dissector.get_phy_port_id(msg.stats.port_number) print ('StatReq Type: Queue(%s): Port_Number: %s Pad: %s Queue_id: %s' % - (stat_type, green(port_number), pad, queue_id)) + (msg.stat_type, green(port_number), msg.stats.pad, msg.stats.queue_id)) -def print_ofp_statReqVendor(pkt): - stats = pkt.of_body['print_ofp_statReqVendor'] - stat_type = stats['type'] - vendor_id = stats['vendor_id'] - print ('StatReq Type: Vendor(%s): Vendor_ID: %s' % (stat_type, - vendor_id)) +def print_ofp_statReqVendor(msg): + print ('StatReq Type: Vendor(%s): Vendor_ID: %s' % (msg.stat_type, + msg.stats.vendor_id)) -def print_ofp_statResDesc(pkt): +def print_ofp_statResDesc(msg): stats = pkt.of_body['print_ofp_statResDesc'] print ('StatRes Type: Description(%s)' % (stats['type'])) print ('StatRes mfr_desc: %s' % (stats['mfr_desc'])) @@ -410,7 +411,7 @@ def print_ofp_statResDesc(pkt): print ('StatRes dp_desc: %s' % (stats['dp_desc'])) -def print_ofp_statResFlowArray(pkt): +def print_ofp_statResFlowArray(msg): flows = pkt.of_body['print_ofp_statResFlowArray'] if len(flows) == 0: print ('StatRes Type: Flow(1)\nNo Flows') @@ -420,7 +421,7 @@ def print_ofp_statResFlowArray(pkt): print_ofp_statResFlow(pkt, flow_stats) -def print_ofp_statResFlow(pkt, stats): +def print_ofp_statResFlow(msg, stats): stat_type = stats['type'] res_flow = stats['res_flow'] print ('StatRes Type: Flow(%s)' % (stat_type)) @@ -519,9 +520,9 @@ def print_ofp_getConfigRes(msg): (msg.flag, msg.miss_send_len)) -def print_ofp_setConfig(pkt): +def print_ofp_setConfig(msg): print ('OpenFlow SetConfig - Flag: %s Miss_send_len: %s' % - (msg.flag, msg.miss_send_len)) + (msg.flags, msg.miss_send_len)) def print_of_echoreq(msg): From 6e7d6e044ee98827bd09f4ad20f7e5c3b38278aa Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Wed, 13 Apr 2016 22:40:31 -0400 Subject: [PATCH 20/88] StatRes - Description, Flow and Aggregated converted --- example_filter.json | 2 +- of10/packet.py | 140 +++++++++++++++++++++++++++++++++--- of10/parser.py | 169 +++++++++++++++++++++++--------------------- of10/prints.py | 88 +++++++++++++---------- 4 files changed, 270 insertions(+), 129 deletions(-) diff --git a/example_filter.json b/example_filter.json index 6cd6fe6..72861b9 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,7 +2,7 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19 ] }, "1.3": { diff --git a/of10/packet.py b/of10/packet.py index 31380d6..87785fd 100644 --- a/of10/packet.py +++ b/of10/packet.py @@ -322,13 +322,13 @@ def __init__(self, of_header): def instantiate(self, *args): if self.stat_type in [1,2]: - self.stats = OFP_STATSRES_FLOWAGG(*args) + self.stats = OFP_STATSREQ_FLOWAGG(*args) elif self.stat_type == 4: - self.stats = OFP_STATRES_PORT(*args) + self.stats = OFP_STATREQ_PORT(*args) elif self.stat_type == 5: - self.stats = OFP_STATRES_QUEUE(*args) + self.stats = OFP_STATREQ_QUEUE(*args) elif self.stat_type == 65535: - self.stats = OFP_STATRES_VENDOR(*args) + self.stats = OFP_STATREQ_VENDOR(*args) def process_msg(self, packet): parser.parse_StatsReq(self, packet) @@ -341,12 +341,31 @@ class OFPT_STATS_RES(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) + self.stat_type = None + self.flags = None + self.stats = None + + def instantiate(self, *args): + if self.stat_type == 0: + self.stats = OFP_STATSRES_DESC(*args) + elif self.stat_type == 1: + self.stats = OFP_STATSRES_FLOW(*args) + elif self.stat_type == 2: + self.stats = OFP_STATSRES_AGG(*args) + elif self.stat_type == 3: + self.stats = OFP_STATSRES_TABLE(*args) + elif self.stat_type == 4: + self.stats = OFP_STATRES_PORT(*args) + elif self.stat_type == 5: + self.stats = OFP_STATRES_QUEUE(*args) + elif self.stat_type == 65535: + self.stats = OFP_STATRES_VENDOR(*args) def process_msg(self, packet): parser.parse_StatsRes(self, packet) def prints(self): - pass + prints.print_ofp_statRes(self) class OFPT_BARRIER_REQ(OFPHeader): @@ -443,8 +462,9 @@ def __init__(self): self.length = None self.payload = None +# OFP_STATS_REQ Auxiliary Classes -class OFP_STATSRES_FLOWAGG: +class OFP_STATSREQ_FLOWAGG: def __init__(self, match, table_id, pad, out_port): self.match = match @@ -452,20 +472,122 @@ def __init__(self, match, table_id, pad, out_port): self.pad = pad self.out_port = out_port -class OFP_STATRES_PORT: + +class OFP_STATREQ_PORT: def __init__(self, port_number, pad): self.port_number = port_number self.pad = pad -class OFP_STATRES_QUEUE: + +class OFP_STATREQ_QUEUE: def __init__(self, port_number, pad, queue_id): self.port_number = port_number self.pad = pad self.queue_id = queue_id + +class OFP_STATREQ_VENDOR: + + def __init__(self, vendor_id): + self.vendor_id = vendor_id + + +# OFP_STATS_RES Auxiliary Classes + +class OFP_STATSRES_DESC: + + def __init__(self, mfr_desc, hw_desc, sw_desc, serial_num, dp_desc): + self.mfr_desc = mfr_desc + self.hw_desc = hw_desc + self.sw_desc = sw_desc + self.serial_num = serial_num + self.dp_desc = dp_desc + + +class OFP_STATSRES_FLOW: + + def __init__(self, flows): + self.flows = flows + + +class OFP_STATSRES_AGG: + + def __init__(self, packet_count, byte_count, flow_count, pad): + self.packet_count = packet_count + self.byte_count = byte_count + self.flow_count = flow_count + self.pad = pad + + +class OFP_STATSRES_TABLE: + + def __init__(self, table_id, pad, name, wildcards, max_entries, + active_count, lookup_count, matched_count): + self.table_id = table_id + self.pad = pad + self.name = name + self.wildcards = wildcards + self.max_entries = max_entries + self.active_count = active_count + self.lookup_count = lookup_count + self.matched_count = matched_count + + +class OFP_STATRES_PORT: + + def __init__(self, port_number, pad, rx_packets, tx_packets, rx_bytes, + tx_bytes, rx_dropped, tx_dropped, rx_errors, tx_errors, + rx_frame_err, rx_over_err, rx_crc_err, collisions): + self.port_number = port_number + self.pad = pad + self.rx_packets = rx_packets + self.tx_packets = tx_packets + self.rx_bytes = rx_bytes + self.tx_bytes = tx_bytes + self.rx_dropped = rx_dropped + self.tx_dropped = tx_dropped + self.rx_errors = rx_errors + self.tx_errors = tx_errors + self.rx_frame_err = rx_frame_err + self.rx_over_err = rx_over_err + self.rx_crc_err = rx_crc_err + self.collisions = collisions + +class OFP_STATRES_QUEUE: + + def __init__(self, length, pad, queue_id, tx_bytes, tx_packets, + tx_errors): + self.length = length + self.pad = pad + self.queue_id = queue_id + self.tx_bytes = tx_bytes + self.tx_packets = tx_packets + self.tx_errors = tx_errors + class OFP_STATRES_VENDOR: def __init__(self, vendor_id): - self.vendor_id = vendor_id \ No newline at end of file + self.vendor_id = vendor_id + + +### STAT_RES Auxiliary Classes #### + +class OFP_STAT_FLOW: + + def __init__(self): + self.length = None + self.table_id = None + self.pad = None + self.match = None + self.duration_sec = None + self.duration_nsec = None + self.priority = None + self.idle_timeout = None + self.hard_timeout = None + self.pad2 = None + self.cookie = None + self.packet_count = None + self.byte_count = None + self.actions = None diff --git a/of10/parser.py b/of10/parser.py index 7dcbfbf..f0c770f 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -13,6 +13,7 @@ from of10.packet import OFP_Phy_port from of10.packet import OFP_Action from of10.packet import OFP_Match +from of10.packet import OFP_STAT_FLOW # *************** Hello ***************** @@ -597,80 +598,86 @@ def parse_StatsReq(msg, packet): # *********************** StatsRes **************************** def parse_StatsRes(msg, packet): - pass # Get type = 16bits # Get flags = 16bits - # of_stat_req = pkt.packet[0:4] - # ofstat = unpack('!HH', of_stat_req) - # stat_type = ofstat[0] - # # flags = ofstat[1] - # start = 4 - # - # # 7 Types available - # if stat_type == 0: - # # Description - # # Fields: mfr_desc(2048), hw_desc(2048), sw_desc(2048), serial_num(256), - # # dp_desc(2048) - # desc_raw = pkt.packet[start:start+1056] - # desc = unpack('!256s256s256s32s256s', desc_raw) - # stats = {'mfr_desc': desc[0], - # 'hw_desc': desc[1], - # 'sw_desc': desc[2], - # 'serial_num': desc[3], - # 'dp_desc': desc[4], - # 'type': stat_type} - # pkt.prepare_printing('print_ofp_statResDesc', stats) - # - # elif stat_type == 1: - # # Flow(1) - # # Fields: length(16), table_id(8), pad(8), match(40), duration_sec(32), - # # duration_nsec(32), priority(16), idle_timeout(16), hard_timeout(16), - # # pad(48), cookie(64), packet_count(64), byte_count(64), actions[] - # count = len(pkt.packet[0:]) - 4 - # flows = [] - # while (count > 0): - # flow_raw = pkt.packet[start:start+4] - # flow = unpack('!HBB', flow_raw) - # res_flow = {'length': flow[0], 'table_id': flow[1], 'pad': flow[2]} - # of_match = _parse_OFMatch(pkt.packet, start+4) - # - # flow_raw = pkt.packet[start+44:start+44+44] - # flow = unpack('!LLHHH6sQQQ', flow_raw) - # res_flow.update({'duration_sec': flow[0], 'duration_nsec': flow[1], - # 'priority': flow[2], 'idle_timeout': flow[3], - # 'hard_timeout': flow[4], 'pad2': flow[5], - # 'cookie': flow[6], 'packet_count': flow[7], - # 'byte_count': flow[8]}) - # stats = {'type': stat_type, 'match': of_match, 'res_flow': res_flow} - # - # # Process Actions[] - # end = res_flow['length'] - (4 + 40 + 44) - # actions = pkt.packet[start+88:start+88+end] - # actions_dict = _parse_OFAction(actions, 0) - # - # stats = {'type': stat_type, 'match': of_match, - # 'res_flow': res_flow, 'print_actions': actions_dict} - # - # flows.append(stats) - # - # count = count - int(res_flow['length']) - # start = start + int(res_flow['length']) - # - # # important to have a sequencial list here because there are multiple - # # flows. So, print_ofp_statResFlow will print a list of flows. - # pkt.prepare_printing('print_ofp_statResFlowArray', flows) - # - # elif stat_type == 2: - # # Aggregate(2) - # # Fields: packet_count(64), byte_count(64), flow_count(32), pad(32) - # flow_raw = pkt.packet[start:start+24] - # flow = unpack('!QQLL', flow_raw) - # res_flow = {'type': stat_type, 'packet_count': flow[0], - # 'byte_count': flow[1], 'flow_count': flow[2], - # 'pad': flow[3]} - # pkt.prepare_printing('print_ofp_statResAggregate', res_flow) - # - # elif stat_type == 3: + of_stat_req = packet[0:4] + msg.stat_type, msg.flags = unpack('!HH', of_stat_req) + + start = 4 + # 7 Types available + if msg.stat_type == 0: + # Description + # Fields: mfr_desc(2048), hw_desc(2048), sw_desc(2048), serial_num(256), + # dp_desc(2048) + desc_raw = packet[start:start+1056] + desc = unpack('!256s256s256s32s256s', desc_raw) + mfr_desc = desc[0] + hw_desc = desc[1] + sw_desc = desc[2] + serial_num = desc[3] + dp_desc = desc[4] + msg.instantiate(mfr_desc, hw_desc, sw_desc, serial_num, dp_desc) + + elif msg.stat_type == 1: + # Flow(1) + # Fields: length(16), table_id(8), pad(8), match(40), duration_sec(32), + # duration_nsec(32), priority(16), idle_timeout(16), hard_timeout(16), + # pad(48), cookie(64), packet_count(64), byte_count(64), actions[] + count = len(packet[0:]) - 4 + flows = [] + while (count > 0): + flow_raw = packet[start:start+4] + flow = unpack('!HBB', flow_raw) + + eflow = OFP_STAT_FLOW() + + eflow.length = flow[0] + eflow.table_id = flow[1] + eflow.pad = flow[2] + + eflow.match = _parse_OFMatch(msg, packet, start+4) + + flow_raw = packet[start+44:start+44+44] + flow = unpack('!LLHHH6sQQQ', flow_raw) + + eflow.duration_sec = flow[0] + eflow.duration_nsec = flow[1] + eflow.priority = flow[2] + eflow.idle_timeout = flow[3] + eflow.hard_timeout = flow[4] + eflow.pad2 = flow[5] + cookie = flow[6] if flow[6] > 0 else 0 + cookie = '0x' + format(cookie, '02x') + eflow.cookie = cookie + eflow.packet_count = flow[7] + eflow.byte_count = flow[8] + + # Process Actions[] + end = eflow.length - (4 + 40 + 44) + actions = packet[start+88:start+88+end] + eflow.actions = _parse_OFAction(actions, 0) + + flows.append(eflow) + + count = count - int(eflow.length) + start = start + int(eflow.length) + del eflow + + msg.instantiate(flows) + + + elif msg.stat_type == 2: + # Aggregate(2) + # Fields: packet_count(64), byte_count(64), flow_count(32), pad(32) + flow_raw = packet[start:start+24] + flow = unpack('!QQLL', flow_raw) + packet_count = flow[0] + byte_count = flow[1] + flow_count = flow[2] + pad = flow[3] + msg.instantiate(packet_count, byte_count, flow_count, pad) + + # elif msg.stat_type == 3: # # Table # # Fields: table_id(8), pad(24), name(256), wildcards(32), # # max_entries(32), active_count(32), lookup_count(64), @@ -683,7 +690,7 @@ def parse_StatsRes(msg, packet): # 'lookup_count': flow[6], 'matched_count': flow[7]} # pkt.prepare_printing('print_ofp_statResTable', res_flow) # - # elif stat_type == 4: + # elif msg.stat_type == 4: # # Port # # Fields: port_number(16), pad(48), rx_packets(64), tx_packets(64), # # rx_bytes(64), tx_bytes(64), rx_dropped(64), tx_dropped(64), @@ -709,7 +716,7 @@ def parse_StatsRes(msg, packet): # # pkt.prepare_printing('print_ofp_statResPortArray', ports) # - # elif stat_type == 5: + # elif msg.stat_type == 5: # # Queue # # Fields: length(16), pad(16), queue_id(32), tx_bytes(64), # # tx_packets(64), tx_errors(64) @@ -727,7 +734,7 @@ def parse_StatsRes(msg, packet): # # pkt.prepare_printing('print_ofp_statResQueueArray', queues) # - # elif stat_type == 65535: + # elif msg.stat_type == 65535: # # Vendor # # Fields: vendor_id(32), data(?) # flow_raw = pkt.packet[start:start+4] @@ -751,9 +758,9 @@ def parse_StatsRes(msg, packet): # # start = start + 1 # # pkt.prepare_printing('print_ofp_statResVendorData', ''.join(data)) # - # else: - # print ('StatRes: Unknown Type: %s' % (stat_type)) - # return 1 + else: + print ('StatRes: Unknown Type: %s' % (msg.stat_type)) + return 1 # ********************** BarrierReq *********************** @@ -769,10 +776,10 @@ def parse_BarrierRes(msg, packet): # ******************* QueueGetConfigReq ******************* def parse_QueueGetConfigReq(msg, packet): queue_raw = packet[0:4] - # queue = unpack('!HH', queue_raw) - # queueConfReq = {'port': queue[0], 'pad': queue[1]} + queue = unpack('!HH', queue_raw) + queueConfReq = {'port': queue[0], 'pad': queue[1]} # pkt.prepare_printing('print_queueReq', queueConfReq) - # return 1 + return 1 # ****************** QueueGetConfigRes ******************** diff --git a/of10/prints.py b/of10/prints.py index 4eec539..9d4c3c4 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -191,8 +191,8 @@ def print_ofp_flow_removed(msg): msg.pad2, msg.pad3, msg.packet_count, msg.byte_count) -def print_actions(msg): - for action in msg.actions: +def print_actions(actions): + for action in actions: print_ofp_action(action.type, action.length, action.payload) @@ -313,7 +313,7 @@ def print_ofp_ovs(print_options, ofmatch, ofactions, ovs_command, prio): def print_of_FlowMod(msg): print_ofp_match(msg.match) print_ofp_body(msg) - print_actions(msg) + print_actions(msg.actions) def _print_portMod_config_mask(variable, name): @@ -355,7 +355,7 @@ def print_ofp_statReq(msg): elif msg.stat_type == 1 or msg.type == 2: print_ofp_statReqFlowAggregate(msg) elif msg.stat_type == 3: - print_ofp_statReqTable(msg) + print_ofp_statResTable(msg) elif msg.stat_type == 4: print_ofp_statReqPort(msg) elif msg.stat_type == 5: @@ -401,57 +401,69 @@ def print_ofp_statReqVendor(msg): msg.stats.vendor_id)) +def print_ofp_statRes(msg): + if msg.stat_type == 0: + print_ofp_statResDesc(msg) + elif msg.stat_type == 1: + print_ofp_statResFlowArray(msg) + elif msg.stat_type == 2: + print_ofp_statResAggregate(msg) + # elif msg.stat_type == 3: + # print_ofp_statResTable(msg) + # elif msg.stat_type == 4: + # print_ofp_statResPortArray(msg) + # elif msg.stat_type == 5: + # print_ofp_statResQueue(msg) + # elif msg.stat_type == 65535: + # print_ofp_statResVendor(msg) + + def print_ofp_statResDesc(msg): - stats = pkt.of_body['print_ofp_statResDesc'] - print ('StatRes Type: Description(%s)' % (stats['type'])) - print ('StatRes mfr_desc: %s' % (stats['mfr_desc'])) - print ('StatRes hw_desc: %s' % (stats['hw_desc'])) - print ('StatRes sw_desc: %s' % (stats['sw_desc'])) - print ('StatRes serial_num: %s' % (stats['serial_num'])) - print ('StatRes dp_desc: %s' % (stats['dp_desc'])) + print ('StatRes Type: Description(%s)' % (msg.stat_type)) + print ('StatRes mfr_desc: %s' % (msg.stats.mfr_desc)) + print ('StatRes hw_desc: %s' % (msg.stats.hw_desc)) + print ('StatRes sw_desc: %s' % (msg.stats.sw_desc)) + print ('StatRes serial_num: %s' % (msg.stats.serial_num)) + print ('StatRes dp_desc: %s' % (msg.stats.dp_desc)) def print_ofp_statResFlowArray(msg): - flows = pkt.of_body['print_ofp_statResFlowArray'] - if len(flows) == 0: + if len(msg.stats.flows) == 0: print ('StatRes Type: Flow(1)\nNo Flows') return - for flow_stats in flows: - print_ofp_statResFlow(pkt, flow_stats) + for flow in msg.stats.flows: + + print_ofp_statResFlow(flow) -def print_ofp_statResFlow(msg, stats): - stat_type = stats['type'] - res_flow = stats['res_flow'] - print ('StatRes Type: Flow(%s)' % (stat_type)) +def print_ofp_statResFlow(flow): + print ('StatRes Type: Flow(1)') print ('StatRes Length: %s Table_id: %s Pad: %s ' % - (res_flow['length'], res_flow['table_id'], res_flow['pad'])) + (flow.length, flow.table_id, flow.pad)) print ('StatRes'), - pkt.of_body['print_ofp_match'] = stats['match'] - print_ofp_match(pkt) + print_ofp_match(flow.match) print ('StatRes duration_sec: %s, duration_nsec: %s, priority: %s,' ' idle_timeout: %s, hard_timeout: %s, pad: %s, cookie: %s,' ' packet_count: %s, byte_count: %s' % - (res_flow['duration_sec'], res_flow['duration_nsec'], - res_flow['priority'], res_flow['idle_timeout'], - res_flow['hard_timeout'], res_flow['pad'], - res_flow['cookie'], - res_flow['packet_count'], res_flow['byte_count'])) - pkt.of_body['print_actions'] = stats['print_actions'] - print_actions(pkt) - - -def print_ofp_statResAggregate(pkt): - res_flow = pkt.of_body['print_ofp_statResAggregate'] - print ('StatRes Type: Aggregate(%s)' % (res_flow['type'])) + (flow.duration_sec, flow.duration_nsec, + flow.priority, flow.idle_timeout, + flow.hard_timeout, flow.pad, + flow.cookie, + flow.packet_count, flow.byte_count)) + print ('StatRes'), + print_actions(flow.actions) + + +def print_ofp_statResAggregate(msg): + print ('StatRes Type: Aggregate(2)') print ('StatRes packet_count: %s, byte_count: %s flow_count: %s ' 'pad: %s' % - (res_flow['packet_count'], res_flow['byte_count'], - res_flow['flow_count'], res_flow['pad'])) + (msg.stats.packet_count, msg.stats.byte_count, + msg.stats.flow_count, msg.stats.pad)) -def print_ofp_statResTable(pkt): +def print_ofp_statResTable(msg): res_flow = pkt.of_body['print_ofp_statResTable'] print ('StatRes Type: Table(%s)' % (res_flow['type'])) print ('StatRes table_id: %s, pad: %s, name: "%s", wildcards: %s, ' @@ -567,7 +579,7 @@ def print_of_packetOut(msg): print ('PacketOut: buffer_id: %s in_port: %s actions_len: %s' % (hex(msg.buffer_id), green(of10.dissector.get_phy_port_id(msg.in_port)), msg.actions_len)) - print_actions(msg) + print_actions(msg.actions) # print_data(msg.data) From 0e31c2b7148e592fe30a75403828824ba8adf807 Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Thu, 14 Apr 2016 16:29:47 -0400 Subject: [PATCH 21/88] Stats Ports --- of10/packet.py | 40 ++++++----- of10/parser.py | 181 +++++++++++++++++++++++++++++-------------------- of10/prints.py | 46 ++++++------- 3 files changed, 153 insertions(+), 114 deletions(-) diff --git a/of10/packet.py b/of10/packet.py index 87785fd..1919856 100644 --- a/of10/packet.py +++ b/of10/packet.py @@ -509,7 +509,7 @@ def __init__(self, mfr_desc, hw_desc, sw_desc, serial_num, dp_desc): class OFP_STATSRES_FLOW: def __init__(self, flows): - self.flows = flows + self.flows = flows # Class OFP_STAT_FLOW[] class OFP_STATSRES_AGG: @@ -537,23 +537,8 @@ def __init__(self, table_id, pad, name, wildcards, max_entries, class OFP_STATRES_PORT: - def __init__(self, port_number, pad, rx_packets, tx_packets, rx_bytes, - tx_bytes, rx_dropped, tx_dropped, rx_errors, tx_errors, - rx_frame_err, rx_over_err, rx_crc_err, collisions): - self.port_number = port_number - self.pad = pad - self.rx_packets = rx_packets - self.tx_packets = tx_packets - self.rx_bytes = rx_bytes - self.tx_bytes = tx_bytes - self.rx_dropped = rx_dropped - self.tx_dropped = tx_dropped - self.rx_errors = rx_errors - self.tx_errors = tx_errors - self.rx_frame_err = rx_frame_err - self.rx_over_err = rx_over_err - self.rx_crc_err = rx_crc_err - self.collisions = collisions + def __init__(self, ports): + self.ports = ports # Class OFP_STAT_PORT[] class OFP_STATRES_QUEUE: @@ -591,3 +576,22 @@ def __init__(self): self.packet_count = None self.byte_count = None self.actions = None + + +class OFP_STAT_PORT: + + def __init__(self): + self.port_number = None + self.pad = None + self.rx_packets = None + self.tx_packets = None + self.rx_bytes = None + self.tx_bytes = None + self.rx_dropped = None + self.tx_dropped = None + self.rx_errors = None + self.tx_errors = None + self.rx_frame_err = None + self.rx_over_err = None + self.rx_crc_err = None + self.collisions = None \ No newline at end of file diff --git a/of10/parser.py b/of10/parser.py index f0c770f..b1a55ca 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -2,18 +2,20 @@ Parser for OpenFlow 1.0 """ -from struct import unpack -import of10.dissector -import of10.prints import socket import struct +from struct import unpack +import gen.proxies import gen.tcpip +import of10.dissector +import of10.prints import of10.vendors -import gen.proxies -from of10.packet import OFP_Phy_port + from of10.packet import OFP_Action +from of10.packet import OFP_Phy_port from of10.packet import OFP_Match from of10.packet import OFP_STAT_FLOW +from of10.packet import OFP_STAT_PORT # *************** Hello ***************** @@ -598,17 +600,28 @@ def parse_StatsReq(msg, packet): # *********************** StatsRes **************************** def parse_StatsRes(msg, packet): - # Get type = 16bits + """ Parses OFP_STAT_RES OpenFlow messages + + Args: + msg: instantiated packet class from of10/packet.py + packet: OpenFlow message to be processed + + Returns: 1 + + """ + + # Get type = 16bits - 7 Types available # Get flags = 16bits of_stat_req = packet[0:4] msg.stat_type, msg.flags = unpack('!HH', of_stat_req) start = 4 - # 7 Types available + if msg.stat_type == 0: - # Description - # Fields: mfr_desc(2048), hw_desc(2048), sw_desc(2048), serial_num(256), - # dp_desc(2048) + """ Parses Description(0) + Fields: mfr_desc(2048), hw_desc(2048), sw_desc(2048), serial_num(256), + dp_desc(2048) = 1056 Bytes + """ desc_raw = packet[start:start+1056] desc = unpack('!256s256s256s32s256s', desc_raw) mfr_desc = desc[0] @@ -619,10 +632,11 @@ def parse_StatsRes(msg, packet): msg.instantiate(mfr_desc, hw_desc, sw_desc, serial_num, dp_desc) elif msg.stat_type == 1: - # Flow(1) - # Fields: length(16), table_id(8), pad(8), match(40), duration_sec(32), - # duration_nsec(32), priority(16), idle_timeout(16), hard_timeout(16), - # pad(48), cookie(64), packet_count(64), byte_count(64), actions[] + """ Parses Flow(1) + Fields: length(16), table_id(8), pad(8), match(40), duration_sec(32), + duration_nsec(32), priority(16), idle_timeout(16), hard_timeout(16), + pad(48), cookie(64), packet_count(64), byte_count(64), actions[] + """ count = len(packet[0:]) - 4 flows = [] while (count > 0): @@ -667,8 +681,10 @@ def parse_StatsRes(msg, packet): elif msg.stat_type == 2: - # Aggregate(2) - # Fields: packet_count(64), byte_count(64), flow_count(32), pad(32) + """ + Parses Aggregate(2) + Fields: packet_count(64), byte_count(64), flow_count(32), pad(32) = 24 Bytes + """ flow_raw = packet[start:start+24] flow = unpack('!QQLL', flow_raw) packet_count = flow[0] @@ -677,63 +693,82 @@ def parse_StatsRes(msg, packet): pad = flow[3] msg.instantiate(packet_count, byte_count, flow_count, pad) - # elif msg.stat_type == 3: - # # Table - # # Fields: table_id(8), pad(24), name(256), wildcards(32), - # # max_entries(32), active_count(32), lookup_count(64), - # # matched_count(64) - # flow_raw = pkt.packet[start:start+64] - # flow = unpack('!B3s32sLLLQQ', flow_raw) - # res_flow = {'type': stat_type, 'table_id': flow[0], 'pad': flow[1], - # 'name': flow[2], 'wildcards': flow[3], - # 'max_entries': flow[4], 'active_count': flow[5], - # 'lookup_count': flow[6], 'matched_count': flow[7]} - # pkt.prepare_printing('print_ofp_statResTable', res_flow) - # - # elif msg.stat_type == 4: - # # Port - # # Fields: port_number(16), pad(48), rx_packets(64), tx_packets(64), - # # rx_bytes(64), tx_bytes(64), rx_dropped(64), tx_dropped(64), - # # rx_errors(64), tx_errors(64), rx_frame_err(64), rx_over_err(64), - # # rx_crc_err(64), collisions(64) - # count = len(pkt.packet[0:]) - 4 - # ports = [] - # while (count > 0): - # flow_raw = pkt.packet[start:start+104] - # flow = unpack('!H6sQQQQQQQQQQQQ', flow_raw) - # port = {'type': stat_type, 'port_no': flow[0], 'pad': flow[1], - # 'rx_packets': flow[2], 'tx_packets': flow[3], - # 'rx_bytes': flow[4], 'tx_bytes': flow[5], - # 'rx_dropped': flow[6], 'tx_dropped': flow[7], - # 'rx_errors': flow[8], 'tx_errors': flow[9], - # 'rx_frame_err': flow[10], 'rx_over_err': flow[11], - # 'rx_crc_err': flow[12], 'collisions': flow[13]} - # - # ports.append(port) - # - # count = count - 104 - # start = start + 104 - # - # pkt.prepare_printing('print_ofp_statResPortArray', ports) - # - # elif msg.stat_type == 5: - # # Queue - # # Fields: length(16), pad(16), queue_id(32), tx_bytes(64), - # # tx_packets(64), tx_errors(64) - # count = len(pkt.packet[0:]) - 4 - # queues = [] - # while (count > 0): - # flow_raw = pkt.packet[start:start+32] - # flow = unpack('!HHLQQQ', flow_raw) - # queue = {'length': flow[0], 'pad': flow[1], 'queue_id': flow[2], - # 'tx_bytes': flow[3], 'tx_packets': flow[4], - # 'tx_errors': flow[5], 'type': stat_type} - # queues.append(queue) - # count = count - 32 - # start = start + 32 - # - # pkt.prepare_printing('print_ofp_statResQueueArray', queues) - # + elif msg.stat_type == 3: + """ Parsers Table(3) + Fields: table_id(8), pad(24), name(256), wildcards(32), + max_entries(32), active_count(32), lookup_count(64), + matched_count(64) = 64 Bytes + """ + flow_raw = packet[start:start+64] + flow = unpack('!B3s32sLLLQQ', flow_raw) + table_id = flow[0] + pad = flow[1] + name = flow[2] + wildcards = flow[3] + max_entries = flow[4] + active_count = flow[5] + lookup_count = flow[6] + matched_count = flow[7] + msg.instantiate(table_id, pad, name, wildcards, max_entries, + active_count, lookup_count, matched_count) + + elif msg.stat_type == 4: + """ Parses Port(4) + Fields: port_number(16), pad(48), rx_packets(64), tx_packets(64), + rx_bytes(64), tx_bytes(64), rx_dropped(64), tx_dropped(64), + rx_errors(64), tx_errors(64), rx_frame_err(64), rx_over_err(64), + rx_crc_err(64), collisions(64) = 104 Bytes + """ + count = len(packet[0:]) - 4 + ports = [] + while (count > 0): + flow_raw = packet[start:start+104] + flow = unpack('!H6sQQQQQQQQQQQQ', flow_raw) + + eport = OFP_STAT_PORT() + eport.port_number = flow[0] + eport.pad = flow[1] + eport.rx_packets = flow[2] + eport.tx_packets = flow[3] + eport.rx_bytes = flow[4] + eport.tx_bytes = flow[5] + eport.rx_dropped = flow[6] + eport.tx_dropped = flow[7] + eport.rx_errors = flow[8] + eport.tx_errors = flow[9] + eport.rx_frame_err = flow[10] + eport.rx_over_err = flow[11] + eport.rx_crc_err = flow[12] + eport.collisions = flow[13] + + ports.append(eport) + del eport + + count = count - 104 + start = start + 104 + + msg.instantiate(ports) + + elif msg.stat_type == 5: + """ Parses Queue(5) + Fields: length(16), pad(16), queue_id(32), tx_bytes(64), + tx_packets(64), tx_errors(64) = Bytes 32 + """ + + count = len(packet[0:]) - 4 + queues = [] + while (count > 0): + flow_raw = packet[start:start+32] + flow = unpack('!HHLQQQ', flow_raw) + queue = {'length': flow[0], 'pad': flow[1], 'queue_id': flow[2], + 'tx_bytes': flow[3], 'tx_packets': flow[4], + 'tx_errors': flow[5], 'type': stat_type} + queues.append(queue) + count = count - 32 + start = start + 32 + + msg.instantiate(queues) + # elif msg.stat_type == 65535: # # Vendor # # Fields: vendor_id(32), data(?) diff --git a/of10/prints.py b/of10/prints.py index 9d4c3c4..dac447d 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -408,10 +408,10 @@ def print_ofp_statRes(msg): print_ofp_statResFlowArray(msg) elif msg.stat_type == 2: print_ofp_statResAggregate(msg) - # elif msg.stat_type == 3: - # print_ofp_statResTable(msg) - # elif msg.stat_type == 4: - # print_ofp_statResPortArray(msg) + elif msg.stat_type == 3: + print_ofp_statResTable(msg) + elif msg.stat_type == 4: + print_ofp_statResPortArray(msg) # elif msg.stat_type == 5: # print_ofp_statResQueue(msg) # elif msg.stat_type == 65535: @@ -433,7 +433,6 @@ def print_ofp_statResFlowArray(msg): return for flow in msg.stats.flows: - print_ofp_statResFlow(flow) @@ -464,34 +463,35 @@ def print_ofp_statResAggregate(msg): def print_ofp_statResTable(msg): - res_flow = pkt.of_body['print_ofp_statResTable'] - print ('StatRes Type: Table(%s)' % (res_flow['type'])) + print ('StatRes Type: Table(3)') print ('StatRes table_id: %s, pad: %s, name: "%s", wildcards: %s, ' 'max_entries: %s, active_count: %s, lookup_count: %s, ' 'matched_count: %s' % - (res_flow['table_id'], res_flow['pad'], - res_flow['name'], hex(res_flow['wildcards']), - res_flow['max_entries'], res_flow['active_count'], - res_flow['lookup_count'], res_flow['matched_count'])) + (msg.table_id, msg.pad, msg.name, hex(msg.wildcards), + msg.max_entries, msg.active_count, + msg.lookup_count, msg.matched_count)) -def print_ofp_statResPortArray(pkt): - for port_stats in pkt.of_body['print_ofp_statResPortArray']: - print_ofp_statResPort(port_stats) +def print_ofp_statResPortArray(msg): + if len(msg.stats.ports) == 0: + print ('StatRes Type: Port(4)\nNo Ports') + return + for port in msg.stats.ports: + print_ofp_statResPort(port) def print_ofp_statResPort(port): - print ('StatRes Type: Port(%s)' % (port['type'])) - print ('StatRes port_no: %s rx_packets: %s rx_bytes: %s rx_errors: %s' + print ('StatRes Type: Port(4)') + print ('StatRes port_number: %s rx_packets: %s rx_bytes: %s rx_errors: %s' ' rx_crc_err: %s rx_dropped: %s rx_over_err: %s rx_frame_err: %s\n' - 'StatRes port_no: %s tx_packets: %s tx_bytes: %s tx_errors: %s' + 'StatRes port_number: %s tx_packets: %s tx_bytes: %s tx_errors: %s' ' tx_dropped: %s collisions: %s pad: %s' % - (red(port['port_no']), port['rx_packets'], - port['rx_bytes'], port['rx_errors'], port['rx_crc_err'], - port['rx_dropped'], port['rx_over_err'], - port['rx_frame_err'], red(port['port_no']), - port['tx_packets'], port['tx_bytes'], port['tx_errors'], - port['tx_dropped'], port['collisions'], port['pad'])) + (red(port.port_number), port.rx_packets, + port.rx_bytes, port.rx_errors, port.rx_crc_err, + port.rx_dropped, port.rx_over_err, + port.rx_frame_err, red(port.port_number), + port.tx_packets, port.tx_bytes, port.tx_errors, + port.tx_dropped, port.collisions, port.pad)) def print_ofp_statResQueueArray(pkt): From a962c8f25324fcb53aee3b871752ec14d924e7cc Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Thu, 14 Apr 2016 22:53:59 -0400 Subject: [PATCH 22/88] Finished STAT_RES and QUEUEs. Next step: handle TODO list and test everything before starting with OF1.3 --- TODO | 2 + of10/packet.py | 61 ++++++++++++++++----- of10/parser.py | 146 ++++++++++++++++++++++++++++--------------------- of10/prints.py | 93 ++++++++++++++++--------------- 4 files changed, 180 insertions(+), 122 deletions(-) diff --git a/TODO b/TODO index 1a2abac..472773c 100644 --- a/TODO +++ b/TODO @@ -10,4 +10,6 @@ how to handle data? packetOut - data how to handle data? +Test all STAT_REPLY, QUEUE +add to the requirement' list: sudo pip install hexdump diff --git a/of10/packet.py b/of10/packet.py index 1919856..873b0ec 100644 --- a/of10/packet.py +++ b/of10/packet.py @@ -403,7 +403,7 @@ def process_msg(self, packet): parser.parse_QueueGetConfigReq(self, packet) def prints(self): - pass + prints.print_queueReq(self) class OFPT_QUEUE_GET_CONFIG_RES(OFPHeader): @@ -412,13 +412,13 @@ def __init__(self, of_header): OFPHeader.__init__(self, of_header) self.port = None self.pad = [] # 0 - 6 Bytes - self.queues = [] # Class ofp_packet_queue + self.queues = [] # Class OFP_QUEUE[] def process_msg(self, packet): parser.parse_QueueGetConfigRes(self, packet) def prints(self): - pass + prints.print_queueRes(self) # Auxiliary Data Structures @@ -540,25 +540,20 @@ class OFP_STATRES_PORT: def __init__(self, ports): self.ports = ports # Class OFP_STAT_PORT[] + class OFP_STATRES_QUEUE: - def __init__(self, length, pad, queue_id, tx_bytes, tx_packets, - tx_errors): - self.length = length - self.pad = pad - self.queue_id = queue_id - self.tx_bytes = tx_bytes - self.tx_packets = tx_packets - self.tx_errors = tx_errors + def __init__(self, queues): + self.queues = queues # Class OFP_STAT_QUEUE[] + class OFP_STATRES_VENDOR: - def __init__(self, vendor_id): + def __init__(self, vendor_id, data): self.vendor_id = vendor_id + self.data = data -### STAT_RES Auxiliary Classes #### - class OFP_STAT_FLOW: def __init__(self): @@ -594,4 +589,40 @@ def __init__(self): self.rx_frame_err = None self.rx_over_err = None self.rx_crc_err = None - self.collisions = None \ No newline at end of file + self.collisions = None + + +class OFP_STAT_QUEUE: + + def __init__(self): + self.length = None + self.pad = None + self.queue_id = None + self.tx_bytes = None + self.tx_packets = None + self.tx_errors = None + + +class OFP_QUEUE: + + def __init__(self): + self.queue_id = None + self.length = None + self.pad = None + self.properties = None + + +class OFP_QUEUE_PROPERTIES: + + def __init__(self): + self.property = None + self.length = None + self.pad = None + self.payload = None + + +class OFP_QUEUE_PROP_PAYLOAD: + + def __init__(self): + self.rate = None + self.pad = None \ No newline at end of file diff --git a/of10/parser.py b/of10/parser.py index b1a55ca..1473677 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -16,6 +16,8 @@ from of10.packet import OFP_Match from of10.packet import OFP_STAT_FLOW from of10.packet import OFP_STAT_PORT +from of10.packet import OFP_STAT_QUEUE +from of10.packet import OFP_QUEUE, OFP_QUEUE_PROPERTIES, OFP_QUEUE_PROP_PAYLOAD # *************** Hello ***************** @@ -539,9 +541,16 @@ def parse_PortMod(msg, packet): # ******************** StatReq **************************** def parse_StatsReq(msg, packet): - ''' - Process the StatsReq - ''' + """ Parse StatReq messages + + Args: + msg: + packet: + + Returns: + + """ + # Get type = 16bits # Get flags = 16bits of_stat_req = packet[0:4] @@ -757,42 +766,38 @@ def parse_StatsRes(msg, packet): count = len(packet[0:]) - 4 queues = [] - while (count > 0): + while count > 0: flow_raw = packet[start:start+32] flow = unpack('!HHLQQQ', flow_raw) - queue = {'length': flow[0], 'pad': flow[1], 'queue_id': flow[2], - 'tx_bytes': flow[3], 'tx_packets': flow[4], - 'tx_errors': flow[5], 'type': stat_type} + + queue = OFP_STAT_QUEUE() + queue.length = flow[0] + queue.pad = flow[1] + queue.queue_id = flow[2] + queue.tx_bytes = flow[3] + queue.tx_packets = flow[4] + queue.tx_errors = flow[5] queues.append(queue) + count = count - 32 start = start + 32 + del queue msg.instantiate(queues) - # elif msg.stat_type == 65535: - # # Vendor - # # Fields: vendor_id(32), data(?) - # flow_raw = pkt.packet[start:start+4] - # flow = unpack('!L', flow_raw) - # vendor_flow = {'type': stat_type, 'vendor_id': flow[0]} - # pkt.prepare_printing('print_ofp_statResVendor', vendor_flow) - # - # pkt.prepare_printing('print_ofp_statResVendorData', - # pkt.packet[start+4:]) - # # start = start + 4 - # # data = [] - # # count = len(packet[0:]) - # - # # import hexdump - # # hexdump.hexdump(pkt.packet[start:]) - # # print - # # while (start < count): - # # flow_raw = pkt.packet[start:start+1] - # # flow = unpack('!B', flow_raw) - # # data.append(str(flow[0])) - # # start = start + 1 - # # pkt.prepare_printing('print_ofp_statResVendorData', ''.join(data)) - # + elif msg.stat_type == 65535: + """ + Parse STAT_RES Vendor message + Fields: vendor_id(32), data(?) + """ + + flow_raw = packet[start:start+4] + flow = unpack('!L', flow_raw) + vendor_id = flow[0] + data = packet[start+4:] + + msg.instantiate(vendor_id, data) + else: print ('StatRes: Unknown Type: %s' % (msg.stat_type)) return 1 @@ -812,41 +817,56 @@ def parse_BarrierRes(msg, packet): def parse_QueueGetConfigReq(msg, packet): queue_raw = packet[0:4] queue = unpack('!HH', queue_raw) - queueConfReq = {'port': queue[0], 'pad': queue[1]} - # pkt.prepare_printing('print_queueReq', queueConfReq) - return 1 + msg.port = queue[0] + msg.pad = queue[1] # ****************** QueueGetConfigRes ******************** def parse_QueueGetConfigRes(msg, packet): queue_raw = packet[0:8] queue = unpack('!H6s', queue_raw) - queueConfRes = {'port': queue[0], 'pad': queue[1]} - - # pkt.prepare_printing('print_queueRes', queueConfRes) - # - # start = 8 - # while (pkt.packet[start:] > 0): - # # Queues - it could be multiple - # # queue_id(32), length(16), pad(16) - # queue_raw = pkt.packet[start:start+8] - # queue = unpack('!LHH', queue_raw) - # queues = {'queue_id': queue[0], 'length': queue[1], 'pad': queue[2]} - # of10.prints.print_queues(queues) - - # q_start = start + 8 - # - # # Look of properties - # # property(16), length(16), pad(32), rate(16), pad(48) - # properties = pkt.packet[q_start:q_start+queues['length']-8] - # - # while (len(properties[q_start:]) > 0): - # prop_raw = pkt.packet[q_start:q_start+8] - # prop = unpack('!HHLH6s', prop_raw) - # properties = {'type': prop[0], 'length': prop[1], - # 'pad': prop[2], 'rate': prop[3], 'pad2': prop[4]} - # of10.prints.print_queueRes_properties(properties) - # - # start = start + queues['length'] - # - # return 1 + msg.port = queue[0] + msg.pad = queue[1] + + start = 8 + queues = [] + while (packet[start:] > 0): + # Queues - it could be multiple + # queue_id(32), length(16), pad(16) + queue_raw = packet[start:start+8] + queue = unpack('!LHH', queue_raw) + + equeue = OFP_QUEUE() + equeue.queue_id = queue[0] + equeue.length = queue[1] + equeue.pad = queue[2] + + q_start = start + 8 + + # Look of properties + # property(16), length(16), pad(32), rate(16), pad(48) + properties = packet[q_start:q_start+equeue.length-8] + properties_list = [] + + while (len(properties[q_start:]) > 0): + prop_raw = packet[q_start:q_start+8] + prop = unpack('!HHLH6s', prop_raw) + + property = OFP_QUEUE_PROPERTIES() + property.property = prop[0] + property.length = prop[1] + property.pad = prop[2] + property.payload = OFP_QUEUE_PROP_PAYLOAD() + property.payload.rate = prop[3] + property.payload.pad = prop[4] + + properties_list.append(property) + del property + + equeue.properties = properties_list + + start = start + equeue.length + + queues.append(equeue) + + msg.queues = queues diff --git a/of10/prints.py b/of10/prints.py index dac447d..44e2d8c 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -1,6 +1,7 @@ ''' Prints for OpenFlow 1.0 only ''' +from hexdump import hexdump import of10.dissector import of10.parser import gen.prints @@ -8,6 +9,7 @@ import gen.tcpip + def red(string): return gen.prints.red(string) @@ -412,10 +414,10 @@ def print_ofp_statRes(msg): print_ofp_statResTable(msg) elif msg.stat_type == 4: print_ofp_statResPortArray(msg) - # elif msg.stat_type == 5: - # print_ofp_statResQueue(msg) - # elif msg.stat_type == 65535: - # print_ofp_statResVendor(msg) + elif msg.stat_type == 5: + print_ofp_statResQueueArray(msg) + elif msg.stat_type == 65535: + print_ofp_statResVendor(msg) def print_ofp_statResDesc(msg): @@ -494,37 +496,32 @@ def print_ofp_statResPort(port): port.tx_dropped, port.collisions, port.pad)) -def print_ofp_statResQueueArray(pkt): - queues = pkt.of_body['print_ofp_statResQueueArray'] - if len(queues) == 0: +def print_ofp_statResQueueArray(msg): + if len(msg.queues) == 0: print 'StatRes Type: Queue(5)\nNo Queues' return - for queue_stats in queues: - print_ofp_statResQueue(queue_stats) + for queue in msg.queues: + print_ofp_statResQueue(queue) def print_ofp_statResQueue(queue): - print ('StatRes Type: Queue(%s)' % (queue['type'])) + print 'StatRes Type: Queue(5)' print ('StatRes queue_id: %s length: %s pad: %s' ' tx_bytes: %s tx_packets: %s tx_errors: %s' % - (queue['queue_id'], queue['length'], queue['pad'], - queue['tx_bytes'], queue['tx_packets'], - queue['tx_errors'])) + (queue.queue_id, queue.length, queue.pad, + queue.tx_bytes, queue.tx_packets, queue.tx_errors)) -def print_ofp_statResVendor(pkt): - vendor = pkt.of_body['print_ofp_statResVendor'] - print ('StatRes Type: Vendor(%s)' % (vendor['type'])) - print ('StatRes vendor_id: %s' % (vendor['vendor_id'])) +def print_ofp_statResVendor(msg): + print ('StatRes Type: Vendor(%s)' % (hex(65535))) + print ('StatRes vendor_id: %s' % (msg.stats.vendor_id)) + print_ofp_statResVendorData(msg.stats.data) -def print_ofp_statResVendorData(pkt): - data = pkt.of_body['print_ofp_statResVendorData'] - # print 'StatRes Vendor Data: %s' % (data) +def print_ofp_statResVendorData(data): print ('StatRes Vendor Data: ') - import hexdump - hexdump.hexdump(data) + hexdump(data) def print_ofp_getConfigRes(msg): @@ -562,11 +559,6 @@ def print_packetInOut_vlan(of_xid, vlan): gen.prints.print_vlan(vlan) -def print_data(data): - # what to do with data? - pass - - def print_of_packetIn(msg): print ('PacketIn: buffer_id: %s total_len: %s in_port: %s reason: %s ' 'pad: %s' % @@ -580,32 +572,45 @@ def print_of_packetOut(msg): (hex(msg.buffer_id), green(of10.dissector.get_phy_port_id(msg.in_port)), msg.actions_len)) print_actions(msg.actions) - # print_data(msg.data) + print_data(msg.data) + + +def print_data(data): + # what to do with data? + pass -def print_queueReq(pkt): - queueConfReq = pkt.of_body['print_queueReq'] +def print_queueReq(msg): print ('QueueGetConfigReq Port: %s Pad: %s' % - (queueConfReq['port'], queueConfReq['pad'])) + (msg.port, msg.pad)) -def print_queueRes(pkt): - queueConfRes = pkt.of_body['print_queueRes'] +def print_queueRes(msg): print ('QueueGetConfigRes Port: %s Pad: %s' % - (queueConfRes['port'], queueConfRes['pad'])) + (msg.port, msg.pad)) + if len(msg.queues) == 0: + print 'QueueGetConfigRes: No Queues' + return + for queue in msg.queues: + print_queueRes_queue(queue) -def print_queueRes_queues(of_xid, queues): - print ('%s Queue_ID: %s Length: %s Pad: %s' % - (of_xid, queues['queue_id'], queues['length'], queues['pad'])) +def print_queueRes_queue(queue): + print ('Queue_ID: %s Length: %s Pad: %s' % + (queue.queue_id, queue.length, queue.pad)) + if len(queue.properties) == 0: + print 'QueueGetConfigRes: No Properties' + return + for property in queue.properties: + print_queueRes_properties(property) -def print_queueRes_properties(of_xid, properties): - print ('%s Property: %s Length: %s Pad: %s Rate: %s Pad: %s' % - (of_xid, properties['type'], properties['length'], properties['pad'], - properties['rate'], properties['pad2'])) +def print_queueRes_properties(property): + print ('Property: %s Length: %s Pad: %s' % + (property.property, property.length, property.pad)) + print_queueRes_prop_payload(property.payload) -def print_body(pkt): - for f in pkt.printing_seq: - eval(f)(pkt) +def print_queueRes_prop_payload(payload): + print ('Payload: Rate %s Pad: %s' % + (payload.rate, payload.pad)) From 8ec52e2687da133f8e051a702502625c029b8ce3 Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Sun, 1 May 2016 01:45:23 -0400 Subject: [PATCH 23/88] Classes for TCP/IP created. PacketOut and PacketIn printing data. Filters per OpenFlow type in place. --- .idea/webServers.xml | 15 +++ README.md | 5 +- TODO | 9 +- __init__.py | 20 ++-- example_filter.json | 2 +- gen/__init__.py | 16 +-- gen/cli.py | 2 +- gen/filters.py | 20 ++-- gen/packet.py | 205 +++++++++++++++----------------- gen/prints.py | 134 +-------------------- gen/proxies.py | 19 ++- gen/tcpip.py | 242 -------------------------------------- of10/__init__.py | 17 ++- of10/parser.py | 150 ++++++++++++------------ of10/prints.py | 101 +++++++--------- of13/__init__.py | 19 ++- of13/prints.py | 20 ++-- ofp_sniffer.py | 35 +++--- tcpiplib/__init__.py | 9 ++ tcpiplib/packet.py | 270 +++++++++++++++++++++++++++++++++++++++++++ tcpiplib/prints.py | 210 +++++++++++++++++++++++++++++++++ tcpiplib/tcpip.py | 54 +++++++++ 22 files changed, 858 insertions(+), 716 deletions(-) create mode 100644 .idea/webServers.xml delete mode 100644 gen/tcpip.py create mode 100644 tcpiplib/__init__.py create mode 100644 tcpiplib/packet.py create mode 100644 tcpiplib/prints.py create mode 100644 tcpiplib/tcpip.py diff --git a/.idea/webServers.xml b/.idea/webServers.xml new file mode 100644 index 0000000..7b50d76 --- /dev/null +++ b/.idea/webServers.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 4982f1d..7e9ba4f 100644 --- a/README.md +++ b/README.md @@ -48,10 +48,11 @@ Usage: ##################### Instalation ###################### ``` Required Python 2.7 (2.6 works but with issues) -apt-get install python-pcapy or yum install pcapy +apt-get install python-pcapy python-pip or yum install pcapy python-pip +pip install hexdump git clone https://github.com/jab1982/ofp_sniffer.git cd ofp_sniffer -git checkout 0.2 +git checkout 0.3 sudo ./ofp_sniffer.py ``` ##################### Examples ######################### diff --git a/TODO b/TODO index 472773c..36c1193 100644 --- a/TODO +++ b/TODO @@ -1,15 +1,8 @@ TODO: Print data from Hello, EchoReq, EchoRes + Handle Vendor Handle Pads -packetIn - data -how to handle data? - -packetOut - data -how to handle data? - Test all STAT_REPLY, QUEUE - -add to the requirement' list: sudo pip install hexdump diff --git a/__init__.py b/__init__.py index 86f35cb..a7b2ac2 100644 --- a/__init__.py +++ b/__init__.py @@ -1,13 +1,7 @@ -import gen.cli -import gen.packet -import gen.prints -import gen.proxies -import gen.tcpip -import gen.termcolor -import of10.dissector -import of10.parser -import of10.prints -import of10.vendors -import of10.dissector -import of13.parser -import of13.prints +# Package gen - general package + +# Package of10 - everything specific to OpenFlow 1.0 + +# Package of13 - everything specific to OpenFlow 1.3 + +# Package tcpiplib - everything specific to the TCPIP stack diff --git a/example_filter.json b/example_filter.json index 72861b9..34e839c 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,7 +2,7 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 10, 14, 15, 16, 18, 19 ] }, "1.3": { diff --git a/gen/__init__.py b/gen/__init__.py index 86f35cb..532e200 100644 --- a/gen/__init__.py +++ b/gen/__init__.py @@ -1,13 +1,13 @@ +# Package gen - general package import gen.cli +import gen.filters import gen.packet import gen.prints import gen.proxies -import gen.tcpip import gen.termcolor -import of10.dissector -import of10.parser -import of10.prints -import of10.vendors -import of10.dissector -import of13.parser -import of13.prints + +# Package of10 - everything specific to OpenFlow 1.0 + +# Package of13 - everything specific to OpenFlow 1.3 + +# Package tcpiplib - everything specific to the TCPIP stack diff --git a/gen/cli.py b/gen/cli.py index d982ac9..c74cee3 100644 --- a/gen/cli.py +++ b/gen/cli.py @@ -4,7 +4,7 @@ import pcapy -VERSION = '0.3-dev' +VERSION = '0.3a-dev' NO_COLOR = False diff --git a/gen/filters.py b/gen/filters.py index a1be6f8..84a3093 100644 --- a/gen/filters.py +++ b/gen/filters.py @@ -1,33 +1,33 @@ ''' Filters to be used ''' -import gen.tcpip +import tcpiplib.tcpip -def filter_OF_version(pkt): +def filter_of_version(msg): # Was -F submitted? - if pkt.print_options['filters'] is 0: + if msg.print_options['filters'] is 0: return False # Check if the OpenFlow version is allowed - name_version = gen.tcpip.get_ofp_version(pkt.of_h['version']) + name_version = tcpiplib.tcpip.get_ofp_version(msg.of_h['version']) supported_versions = [] - for version in pkt.sanitizer['allowed_of_versions']: + for version in msg.sanitizer['allowed_of_versions']: supported_versions.append(version) if name_version not in supported_versions: return True return False -def filter_OF_type(pkt): +def filter_of_type(msg): # Was -F submitted? - if pkt.print_options['filters'] is 0: + if msg.print_options['filters'] is 0: return False - name_version = gen.tcpip.get_ofp_version(pkt.of_h['version']) + name_version = tcpiplib.tcpip.get_ofp_version(msg.ofp.version) # OF Types to be ignored through json file (-F) - rejected_types = pkt.sanitizer['allowed_of_versions'][name_version] - if pkt.of_h['type'] in rejected_types['rejected_of_types']: + rejected_types = msg.sanitizer['allowed_of_versions'][name_version] + if msg.ofp.type in rejected_types['rejected_of_types']: return True return False diff --git a/gen/packet.py b/gen/packet.py index 8e50357..481eced 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -1,13 +1,16 @@ -from gen.tcpip import get_ethernet_frame, get_ip_packet, get_tcp_stream, \ - get_openflow_header -# from of13.parser import process_ofp_type13 -import gen.prints -import of10.prints +""" + This module defines two main classes: + class OFMessage: used to process EACH OpenFlow message from the + IP packet + class Packet: used to process EACH IP packet. Each IP packet + might have multiple OpenFlow messages (class OFMessage) +""" import gen.filters -import of13.prints - -# new approach import of10.packet +import tcpiplib.packet +import tcpiplib.prints +from tcpiplib.tcpip import get_openflow_header +import gen.proxies IP_PROTOCOL = 8 @@ -18,40 +21,38 @@ class OFMessage: """ - Used to all all data regarding an OpenFlow message + Used to process all data regarding this OpenFlow message """ def __init__(self, pkt): self.main_packet = pkt self.packet = pkt.this_packet - self.of_h = {} - self.of_body = {} - self.printing_seq = [] self.offset = 0 self.print_options = self.main_packet.print_options self.sanitizer = self.main_packet.sanitizer # self.message = None - # new approad + # ofp is the real OpenFlow message self.ofp = None - def seq_of_print(self, function): - self.printing_seq.append(function) - - def process_openflow_header(self): - # remove line below - self.of_h = get_openflow_header(self.packet, self.offset) - # keep line below - of_header = get_openflow_header(self.packet, self.offset) - # instantiate packet + def process_openflow_header(self, of_header): + """ + This method instantiate the class equivalent to the OpenFlow + message type. + Args: + of_header: dictionary of the OpenFlow header + + Returns: + 0: message type unknown or OpenFlow version non-dissected + 1: No error + """ if of_header['version'] is 1: self.ofp = of10.packet.instantiate(self, of_header) - # If type is not recognized, return 0 if type(self.ofp) is type(int()): print 'Debug: Type not recognized' self.offset += 8 self.packet = self.packet[8:] return 0 - # elif self.of_h is 4: + # elif of_header['version'] is 4: # of13.packet.instantiate_class(self) else: return 0 @@ -60,52 +61,52 @@ def process_openflow_header(self): self.packet = self.packet[8:] return 1 - def handle_malformed_pkts(self): + def handle_malformed_pkts(self, exception): + """ + In case the OpenFlow message processing crashes, this + function tries to give some ideas of what happened + Args: + exception = generated expection + """ string = ('!!! MalFormed Packet - Packet Len: %s Informed: %s ' - 'Missing: %s Bytes - Probably Reached MTU? !!!' % - (len(self.packet), self.of_h['length'], - self.of_h['length'] - len(self.packet))) - message = {'message': string} - self.prepare_printing('print_string', message) - - def process_openflow_body(self): - if not self.process_openflow_header(): + 'Missing: %s Bytes !!!' % + (len(self.packet), self.ofp.length, + self.ofp.length - len(self.packet))) + print 'message %s\n Details about the Error:' % string + print exception + + def process_openflow_body(self, of_header): + """ + Process the OpenFlow content - starts with header + Args: + of_header: dictionary of the OpenFlow header + + Returns: + 0: Error with the OpenFlow header + 1: Success + -1: Error processing the OpenFlow content + """ + if not self.process_openflow_header(of_header): return 0 - # are those options needed? - if self.ofp.version is 1: - try: - self.ofp.process_msg(self.packet) - return 1 - except Exception as e: - print e - self.handle_malformed_pkts() - return -1 - # if self.ofp.version is 4: - # try: - # if not process_ofp_type13(self): - # # of10.prints.print_type_unknown(self) - # return 0 - # return 1 - # except: - # self.handle_malformed_pkts() - # return -1 - return 0 - - def prepare_printing(self, string, values): - self.of_body[string] = values - self.seq_of_print(string) + try: + # support for proxies + if of_header['type'] is 13: + gen.proxies.insert_ip_port(self.main_packet.l3.d_addr, + self.main_packet.l4.dest_port) + self.ofp.process_msg(self.packet) + return 1 + except Exception as exception: + self.handle_malformed_pkts(exception) + return -1 def print_packet(self, pkt): - if not gen.filters.filter_OF_type(self): + # TODO: what about the OpenFlow version filter? + if not gen.filters.filter_of_type(self): if pkt.printed_header is False: - gen.prints.print_headers(pkt) + tcpiplib.prints.print_headers(pkt) pkt.printed_header = True - gen.prints.print_openflow_header(self.ofp) - # if self.of_h['version'] is 1: - # of10.prints.print_body(self) + tcpiplib.prints.print_openflow_header(self.ofp) self.ofp.prints() - #elif self.of_h['version'] is 4: - # of13.prints.print_body(self) print @@ -121,74 +122,58 @@ def __init__(self, packet, print_options, sanitizer, ctr): self.position = ctr self.offset = 0 self.openflow_packet = False - self.qtd_of_msg = 1 self.cur_msg = 0 self.printed_header = False + self.this_packet = None + self.remaining_bytes = None # Filters self.print_options = print_options self.sanitizer = sanitizer # TCP/IP header - self.l1 = {} - self.l2 = {} - self.l3 = {} - self.l4 = {} + self.l1 = tcpiplib.packet.L1() + self.l2 = tcpiplib.packet.Ethernet() + self.l3 = tcpiplib.packet.IP() + self.l4 = tcpiplib.packet.TCP() # OpenFlow messages Array # As multiple OpenFlow messages per packet is support # an array needs to be created self.ofmsgs = [] - # Header TCP/IP - def process_header(self, captured_size, truncated_size, now): - self.process_l1(captured_size, truncated_size, now) - self.process_l2() - if self.l2['protocol'] == IP_PROTOCOL: - self.process_l3() - if self.l3['protocol'] == TCP_PROTOCOL: - self.process_l4() - if self.l4['flag_psh'] == TCP_FLAG_PUSH: + def process_packet_header(self, header, time): + """ + Process TCP/IP Header, from Layer 1 to TCP. + Each layer has a different class. Methods parse are used + per layer to dissect it + Args: + header: header of the captured packet + time: time the packet was captured + """ + self.l1.parse(header, time) + self.offset = self.l2.parse(self.packet) + if self.l2.protocol == IP_PROTOCOL: + self.offset = self.l3.parse(self.packet, self.offset) + if self.l3.protocol == TCP_PROTOCOL: + self.offset = self.l4.parse(self.packet, self.offset) + if self.l4.flag_psh == TCP_FLAG_PUSH: self.openflow_packet = True - def process_l1(self, captured_size, truncated_size, now): - self.l1 = {'caplen': captured_size, 'truncate_len': truncated_size, - 'time': now} - - def process_l2(self): - self.l2 = get_ethernet_frame(self.packet) - self.offset = self.l2['length'] - - def process_l3(self): - self.l3 = get_ip_packet(self.packet, self.offset) - self.offset += self.l3['length'] - - def process_l4(self): - self.l4 = get_tcp_stream(self.packet, self.offset) - self.offset += self.l4['length'] - def get_remaining_bytes(self): - return self.l1['caplen'] - self.offset + return self.l1.caplen - self.offset + # TODO: This method has to be removed - uses dictionaries def get_of_message_length(self): of_h = get_openflow_header(self.packet, self.offset) - return of_h['length'] - - # OpenFlow messages - @property - def of_h(self): - return self.ofmsgs[self.cur_msg].of_h - - @property - def of_body(self): - return self.ofmsgs[self.cur_msg].of_body + return of_h, of_h['length'] def process_openflow_messages(self): self.remaining_bytes = self.get_remaining_bytes() while self.remaining_bytes >= 8: # self.this_packet is the OpenFlow message # let's remove the current OpenFlow message from the packet - length = self.get_of_message_length() + of_header, length = self.get_of_message_length() if length < 8: # MalFormed Packet return 0 @@ -197,7 +182,7 @@ def process_openflow_messages(self): # Process the content, using cur_msg position of the array of msgs self.ofmsgs.insert(self.cur_msg, OFMessage(self)) - version = self.ofmsgs[self.cur_msg].process_openflow_body() + version = self.ofmsgs[self.cur_msg].process_openflow_body(of_header) if version is 0: return 0 @@ -208,13 +193,13 @@ def process_openflow_messages(self): # If there is another OpenFlow message, instantiate another OFMsg if self.remaining_bytes >= 8: self.cur_msg += 1 - self.qtd_of_msg += 1 return 1 def print_packet(self): - # fix it - #if not gen.filters.filter_OF_version(self): - + """ + This method iterate over the self.ofmsgs (array of OF messages), + printing each one of them. + """ for msg in self.ofmsgs: msg.print_packet(self) diff --git a/gen/prints.py b/gen/prints.py index ed2768f..a417a3b 100644 --- a/gen/prints.py +++ b/gen/prints.py @@ -1,20 +1,5 @@ -''' - Generic/Protocol-independent prints -''' - from gen.termcolor import colored -import of10.dissector -import of13.dissector -import gen.cli # NO_COLOR variable -import gen.proxies -import socket -import struct -import gen.tcpip - - -def debug(pkt, string): - if pkt.print_options['debug'] is 1: - print 'DEBUG: %s' % string +import gen.cli def red(string): @@ -45,120 +30,3 @@ def cyan(string): if gen.cli.NO_COLOR is True: return string return colored(string, 'cyan') - - -def eth_addr(a): - mac = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" % (ord(a[0]), ord(a[1]), ord(a[2]), - ord(a[3]), ord(a[4]), ord(a[5])) - return mac - - -def datapath_id(a): - dpid = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" % (ord(a[0]), ord(a[1]), - ord(a[2]), ord(a[3]), - ord(a[4]), ord(a[5]), - ord(a[6]), ord(a[7])) - return dpid - - -def get_ip_from_long(long_ip): - return (socket.inet_ntoa(struct.pack('!L', long_ip))) - - -def print_headers(pkt): - if pkt.print_options['min'] == 1: - print_minimal(pkt.position, pkt.l1['time'], pkt.l1['caplen'], pkt.l3, - pkt.l4) - else: - print_position(pkt.position) - print_layer1(pkt.l1['time'], pkt.l1['caplen'], pkt.l1['truncate_len']) - print_layer2(pkt.l2) - print_layer3(pkt.l3) - print_tcp(pkt.l4) - - -def print_minimal(position, date, getlen, ip, tcp): - string = 'Packet #%s - %s %s:%s -> %s:%s Size: %s Bytes' - - source = gen.proxies.get_ip_name(ip['s_addr'], tcp['source_port']) - dest = gen.proxies.get_ip_name(ip['d_addr'], tcp['dest_port']) - - print string % (position, date, cyan(source), cyan(tcp['source_port']), - cyan(dest), cyan(tcp['dest_port']), getlen) - - -def print_position(position): - print ('Position # %s' % position) - - -def print_layer1(date, getlen, caplen): - print ('%s: captured %d bytes, truncated to %d bytes' % - (date, getlen, caplen)) - - -def print_layer2(eth): - print ('Ethernet: Destination MAC: %s Source MAC: %s Protocol: %s' % - (eth_addr(eth['dst_mac']), eth_addr(eth['src_mac']), - red(gen.tcpip.get_ethertype(eth['protocol'])))) - - -def print_vlan(vlan): - print ('VLAN: Prio: %s CFI: %s VID: %s' % - (vlan['prio'], vlan['cfi'], red(vlan['vid']))) - - -def print_arp(arp): - print ('ARP: Hardware Type: %s Protocol Type: %s ' - 'HW Length: %s Prot Length: %s Opcode: %s ' - '\nARP: Source MAC: %s Source IP: %s Destination MAC: %s ' - 'Destination IP: %s' - % (arp['hw_type'], arp['prot_type'], arp['hw_len'], arp['prot_len'], - arp['opcode'], - eth_addr(arp['src_mac']), get_ip_from_long(arp['src_ip']), - eth_addr(arp['dst_mac']), get_ip_from_long(arp['dst_ip']))) - - -def print_layer3(ip): - print (('IP Version: %d IP Header Length: %d TTL: %d Protocol: %d ' - 'Source Address: %s Destination Address: %s') % - (ip['version'], (ip['ihl'] * 4), ip['ttl'], ip['protocol'], - blue(ip['s_addr']), blue(ip['d_addr']))) - - -def print_tcp(tcp): - print ('TCP Source Port: %s Dest Port: %s Sequence Number: %s ' - 'Acknowledgement: %s TCP header length: %s Flags: (CWR: %s ' - 'ECE: %s URG: %s ACK: %s PSH: %s RST: %s SYN: %s FYN: %s' % - (tcp['source_port'], tcp['dest_port'], tcp['sequence'], - tcp['acknowledgement'], (tcp['length']), tcp['flag_cwr'], - tcp['flag_ece'], tcp['flag_urg'], tcp['flag_ack'], tcp['flag_psh'], - tcp['flag_rst'], tcp['flag_syn'], tcp['flag_fyn'])) - - -def print_openflow_header(ofp): - version = gen.tcpip.get_ofp_version(ofp.version) - name_version = '%s(%s)' % (version, ofp.version) - if version == '1.0': - name = of10.dissector.get_ofp_type(ofp.type) - name_type = '%s(%s)' % (name, ofp.type) - elif version == '1.3': - name = of13.dissector.get_ofp_type(ofp.type) - name_type = '%s(%s)' % (name, ofp.type) - else: - name_type = '%s' % (ofp.type) - - print ('OpenFlow Version: %s Type: %s Length: %s XID: %s' % - (name_version, yellow(name_type), ofp.length, red(ofp.xid))) - - -def print_lldp(pkt): - lldp = pkt.of_body['print_lldp'] - print ('LLDP: Chassis Type(%s) Length: %s SubType: %s ID: %s\n' - 'LLDP: Port Type(%s) Length: %s SubType: %s ID: %s\n' - 'LLDP: TTL(%s) Length: %s Seconds: %s\n' - 'LLDP: END(%s) Length: %s' % - (lldp['c_type'], lldp['c_length'], lldp['c_subtype'], - green(lldp['c_id']), lldp['p_type'], - lldp['p_length'], lldp['p_subtype'], green(lldp['p_id']), - lldp['t_type'], lldp['t_length'], lldp['t_ttl'], - lldp['e_type'], lldp['e_length'])) diff --git a/gen/proxies.py b/gen/proxies.py index 064a26a..eeefda3 100644 --- a/gen/proxies.py +++ b/gen/proxies.py @@ -1,3 +1,5 @@ +D_ADDR = None +DEST_PORT = None NET = {} name = {"cc4e249102000000": "andes2", "cc4e249126000000": "andes1", @@ -8,15 +10,22 @@ "24389406000000": "mct01"} -def support_fsfw(pkt, lldp): +def insert_ip_port(dest_ip, dest_port): + global D_ADDR + global DEST_PORT + D_ADDR = dest_ip + DEST_PORT = dest_port + + +def support_fsfw(lldp): global NET - ip = pkt.main_packet.l3['d_addr'] - port = pkt.main_packet.l4['dest_port'] + ip = D_ADDR + port = DEST_PORT try: - dpid = lldp['c_id'].split(':')[1] + dpid = lldp.c_id.split(':')[1] except: - dpid = lldp['c_id'] + dpid = lldp.c_id name = get_name_dpid(dpid) NET[ip, port] = name return diff --git a/gen/tcpip.py b/gen/tcpip.py deleted file mode 100644 index ef59010..0000000 --- a/gen/tcpip.py +++ /dev/null @@ -1,242 +0,0 @@ -from struct import unpack -import socket - - -def get_ethernet_frame(packet, host_order=0): - # Ethernet Header has 14 bytes - eth_length = 14 - eth_header = packet[:eth_length] - dst_mac, src_mac, prot = unpack('!6s6sH', eth_header) - if not host_order: - eth_protocol = socket.ntohs(prot) - else: - eth_protocol = prot - eth_frame = {'src_mac': src_mac, 'dst_mac': dst_mac, - 'protocol': eth_protocol, 'length': eth_length} - return eth_frame - - -def get_ethertype(etype): - etypes = {8: 'IP', - 2048: 'IP', - 2054: 'ARP', - 33024: 'VLAN', - 34925: 'IPv6', - 34887: 'MPLS', - 35020: 'LLDP', - 35138: 'BBDP', - 34998: 'PRIVATE'} - try: - return '%s(%s)' % (etypes[etype], hex(etype)) - except: - return hex(etype) - - -def get_ethernet_vlan(packet): - vlan_length = 2 - vlan_pq = packet[:vlan_length] - vlan_p = unpack('!H', vlan_pq) - prio = vlan_p[0] >> 13 - cfi = (vlan_p[0] & 0x1000) >> 12 - vid = vlan_p[0] & 0xfff - vlan = {'prio': prio, 'cfi': cfi, 'vid': vid} - return vlan - - -def get_next_etype(packet): - etype_length = 2 - et = packet[:etype_length] - return unpack('!H', et)[0] - - -def get_arp(packet): - arp_raw = packet[:28] - arp = unpack('!HHBBH6sL6sL', arp_raw) - arp_frame = {'hw_type': arp[0], 'prot_type': arp[1], 'hw_len': arp[2], - 'prot_len': arp[3], 'opcode': arp[4], 'src_mac': arp[5], - 'src_ip': arp[6], 'dst_mac': arp[7], 'dst_ip': arp[8]} - return arp_frame - - -def get_ip_packet(packet, eth_length): - ''' - Returns IP Header fields - ''' - ip_min_len = 20 - ip_header = packet[eth_length:ip_min_len+eth_length] - iph = unpack('!BBHHHBBH4s4s', ip_header) - version_ihl = iph[0] - version = version_ihl >> 4 - ihl = version_ihl & 0xF - iph_length = ihl * 4 - ttl = iph[5] - protocol = iph[6] - s_addr = socket.inet_ntoa(iph[8]) - d_addr = socket.inet_ntoa(iph[9]) - ip_pkt = {'version': version, 'ihl': ihl, 'length': iph_length, - 'ttl': ttl, 'protocol': protocol, 's_addr': s_addr, - 'd_addr': d_addr} - return ip_pkt - - -def get_tcp_stream(packet, header_size): - ''' - Returns TCP Header fields - ''' - tcp_length = 20 - tcp_header = packet[header_size:header_size+tcp_length] - tcph = unpack('!HHLLBBHHH', tcp_header) - source_port = tcph[0] - dest_port = tcph[1] - sequence = tcph[2] - acknowledgement = tcph[3] - doff_reserved = tcph[4] - tcph_length = doff_reserved >> 4 - tcph_length = tcph_length * 4 - flags = tcph[5] # Ignoring Flag NS - flag_cwr = flags & 0x80 - flag_ece = flags & 0x40 - flag_urg = flags & 0x20 - flag_ack = flags & 0x10 - flag_psh = flags & 0x08 - flag_rst = flags & 0x04 - flag_syn = flags & 0x02 - flag_fyn = flags & 0x01 - tcp_stream = {'source_port': source_port, 'dest_port': dest_port, - 'sequence': sequence, 'acknowledgement': acknowledgement, - 'length': tcph_length, 'flag_cwr': flag_cwr, - 'flag_ece': flag_ece, 'flag_urg': flag_urg, - 'flag_ack': flag_ack, 'flag_psh': flag_psh, - 'flag_rst': flag_rst, 'flag_syn': flag_syn, - 'flag_fyn': flag_fyn} - return tcp_stream - - -def get_ofp_version(version): - of_versions = {0: 'Experimental', - 1: '1.0', - 2: '1.1', - 3: '1.2', - 4: '1.3', - 5: '1.4', - 6: '1.5'} - try: - return of_versions[version] - except: - return 'Unknown(%s)' % version - - -def get_openflow_header(packet, start): - ''' - Returns OpenFlow header - It is non-version aware - ''' - of_header_length = 8 - of_header = packet[start:of_header_length+start] - try: - ofh = unpack('!BBHL', of_header) - of_version = ofh[0] - of_type = ofh[1] - of_length = ofh[2] - of_xid = ofh[3] - of_header = {'version': of_version, 'type': of_type, - 'length': of_length, 'xid': of_xid} - return of_header - - except Exception as exception: - print exception - of_header['version'] = -1 - return of_header - - -def get_lldp(packet): - # Chassis - # TLV (1) + Length = 2 bytes | Sub-type = 1 Byte - chassis_raw = packet[:3] - chassis = unpack('!HB', chassis_raw) - c_type = chassis[0] >> 9 - if c_type is not 1: - return {} - c_length = chassis[0] & 0xFF - c_subtype = chassis[1] - length = c_length - 1 - # Get C_ID - chassis_raw = packet[3:3+length] - string = '!%ss' % length - chassis = unpack(string, chassis_raw) - c_id = chassis[0] - - start = 3 + length - - # Port - # TLV (2) + Length = 2 Bytes | Port_id = 1 Byte - port_raw = packet[start:start+3] - port = unpack('!HB', port_raw) - p_type = port[0] >> 9 - if p_type is not 2: - return {} - p_length = port[0] & 0xFF - p_subtype = port[1] - length = p_length - 1 - # Get P_ID - port_raw = packet[start+3:start+3+length] - # string = '!%ss' % length - if length is 1: - string = '!B' - elif length is 2: - string = '!H' - elif length is 4: - string = '!L' - else: - string = '!%ss' % length - port = unpack(string, port_raw) - p_id = port[0] - start = start + 3 + length - - # TTL - ttl_raw = packet[start:start+4] - ttl = unpack('!HH', ttl_raw) - t_type = ttl[0] >> 9 - if t_type is not 3: - return {} - t_length = ttl[0] & 0xFF - t_ttl = ttl[1] - - start = start + 4 - - # Loop to get User-Specific TLVs - while len(packet[start:]) > 2: - next_raw = packet[start:start+2] - nraw = unpack('!H', next_raw) - n_type = nraw[0] >> 9 - n_length = nraw[0] & 0xFF - length = n_length - 4 - if n_type == 0: - break - elif n_type == 127: - # We only want TLV 127, OUI a42305 (ONOS) - # Then we will look for Subtype 2 and get the content - # Skip the OUI - 3 bytes - subtype_raw = packet[start+5:start+6] - subtype = unpack('!B', subtype_raw) - if subtype[0] == 2: - content_raw = packet[start+6:start+6+length] - string = '!%ss' % length - content = unpack(string, content_raw) - c_id = content[0] - - start = start + n_length + 2 - - # END - end_raw = packet[start:start+2] - end = unpack('!H', end_raw) - e_type = end[0] >> 9 - e_length = end[0] & 0xFF - - lldp = {'c_type': c_type, 'c_length': c_length, 'c_subtype': c_subtype, - 'c_id': c_id, 'p_type': p_type, 'p_length': p_length, - 'p_subtype': p_subtype, 'p_id': p_id, 't_type': t_type, - 't_length': t_length, 't_ttl': t_ttl, 'e_type': e_type, - 'e_length': e_length} - - return lldp diff --git a/of10/__init__.py b/of10/__init__.py index 86f35cb..2b4e5ce 100644 --- a/of10/__init__.py +++ b/of10/__init__.py @@ -1,13 +1,12 @@ -import gen.cli -import gen.packet -import gen.prints -import gen.proxies -import gen.tcpip -import gen.termcolor +# Package gen - general package + +# Package of10 - everything specific to OpenFlow 1.0 import of10.dissector +import of10.packet import of10.parser import of10.prints import of10.vendors -import of10.dissector -import of13.parser -import of13.prints + +# Package of13 - everything specific to OpenFlow 1.3 + +# Package tcpiplib - everything specific to the TCPIP stack diff --git a/of10/parser.py b/of10/parser.py index 1473677..e0eebab 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -5,19 +5,13 @@ import socket import struct from struct import unpack + import gen.proxies -import gen.tcpip import of10.dissector import of10.prints import of10.vendors - -from of10.packet import OFP_Action -from of10.packet import OFP_Phy_port -from of10.packet import OFP_Match -from of10.packet import OFP_STAT_FLOW -from of10.packet import OFP_STAT_PORT -from of10.packet import OFP_STAT_QUEUE -from of10.packet import OFP_QUEUE, OFP_QUEUE_PROPERTIES, OFP_QUEUE_PROP_PAYLOAD +import tcpiplib.tcpip +import tcpiplib.packet # *************** Hello ***************** @@ -104,7 +98,7 @@ def _parse_phy_ports(packet): supported = _parse_phy_curr(phy[7]) peer = _parse_phy_curr(phy[8]) - port = OFP_Phy_port() + port = of10.packet.OFP_Phy_port() port.port_id = port_id port.hw_addr = hw_addr port.name = phy[2] @@ -161,70 +155,70 @@ def parse_SetConfig(msg, packet): # ****************** PacketIn ************************ -def process_data(pkt, start): - ''' +def process_data(packet, start, msg): + """ This funcion aims to dissect PacketIn and PacketOut data It assumes it is - Ethernet [vlan] (BDDP|LLDP|ARP|IP) [TCP|UDP] - ''' - + Ethernet [vlan] (BDDP|LLDP|ARP|IP) [TCP|UDP] + Args: + packet: class OFMessage + start: offset + Returns: + payload: array with all classes + """ + payload = [] # Ethernet - eth = gen.tcpip.get_ethernet_frame(pkt.packet[start:start+14], 1) - pkt.prepare_printing('print_layer2_pktIn', eth) + eth = tcpiplib.packet.Ethernet() + eth.parse(packet[start:start + 14], 1) + payload.append(eth) # VLAN or not - ETYPE 0x8100 or 33024 - start = start + 14 etype = '0x0000' - vlan = {} - if eth['protocol'] in [33024]: - vlan = gen.tcpip.get_ethernet_vlan(pkt.packet[start:start+2]) - pkt.prepare_printing('print_vlan', vlan) - start = start + 2 - # If VLAN exists, there is a next eth['protocol'] - etype = gen.tcpip.get_next_etype(pkt.packet[start:start+2]) - start = start + 2 + + start = start + 14 + if eth.protocol in [33024]: + """ + Frame has VLAN + """ + vlan = tcpiplib.packet.VLAN() + vlan.parse(packet[start:start + 4]) + payload.append(vlan) + etype = vlan.protocol + start = start + 4 else: - etype = eth['protocol'] + etype = eth.protocol - # LLDP - ETYPE 0x88CC or 35020 - # BBDP - ETYPE 0x8942 or 35138 - lldp = {} + # LLDP - ETYPE 0x88CC or 35020 or BBDP - ETYPE 0x8942 or 35138 if etype in [35020, 35138]: - lldp = gen.tcpip.get_lldp(pkt.packet[start:]) - if len(lldp) is 0: - message = {'message': 'LLDP Packet MalFormed'} - pkt.prepare_printing('print_string', message) + lldp = tcpiplib.packet.LLDP() + lldp.parse(packet[start:]) + if not isinstance(lldp, tcpiplib.packet.LLDP): + lldp.c_id = 0 else: - pkt.prepare_printing('print_lldp', lldp) - if pkt.of_h['type'] is 13: - gen.proxies.support_fsfw(pkt, lldp) - return - - # OESS FVD - ETYPE 0x88B6 or 34998 - if etype in [34998]: - message = {'message': 'OESS FVD'} - pkt.prepare_printing('print_string', message) - return + if msg.type is 13: + gen.proxies.support_fsfw(lldp) + payload.append(lldp) + return payload # IP - ETYPE 0x800 or 2048 if etype in [2048]: - ip = gen.tcpip.get_ip_packet(pkt.packet, start) - pkt.prepare_printing('print_layer3', ip) - if ip['protocol'] is 6: - tcp = gen.tcpip.get_tcp_stream(pkt.packet, start+ip['length']) - pkt.prepare_printing('print_tcp', tcp) - return + ip = tcpiplib.packet.IP() + ip.parse(packet, start) + payload.append(ip) + if ip.protocol is 6: + tcp = tcpiplib.packet.TCP() + tcp.parse(packet, start + ip.length) + payload.append(tcp) + return payload # ARP - ETYPE 0x806 or 2054 if etype in [2054]: - arp = gen.tcpip.get_arp(pkt.packet[start:]) - pkt.prepare_printing('print_arp', arp) - return + arp = tcpiplib.packet.ARP() + arp.parse(packet[start:]) + payload.append(arp) + return payload - string = 'Ethertype %s not dissected' % hex(eth['protocol']) - message = {'message': string} - pkt.prepare_printing('print_string', message) - return + return payload def parse_PacketIn(msg, packet): @@ -237,11 +231,9 @@ def parse_PacketIn(msg, packet): msg.in_port = p_in[2] msg.reason = reason msg.pad = p_in[4] + msg.data = process_data(packet, 10, msg) - # process data - # how to handle data? - # process_data(pkt, 10) - + return 1 # ******************** FlowRemoved *************************** def parse_FlowRemoved(msg, packet): @@ -288,7 +280,7 @@ def parse_PacketOut(msg, packet): # Actions start = 8 total = start+msg.actions_len - msg.action = _parse_OFAction(packet[start:total], 0) + msg.actions = _parse_OFAction(packet[start:total], 0) start = start + msg.actions_len @@ -297,7 +289,7 @@ def parse_PacketOut(msg, packet): return 1 # process body - # process_data(pkt, start) + msg.data = process_data(packet, start, msg) return 1 @@ -337,7 +329,7 @@ def get_ip_from_long(long_ip): def _parse_OFMatch(msg, packet, h_size): - match_tmp = OFP_Match() + match_tmp = of10.packet.OFP_Match() of_match = packet[h_size:h_size+40] ofm = unpack('!LH6s6sHBBHBBHLLHH', of_match) wildcard = ofm[0] @@ -499,13 +491,13 @@ def _parse_OFAction(packet, start): total_length = 4 ofa_action_payload = packet[start:start + total_length] - action = OFP_Action() + action = of10.packet.OFP_Action() action.type = ofa_type action.length = ofa_length action.payload = ofa_action_payload actions_list.append(action) # Next packet would start at.. - start = start + total_length + start += total_length del action else: break @@ -648,11 +640,11 @@ def parse_StatsRes(msg, packet): """ count = len(packet[0:]) - 4 flows = [] - while (count > 0): + while count > 0: flow_raw = packet[start:start+4] flow = unpack('!HBB', flow_raw) - eflow = OFP_STAT_FLOW() + eflow = of10.packet.OFP_STAT_FLOW() eflow.length = flow[0] eflow.table_id = flow[1] @@ -682,8 +674,8 @@ def parse_StatsRes(msg, packet): flows.append(eflow) - count = count - int(eflow.length) - start = start + int(eflow.length) + count -= int(eflow.length) + start += int(eflow.length) del eflow msg.instantiate(flows) @@ -730,11 +722,11 @@ def parse_StatsRes(msg, packet): """ count = len(packet[0:]) - 4 ports = [] - while (count > 0): + while count > 0: flow_raw = packet[start:start+104] flow = unpack('!H6sQQQQQQQQQQQQ', flow_raw) - eport = OFP_STAT_PORT() + eport = of10.packet.OFP_STAT_PORT() eport.port_number = flow[0] eport.pad = flow[1] eport.rx_packets = flow[2] @@ -753,8 +745,8 @@ def parse_StatsRes(msg, packet): ports.append(eport) del eport - count = count - 104 - start = start + 104 + count -= 104 + start += 104 msg.instantiate(ports) @@ -770,7 +762,7 @@ def parse_StatsRes(msg, packet): flow_raw = packet[start:start+32] flow = unpack('!HHLQQQ', flow_raw) - queue = OFP_STAT_QUEUE() + queue = of10.packet.OFP_STAT_QUEUE() queue.length = flow[0] queue.pad = flow[1] queue.queue_id = flow[2] @@ -836,7 +828,7 @@ def parse_QueueGetConfigRes(msg, packet): queue_raw = packet[start:start+8] queue = unpack('!LHH', queue_raw) - equeue = OFP_QUEUE() + equeue = of10.packet.OFP_QUEUE() equeue.queue_id = queue[0] equeue.length = queue[1] equeue.pad = queue[2] @@ -848,15 +840,15 @@ def parse_QueueGetConfigRes(msg, packet): properties = packet[q_start:q_start+equeue.length-8] properties_list = [] - while (len(properties[q_start:]) > 0): + while len(properties[q_start:] > 0): prop_raw = packet[q_start:q_start+8] prop = unpack('!HHLH6s', prop_raw) - property = OFP_QUEUE_PROPERTIES() + property = of10.packet.OFP_QUEUE_PROPERTIES() property.property = prop[0] property.length = prop[1] property.pad = prop[2] - property.payload = OFP_QUEUE_PROP_PAYLOAD() + property.payload = of10.packet.OFP_QUEUE_PROP_PAYLOAD() property.payload.rate = prop[3] property.payload.pad = prop[4] diff --git a/of10/prints.py b/of10/prints.py index 44e2d8c..6e773a1 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -2,60 +2,14 @@ Prints for OpenFlow 1.0 only ''' from hexdump import hexdump + import of10.dissector import of10.parser -import gen.prints -import gen.packet -import gen.tcpip - - - -def red(string): - return gen.prints.red(string) - - -def green(string): - return gen.prints.green(string) - - -def eth_addr(string): - return gen.prints.eth_addr(string) - - -def datapath_id(string): - return gen.prints.datapath_id(string) - - -def print_layer2(pkt): - gen.prints.print_layer2(pkt.l2) - - -def print_layer2_pktIn(pkt): - gen.prints.print_layer2(pkt.of_body['print_layer2_pktIn']) - - -def print_tcp(pkt): - gen.prints.print_tcp(pkt.of_body['print_tcp']) - - -def print_layer3(pkt): - gen.prints.print_layer3(pkt.of_body['print_layer3']) - - -def print_lldp(pkt): - gen.prints.print_lldp(pkt) - - -def print_arp(pkt): - gen.prints.print_arp(pkt.of_body['print_arp']) - - -def print_vlan(pkt): - gen.prints.print_vlan(pkt.of_body['print_vlan']) - - -def print_string(pkt): - print pkt.of_body['print_string']['message'] +import tcpiplib.prints +import tcpiplib.tcpip +from gen.prints import red, green +from tcpiplib.prints import eth_addr, datapath_id +import tcpiplib.prints def print_type_unknown(pkt): @@ -164,7 +118,7 @@ def print_ofp_match(match): elif match_item is 'wildcards': match_item_value = hex(match_item_value) elif match_item is 'dl_type': - match_item_value = gen.tcpip.get_ethertype(match_item_value) + match_item_value = tcpiplib.tcpip.get_ethertype(match_item_value) print ("%s: %s" % (match_item, green(match_item_value))), print @@ -551,33 +505,60 @@ def print_portStatus(msg): def print_packetInOut_layer2(of_xid, eth): print ('%s' % of_xid), - gen.prints.print_layer2(eth) + tcpiplib.prints.print_layer2(eth) def print_packetInOut_vlan(of_xid, vlan): print ('%s Ethernet:' % of_xid), - gen.prints.print_vlan(vlan) + tcpiplib.prints.print_vlan(vlan) def print_of_packetIn(msg): print ('PacketIn: buffer_id: %s total_len: %s in_port: %s reason: %s ' 'pad: %s' % - (hex(msg.buffer_id), msg.total_len, green(msg.in_port), green(msg.reason), - msg.pad)) + (hex(msg.buffer_id), msg.total_len, green(msg.in_port), + green(msg.reason), msg.pad)) print_data(msg.data) def print_of_packetOut(msg): print ('PacketOut: buffer_id: %s in_port: %s actions_len: %s' % - (hex(msg.buffer_id), green(of10.dissector.get_phy_port_id(msg.in_port)), + (hex(msg.buffer_id), + green(of10.dissector.get_phy_port_id(msg.in_port)), msg.actions_len)) print_actions(msg.actions) print_data(msg.data) def print_data(data): - # what to do with data? - pass + """ + Print msg.data from both PacketIn and Packetout + Args: + data: msg.data - array of protocols + """ + next_protocol = '0x0000' + eth = data.pop(0) + tcpiplib.prints.print_layer2(eth) + next_protocol = eth.protocol + if next_protocol in [33024]: + vlan = data.pop(0) + tcpiplib.prints.print_vlan(vlan) + next_protocol = vlan.protocol + + if next_protocol in [35020, 35138]: + lldp = data.pop(0) + tcpiplib.prints.print_lldp(lldp) + elif next_protocol in [34998]: + print 'OESS FVD' + elif next_protocol in [2048]: + ip = data.pop(0) + tcpiplib.prints.print_layer3(ip) + if ip.protocol is 6: + tcp = data.pop(0) + tcpiplib.prints.print_tcp(tcp) + elif next_protocol in [2054]: + arp = data.pop(0) + tcpiplib.prints.print_arp(arp) def print_queueReq(msg): diff --git a/of13/__init__.py b/of13/__init__.py index 86f35cb..2ff27ba 100644 --- a/of13/__init__.py +++ b/of13/__init__.py @@ -1,13 +1,10 @@ -import gen.cli -import gen.packet -import gen.prints -import gen.proxies -import gen.tcpip -import gen.termcolor -import of10.dissector -import of10.parser -import of10.prints -import of10.vendors -import of10.dissector +# Package gen - general package + +# Package of10 - everything specific to OpenFlow 1.0 + +# Package of13 - everything specific to OpenFlow 1.3 +import of13.dissector import of13.parser import of13.prints + +# Package tcpiplib - everything specific to the TCPIP stack diff --git a/of13/prints.py b/of13/prints.py index d7f0de8..1009104 100644 --- a/of13/prints.py +++ b/of13/prints.py @@ -1,20 +1,20 @@ ''' OpenFlow 1.3 prints ''' -import gen.prints import of13.dissector +import tcpiplib.prints def red(string): - return gen.prints.red(string) + return tcpiplib.prints.red(string) def green(string): - return gen.prints.green(string) + return tcpiplib.prints.green(string) def datapath_id(string): - return gen.prints.datapath_id(string) + return tcpiplib.prints.datapath_id(string) def print_string(pkt): @@ -123,7 +123,7 @@ def print_match_oxm(oxm): oxm['value'] = of13.dissector.get_phy_port_id(oxm['value']) # DL_DST or DL_SRC elif oxm['field'] in [3, 4, 24, 25, 32, 33]: - print green(gen.prints.eth_addr(oxm['value'])) + print green(tcpiplib.prints.eth_addr(oxm['value'])) return # DL_TYPE elif oxm['field'] in [5]: @@ -136,7 +136,7 @@ def print_match_oxm(oxm): oxm['value'] = oxm['value'] & 0xfff # NW_SRC or NW_DST elif oxm['field'] in [11, 12, 22, 23]: - oxm['value'] = gen.prints.get_ip_from_long(oxm['value']) + oxm['value'] = tcpiplib.prints.get_ip_from_long(oxm['value']) # IPv6 Extensions elif oxm['field'] in [39]: extensions = of13.parser.parse_ipv6_extension_header(oxm['values']) @@ -147,11 +147,11 @@ def print_match_oxm(oxm): elif oxm['hasmask'] == 1: if oxm['field'] in [3, 4, 24, 25]: - oxm['value'] = gen.prints.eth_addr(oxm['value']) - oxm['mask'] = gen.prints.eth_addr(oxm['mask']) + oxm['value'] = tcpiplib.prints.eth_addr(oxm['value']) + oxm['mask'] = tcpiplib.prints.eth_addr(oxm['mask']) if oxm['field'] in [11, 12, 22, 23]: - oxm['value'] = gen.prints.get_ip_from_long(oxm['value']) - oxm['mask'] = gen.prints.get_ip_from_long(oxm['mask']) + oxm['value'] = tcpiplib.prints.get_ip_from_long(oxm['value']) + oxm['mask'] = tcpiplib.prints.get_ip_from_long(oxm['mask']) print ('%s/%s' % (green(oxm['value']), green(oxm['mask']))) diff --git a/ofp_sniffer.py b/ofp_sniffer.py index fab9545..24edb93 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -1,18 +1,15 @@ #!/usr/bin/env python """ - This code acts as an OpenFlow troubleshoot toolkit: it acts as a sniffer, - a topology validator and as an OpenFlow message checker, to make sure the + This code acts as an OpenFlow troubleshoot toolkit: it acts as a sniffer + and as an OpenFlow message checker, to make sure the ONF standards are being followed. - Despite of ONF standards, this code also supports OpenVSwitch/NICIRA - OpenFlow type. - More info on how to use it: www.sdn.amlight.net Current version: 0.3 - Author: Jeronimo Bezerra + Author: Jeronimo Bezerra """ import datetime @@ -25,11 +22,20 @@ def process_packet(header, packet): - global ctr + """ + Every packet captured by cap.loop is then processed here. + If packets are bigger than 62, we process. If it is 0, means there is + no more packets. If it is something in between, it is a fragment, + just ignore. + Args: + header: header of the captured packet + packet: packet captured from file or interface + """ + global ctr # packet counter if len(packet) >= 62: time = datetime.datetime.now() pkt = Packet(packet, print_options, sanitizer, ctr) - pkt.process_header(header.getlen(), header.getcaplen(), time) + pkt.process_packet_header(header, time) if pkt.openflow_packet: result = pkt.process_openflow_messages() if result is 1: @@ -42,17 +48,18 @@ def process_packet(header, packet): def main(argv): """ - This is the main function + This is how it starts: cap.loop continuously capture packets w/ pcapy + print_options and sanitizer are global variables """ cap.loop(-1, process_packet) - return - -if __name__ == "__main__": # try: - cap, print_options, sanitizer = gen.cli.get_params(sys.argv) - main(sys.argv) +# cap.loop(-1, process_packet) # except KeyboardInterrupt: # print 'Exiting...' # sys.exit(0) # except Exception as exception: # print exception + +if __name__ == "__main__": + cap, print_options, sanitizer = gen.cli.get_params(sys.argv) + main(sys.argv) \ No newline at end of file diff --git a/tcpiplib/__init__.py b/tcpiplib/__init__.py new file mode 100644 index 0000000..1dee2d6 --- /dev/null +++ b/tcpiplib/__init__.py @@ -0,0 +1,9 @@ +# Package gen - general package +import tcpiplib.tcpip + +# Package of10 - everything specific to OpenFlow 1.0 + +# Package of13 - everything specific to OpenFlow 1.3 + +# Package tcpiplib - everything specific to the TCPIP stack +import tcpiplib.packet \ No newline at end of file diff --git a/tcpiplib/packet.py b/tcpiplib/packet.py new file mode 100644 index 0000000..0dbf7fe --- /dev/null +++ b/tcpiplib/packet.py @@ -0,0 +1,270 @@ +""" + Module to define classes in use by the TCP/IP stack +""" + +from struct import unpack +import socket + + +class L1: + """ + Class to manage L1 fields + """ + def __init__(self): + self.caplen = None + self.truncate = None + self.time = None + + def parse(self, header, time): + self.caplen = header.getlen() + self.truncate = header.getcaplen() + self.time = time + + +class Ethernet: + """ + Class to manage Ethernet fields + """ + def __init__(self): + + self.src_mac = None + self.dst_mac = None + self.protocol = None + self.length = 14 # Ethernet Header has 14 bytes + + def parse(self, packet, host_order=0): + eth_raw = packet[:self.length] + ethernet = unpack('!6s6sH', eth_raw) + self.dst_mac = ethernet[0] + self.src_mac = ethernet[1] + + if not host_order: + self.protocol = socket.ntohs(ethernet[2]) + else: + self.protocol = ethernet[2] + return self.length + + +class IP: + """ + Class to manage IP fields + """ + def __init__(self): + self.version = None + self.ihl = None + self.length = 20 # Minimum length + self.ttl = None + self.protocol = None + self.s_addr = None + self.d_addr = None + + def parse(self, packet, offset): + ip_raw = packet[offset:self.length + offset] + iph = unpack('!BBHHHBBH4s4s', ip_raw) + version_ihl = iph[0] + self.version = version_ihl >> 4 + self.ihl = version_ihl & 0xF + self.length = self.ihl * 4 + self.ttl = iph[5] + self.protocol = iph[6] + self.s_addr = socket.inet_ntoa(iph[8]) + self.d_addr = socket.inet_ntoa(iph[9]) + return self.length + offset + + +class TCP: + """ + Class to manage TCP fields + """ + def __init__(self): + self.source_port = None + self.dest_port = None + self.sequence = None + self.acknowledgement = None + self.length = 20 # minimun length. + self.flag_cwr = None + self.flag_ece = None + self.flag_urg = None + self.flag_ack = None + self.flag_psh = None + self.flag_rst = None + self.flag_syn = None + self.flag_fyn = None + + def parse(self, packet, offset): + tcp_raw = packet[offset:offset + self.length] + tcph = unpack('!HHLLBBHHH', tcp_raw) + self.source_port = tcph[0] + self.dest_port = tcph[1] + self.sequence = tcph[2] + self.acknowledgement = tcph[3] + doff_reserved = tcph[4] + tcph_length = doff_reserved >> 4 + self.length = tcph_length * 4 + flags = tcph[5] # Ignoring Flag NS + self.flag_cwr = flags & 0x80 + self.flag_ece = flags & 0x40 + self.flag_urg = flags & 0x20 + self.flag_ack = flags & 0x10 + self.flag_psh = flags & 0x08 + self.flag_rst = flags & 0x04 + self.flag_syn = flags & 0x02 + self.flag_fyn = flags & 0x01 + return self.length + offset + + +class VLAN: + """ + Class to manage VLAN fields + """ + def __init__(self): + self.vid = None + self.cfi = None + self.pcp = None + self.protocol = None + self.ethertype = None + + def parse(self, packet): + vlan_length = 2 + ethertype = 2 + vlan_raw = packet[:vlan_length + ethertype] + vlan_p = unpack('!HH', vlan_raw) + self.pcp = vlan_p[0] >> 13 + self.cfi = (vlan_p[0] & 0x1000) >> 12 + self.vid = vlan_p[0] & 0xfff + self.protocol = vlan_p[1] + self.ethertype = self.protocol + + +class LLDP: + """ + Class to manage LLDP fields + """ + def __init__(self): + self.c_type = None + self.c_length = None + self.c_subtype = None + self.c_id = None + self.p_type = None + self.p_length = None + self.p_subtype = None + self.p_id = None + self.t_type = None + self.t_length = None + self.t_ttl = None + self.e_type = None + self.e_length = None + + def parse(self, packet): + # Chassis + # TLV (1) + Length = 2 bytes | Sub-type = 1 Byte + chassis_raw = packet[:3] + chassis = unpack('!HB', chassis_raw) + self.c_type = chassis[0] >> 9 + if self.c_type is not 1: + return {} + self.c_length = chassis[0] & 0xFF + self.c_subtype = chassis[1] + length = self.c_length - 1 + # Get C_ID + chassis_raw = packet[3:3 + length] + string = '!%ss' % length + chassis = unpack(string, chassis_raw) + self.c_id = chassis[0] + + start = 3 + length + + # Port + # TLV (2) + Length = 2 Bytes | Port_id = 1 Byte + port_raw = packet[start:start + 3] + port = unpack('!HB', port_raw) + self.p_type = port[0] >> 9 + if self.p_type is not 2: + return {} + self.p_length = port[0] & 0xFF + self.p_subtype = port[1] + length = self.p_length - 1 + # Get P_ID + port_raw = packet[start + 3:start + 3 + length] + # string = '!%ss' % length + if length is 1: + string = '!B' + elif length is 2: + string = '!H' + elif length is 4: + string = '!L' + else: + string = '!%ss' % length + port = unpack(string, port_raw) + self.p_id = port[0] + + start = start + 3 + length + + # TTL + ttl_raw = packet[start:start + 4] + ttl = unpack('!HH', ttl_raw) + self.t_type = ttl[0] >> 9 + if self.t_type is not 3: + return {} + self.t_length = ttl[0] & 0xFF + self.t_ttl = ttl[1] + + start += 4 + + # Loop to get User-Specific TLVs + while len(packet[start:]) > 2: + next_raw = packet[start:start + 2] + nraw = unpack('!H', next_raw) + n_type = nraw[0] >> 9 + n_length = nraw[0] & 0xFF + length = n_length - 4 + if n_type == 0: + break + elif n_type == 127: + # We only want TLV 127, OUI a42305 (ONOS) + # Then we will look for Subtype 2 and get the content + # Skip the OUI - 3 bytes + subtype_raw = packet[start + 5:start + 6] + subtype = unpack('!B', subtype_raw) + if subtype[0] == 2: + content_raw = packet[start + 6:start + 6 + length] + string = '!%ss' % length + content = unpack(string, content_raw) + self.c_id = content[0] + + start = start + n_length + 2 + + # END + end_raw = packet[start:start + 2] + end = unpack('!H', end_raw) + self.e_type = end[0] >> 9 + self.e_length = end[0] & 0xFF + + +class ARP: + """ + Class to manage ARP fields + """ + def __init__(self): + self.hw_type = None + self.prot_type = None + self.hw_len = None + self.prot_len = None + self.opcode = None + self.src_mac = None + self.src_ip = None + self.dst_mac = None + self.dst_ip = None + + def parse(self, packet): + arp_raw = packet[:28] + arp = unpack('!HHBBH6sL6sL', arp_raw) + self.hw_type = arp[0] + self.prot_type = arp[1] + self.hw_len = arp[2] + self.prot_len = arp[3] + self.opcode = arp[4] + self.src_mac = arp[5] + self.src_ip = arp[6] + self.dst_mac = arp[7] + self.dst_ip = arp[8] diff --git a/tcpiplib/prints.py b/tcpiplib/prints.py new file mode 100644 index 0000000..fe3a7eb --- /dev/null +++ b/tcpiplib/prints.py @@ -0,0 +1,210 @@ +''' + Generic/Protocol-independent prints +''' + +import socket +import struct +import gen.proxies +import of10.dissector +import of13.dissector +import tcpiplib.tcpip +from gen.prints import red, green, blue, yellow, cyan + + +def eth_addr(a): + """ + Print Mac Address in the human format + Args: + a: string "6s" + Returns: + mac in the human format + """ + string = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" + mac = string % (ord(a[0]), ord(a[1]), ord(a[2]), + ord(a[3]), ord(a[4]), ord(a[5])) + return mac + + +def get_ip_from_long(long_ip): + """ + Get IP from a long int + Args: + long_ip: IP in the long int format + + Returns: IP in the format x.x.x.x + """ + return (socket.inet_ntoa(struct.pack('!L', long_ip))) + + +def datapath_id(a): + """ + Convert OpenFlow Datapath ID to human format + Args: + a: DPID in "8s" format + Returns: + DPID in human format + """ + string = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" + dpid = string % (ord(a[0]), ord(a[1]), ord(a[2]), ord(a[3]), + ord(a[4]), ord(a[5]), ord(a[6]), ord(a[7])) + return dpid + + +def print_headers(pkt): + """ + Print TCP/IP header. It uses command line option -p + to print 'mininal' or 'full' headers + Args: + pkt: class OFMessage + """ + if pkt.print_options['min'] == 1: + print_minimal(pkt.position, pkt.l1.time, pkt.l1.caplen, pkt.l3, + pkt.l4) + else: + print_position(pkt.position) + print_layer1(pkt.l1.time, pkt.l1.caplen, pkt.l1.truncate) + print_layer2(pkt.l2) + print_layer3(pkt.l3) + print_tcp(pkt.l4) + + +def print_minimal(position, date, getlen, ip, tcp): + """ + Print TCP/IP header with minimal information + Args: + position: packet count + date: date/time packet was captured + getlen: total number of bytes captured + ip: class IP + tcp: class TCP + """ + string = 'Packet #%s - %s %s:%s -> %s:%s Size: %s Bytes' + + source = gen.proxies.get_ip_name(ip.s_addr, tcp.source_port) + dest = gen.proxies.get_ip_name(ip.d_addr, tcp.dest_port) + + print string % (position, date, cyan(source), cyan(tcp.source_port), + cyan(dest), cyan(tcp.dest_port), getlen) + + +def print_position(position): + """ + Print the packet counter (ctr) number + Args: + position: number of the packet captured in the sequence + """ + print ('Packet Number # %s' % position) + + +def print_layer1(date, getlen, caplen): + """ + Prints information about the captured packet + Args: + date: date/time when the packet was captured + getlen: total packet captured + caplen: truncated size of the packet captured + """ + print ('%s: captured %d bytes, truncated to %d bytes' % + (date, getlen, caplen)) + + +def print_layer2(eth): + """ + Prints the Ethernet frame + Args: + eth: class Ethernet + """ + print ('Ethernet: Destination MAC: %s Source MAC: %s Protocol: %s' % + (eth_addr(eth.dst_mac), eth_addr(eth.src_mac), + red(tcpiplib.tcpip.get_ethertype(eth.protocol)))) + + +def print_vlan(vlan): + """ + Print VLAN fields + Args: + vlan: class VLAN + """ + print ('VLAN: PCP: %s CFI: %s VID: %s' % + (vlan.pcp, vlan.cfi, red(vlan.vid))) + + +def print_arp(arp): + """ + Print ARP fields + Args: + arp: class ARP + """ + print ('ARP: Hardware Type: %s Protocol Type: %s ' + 'HW Length: %s Prot Length: %s Opcode: %s ' + '\nARP: Source MAC: %s Source IP: %s Destination MAC: %s ' + 'Destination IP: %s' + % (arp.hw_type, arp.prot_type, arp.hw_len, + arp.prot_len, arp.opcode, + eth_addr(arp.src_mac), get_ip_from_long(arp.src_ip), + eth_addr(arp.dst_mac), get_ip_from_long(arp.dst_ip))) + + +def print_layer3(ip): + """ + Prints IP headers + Args: + ip: class IP + """ + print (('IP Version: %d IP Header Length: %d TTL: %d Protocol: %d ' + 'Source Address: %s Destination Address: %s') % + (ip.version, (ip.length), ip.ttl, ip.protocol, + blue(ip.s_addr), blue(ip.d_addr))) + + +def print_tcp(tcp): + """ + Print TCP headers + Args: + tcp: class TCP + """ + print ('TCP Source Port: %s Dest Port: %s Sequence Number: %s ' + 'Acknowledgement: %s TCP header length: %s Flags: CWR: %s ' + 'ECE: %s URG: %s ACK: %s PSH: %s RST: %s SYN: %s FYN: %s' % + (tcp.source_port, tcp.dest_port, tcp.sequence, + tcp.acknowledgement, (tcp.length), tcp.flag_cwr, + tcp.flag_ece, tcp.flag_urg, tcp.flag_ack, tcp.flag_psh, + tcp.flag_rst, tcp.flag_syn, tcp.flag_fyn)) + + +def print_openflow_header(ofp): + """ + Print OpenFlow header + Args: + ofp: class OFMessage + """ + version = tcpiplib.tcpip.get_ofp_version(ofp.version) + name_version = '%s(%s)' % (version, ofp.version) + if version == '1.0': + name = of10.dissector.get_ofp_type(ofp.type) + name_type = '%s(%s)' % (name, ofp.type) + elif version == '1.3': + name = of13.dissector.get_ofp_type(ofp.type) + name_type = '%s(%s)' % (name, ofp.type) + else: + name_type = '%s' % (ofp.type) + + print ('OpenFlow Version: %s Type: %s Length: %s XID: %s' % + (name_version, yellow(name_type), ofp.length, red(ofp.xid))) + + +def print_lldp(lldp): + """ + Print LLDP fields + Args: + lldp: class LLDP + """ + print ('LLDP: Chassis Type(%s) Length: %s SubType: %s ID: %s\n' + 'LLDP: Port Type(%s) Length: %s SubType: %s ID: %s\n' + 'LLDP: TTL(%s) Length: %s Seconds: %s\n' + 'LLDP: END(%s) Length: %s' % + (lldp.c_type, lldp.c_length, lldp.c_subtype, + green(lldp.c_id), lldp.p_type, + lldp.p_length, lldp.p_subtype, green(lldp.p_id), + lldp.t_type, lldp.t_length, lldp.t_ttl, + lldp.e_type, lldp.e_length)) diff --git a/tcpiplib/tcpip.py b/tcpiplib/tcpip.py new file mode 100644 index 0000000..fc8cec2 --- /dev/null +++ b/tcpiplib/tcpip.py @@ -0,0 +1,54 @@ +from struct import unpack + + +def get_ethertype(etype): + etypes = {8: 'IP', + 2048: 'IP', + 2054: 'ARP', + 33024: 'VLAN', + 34925: 'IPv6', + 34887: 'MPLS', + 35020: 'LLDP', + 35138: 'BBDP', + 34998: 'PRIVATE'} + try: + return '%s(%s)' % (etypes[etype], hex(etype)) + except: + return hex(etype) + + +def get_ofp_version(version): + of_versions = {0: 'Experimental', + 1: '1.0', + 2: '1.1', + 3: '1.2', + 4: '1.3', + 5: '1.4', + 6: '1.5'} + try: + return of_versions[version] + except: + return 'Unknown(%s)' % version + + +def get_openflow_header(packet, start): + """ + Returns OpenFlow header + It is non-version aware + """ + of_header_length = 8 + of_header = packet[start:of_header_length+start] + try: + ofh = unpack('!BBHL', of_header) + of_version = ofh[0] + of_type = ofh[1] + of_length = ofh[2] + of_xid = ofh[3] + of_header = {'version': of_version, 'type': of_type, + 'length': of_length, 'xid': of_xid} + return of_header + + except Exception as exception: + print exception + of_header['version'] = -1 + return of_header From 22aa768fade73378e84c6118d58aee5078b86d03 Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Sun, 1 May 2016 16:57:54 -0400 Subject: [PATCH 24/88] Pad, Vendor, Small Bug Fixes, some documentation. OpenFlow 1.0 ready and tested. Fix OF1.3 bug fixes and add all missing types (15+). --- TODO | 8 ---- docs/TODO | 1 + example_filter.json | 2 +- gen/packet.py | 1 - gen/proxies.py | 9 +--- of10/packet.py | 29 +++++++----- of10/parser.py | 57 +++++++++++++---------- of10/prints.py | 109 +++++++++++++++++++++++++++----------------- 8 files changed, 122 insertions(+), 94 deletions(-) delete mode 100644 TODO create mode 100644 docs/TODO diff --git a/TODO b/TODO deleted file mode 100644 index 36c1193..0000000 --- a/TODO +++ /dev/null @@ -1,8 +0,0 @@ -TODO: - -Print data from Hello, EchoReq, EchoRes - -Handle Vendor -Handle Pads - -Test all STAT_REPLY, QUEUE diff --git a/docs/TODO b/docs/TODO new file mode 100644 index 0000000..bc60bf4 --- /dev/null +++ b/docs/TODO @@ -0,0 +1 @@ +TODO: diff --git a/example_filter.json b/example_filter.json index 34e839c..8751d82 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,7 +2,7 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 10, 14, 15, 16, 18, 19 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19 ] }, "1.3": { diff --git a/gen/packet.py b/gen/packet.py index 481eced..eac95ab 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -163,7 +163,6 @@ def process_packet_header(self, header, time): def get_remaining_bytes(self): return self.l1.caplen - self.offset - # TODO: This method has to be removed - uses dictionaries def get_of_message_length(self): of_h = get_openflow_header(self.packet, self.offset) return of_h, of_h['length'] diff --git a/gen/proxies.py b/gen/proxies.py index eeefda3..f3a6ee2 100644 --- a/gen/proxies.py +++ b/gen/proxies.py @@ -43,11 +43,4 @@ def get_ip_name(ip, port): for i, j in NET.iteritems(): if i == (ip, port): return '%s(%s)' % (ip, j) - return ip - - -def close(): - print '\n' - # Future: send to a file to import faster - # for i, j in NET.iteritems(): - # print i, j + return ip \ No newline at end of file diff --git a/of10/packet.py b/of10/packet.py index 873b0ec..6c1e378 100644 --- a/of10/packet.py +++ b/of10/packet.py @@ -124,7 +124,7 @@ def process_msg(self, packet): parser.parse_Vendor(self, packet) def prints(self): - prints.print_of_echores(self) + prints.print_of_vendor(self) class OFPT_FEATURE_REQ(OFPHeader): @@ -181,7 +181,7 @@ def process_msg(self, packet): parser.parse_GetConfigRes(self, packet) def prints(self): - prints.print_of_getconfig_req(self) + prints.print_ofp_getConfigRes(self) class OFPT_SET_CONFIG(OFPHeader): @@ -523,16 +523,8 @@ def __init__(self, packet_count, byte_count, flow_count, pad): class OFP_STATSRES_TABLE: - def __init__(self, table_id, pad, name, wildcards, max_entries, - active_count, lookup_count, matched_count): - self.table_id = table_id - self.pad = pad - self.name = name - self.wildcards = wildcards - self.max_entries = max_entries - self.active_count = active_count - self.lookup_count = lookup_count - self.matched_count = matched_count + def __init__(self, tables): + self.tables = tables # Class OFP_STAT_TABLE[] class OFP_STATRES_PORT: @@ -592,6 +584,19 @@ def __init__(self): self.collisions = None +class OFP_STAT_TABLE: + + def __init__(self): + self.table_id = None + self.pad = None + self.name = None + self.wildcards = None + self.max_entries = None + self.active_count = None + self.lookup_count = None + self.matched_count = None + + class OFP_STAT_QUEUE: def __init__(self): diff --git a/of10/parser.py b/of10/parser.py index e0eebab..635f615 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -224,7 +224,7 @@ def process_data(packet, start, msg): def parse_PacketIn(msg, packet): # buffer_id(32), total_len(16), in_port(16), reason(8), pad(8) pkt_raw = packet[0:10] - p_in = unpack('!LHHBB', pkt_raw) + p_in = unpack('!LHHB1s', pkt_raw) reason = of10.dissector.get_packetIn_reason(p_in[3]) msg.buffer_id = p_in[0] msg.total_len = p_in[1] @@ -240,7 +240,7 @@ def parse_FlowRemoved(msg, packet): msg.match = _parse_OFMatch(msg, packet, 0) of_rem_body = packet[40:40+40] - ofrem = unpack('!QHBBLLHBBQQ', of_rem_body) + ofrem = unpack('!QHB1sLLH1s1sQQ', of_rem_body) cookie = ofrem[0] if ofrem[0] > 0 else 0 cookie = '0x' + format(cookie, '02x') reason = of10.dissector.get_flow_removed_reason(ofrem[2]) @@ -517,7 +517,7 @@ def parse_FlowMod(msg, packet): def parse_PortMod(msg, packet): # port(16), hw_addr(48), config(32), mask(32), advertise(32), pad(32) pmod_raw = packet[0:24] - pmod = unpack('!H6sLLLL', pmod_raw) + pmod = unpack('!H6sLLL4s', pmod_raw) config = _parse_phy_config(pmod[2]) mask = _parse_phy_config(pmod[3]) @@ -564,7 +564,7 @@ def parse_StatsReq(msg, packet): match = _parse_OFMatch(msg, packet, start) # 44 Bytes (40B from Match, 4 from header) of_stat_req = packet[start+40:start+40+4] - table_id, pad, out_port = unpack('!BBH', of_stat_req) + table_id, pad, out_port = unpack('!B1sH', of_stat_req) msg.instantiate(match, table_id, pad, out_port) elif msg.stat_type == 3: @@ -583,7 +583,7 @@ def parse_StatsReq(msg, packet): # Queue # Fields: port_number(16), pad(16), queue_id(32) of_stat_req = packet[start:start+8] - port_number, pad, queue_id = unpack('!HHL', of_stat_req) + port_number, pad, queue_id = unpack('!H2sL', of_stat_req) msg.instantiate(port_number, pad, queue_id) elif msg.stat_type == 65535: @@ -642,7 +642,7 @@ def parse_StatsRes(msg, packet): flows = [] while count > 0: flow_raw = packet[start:start+4] - flow = unpack('!HBB', flow_raw) + flow = unpack('!HB1s', flow_raw) eflow = of10.packet.OFP_STAT_FLOW() @@ -687,7 +687,7 @@ def parse_StatsRes(msg, packet): Fields: packet_count(64), byte_count(64), flow_count(32), pad(32) = 24 Bytes """ flow_raw = packet[start:start+24] - flow = unpack('!QQLL', flow_raw) + flow = unpack('!QQL4s', flow_raw) packet_count = flow[0] byte_count = flow[1] flow_count = flow[2] @@ -700,18 +700,29 @@ def parse_StatsRes(msg, packet): max_entries(32), active_count(32), lookup_count(64), matched_count(64) = 64 Bytes """ - flow_raw = packet[start:start+64] - flow = unpack('!B3s32sLLLQQ', flow_raw) - table_id = flow[0] - pad = flow[1] - name = flow[2] - wildcards = flow[3] - max_entries = flow[4] - active_count = flow[5] - lookup_count = flow[6] - matched_count = flow[7] - msg.instantiate(table_id, pad, name, wildcards, max_entries, - active_count, lookup_count, matched_count) + count = len(packet[0:]) - 4 + tables = [] + while count > 0: + flow_raw = packet[start:start+64] + flow = unpack('!B3s32sLLLQQ', flow_raw) + + etable = of10.packet.OFP_STAT_TABLE() + etable.table_id = flow[0] + etable.pad = flow[1] + etable.name = flow[2] + etable.wildcards = flow[3] + etable.max_entries = flow[4] + etable.active_count = flow[5] + etable.lookup_count = flow[6] + etable.matched_count = flow[7] + + tables.append(etable) + del etable + + count -= 64 + start += 64 + + msg.instantiate(tables) elif msg.stat_type == 4: """ Parses Port(4) @@ -760,7 +771,7 @@ def parse_StatsRes(msg, packet): queues = [] while count > 0: flow_raw = packet[start:start+32] - flow = unpack('!HHLQQQ', flow_raw) + flow = unpack('!H2sLQQQ', flow_raw) queue = of10.packet.OFP_STAT_QUEUE() queue.length = flow[0] @@ -808,7 +819,7 @@ def parse_BarrierRes(msg, packet): # ******************* QueueGetConfigReq ******************* def parse_QueueGetConfigReq(msg, packet): queue_raw = packet[0:4] - queue = unpack('!HH', queue_raw) + queue = unpack('!H2s', queue_raw) msg.port = queue[0] msg.pad = queue[1] @@ -826,7 +837,7 @@ def parse_QueueGetConfigRes(msg, packet): # Queues - it could be multiple # queue_id(32), length(16), pad(16) queue_raw = packet[start:start+8] - queue = unpack('!LHH', queue_raw) + queue = unpack('!LH2s', queue_raw) equeue = of10.packet.OFP_QUEUE() equeue.queue_id = queue[0] @@ -842,7 +853,7 @@ def parse_QueueGetConfigRes(msg, packet): while len(properties[q_start:] > 0): prop_raw = packet[q_start:q_start+8] - prop = unpack('!HHLH6s', prop_raw) + prop = unpack('!HH4sH6s', prop_raw) property = of10.packet.OFP_QUEUE_PROPERTIES() property.property = prop[0] diff --git a/of10/prints.py b/of10/prints.py index 6e773a1..3e2bf87 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -17,6 +17,22 @@ def print_type_unknown(pkt): print string % (pkt.of_h['type']) +def print_pad(pad): + """ + Used to print pads as a sequence of 0s: 0, 00, 000.. + Args: + pad: pad in str format + Returns: string with '0' + """ + pad_len = len(pad) + string = '0' + if pad_len == 1: + return '0' + for item in range(0,pad_len-1): + string += '0' + return string + + def print_of_hello(msg): print 'OpenFlow Hello' @@ -37,7 +53,7 @@ def print_of_getconfig_req(msg): def print_of_feature_res(msg): dpid = datapath_id(msg.datapath_id) print ('FeatureRes - datapath_id: %s n_buffers: %s n_tbls: %s, pad: %s' - % (green(dpid), msg.n_buffers, msg.n_tbls, msg.pad)) + % (green(dpid), msg.n_buffers, msg.n_tbls, print_pad(msg.pad))) print ('FeatureRes - Capabilities:'), for i in msg.capabilities: print of10.dissector.get_feature_res_capabilities(i), @@ -59,7 +75,7 @@ def print_port_field(port_id, variable, name): port_id = '%s' % green(port_id) printed = False - print ('Port_id: %s - %s curr:' % (port_id, name)), + print ('Port_id: %s - %s:' % (port_id, name)), for i in variable: print of10.dissector.get_phy_feature(i), printed = True @@ -142,9 +158,10 @@ def print_ofp_flow_removed(msg): 'Duration Secs/NSecs: %s/%s Idle Timeout: %s Pad2/Pad3: %s/%s' ' Packet Count: %s Byte Count: %s') - print string % (msg.cookie, msg.priority, red(msg.reason), msg.pad, - msg.duration_sec, msg.duration_nsec, msg.idle_timeout, - msg.pad2, msg.pad3, msg.packet_count, msg.byte_count) + print string % (msg.cookie, msg.priority, red(msg.reason), + print_pad(msg.pad), msg.duration_sec, msg.duration_nsec, + msg.idle_timeout, print_pad(msg.pad2), + print_pad(msg.pad3), msg.packet_count, msg.byte_count) def print_actions(actions): @@ -165,13 +182,13 @@ def print_ofp_action(action_type, length, payload): elif action_type == 1: vlan, pad = of10.parser.get_action(action_type, length, payload) print ('Action - Type: %s Length: %s VLAN ID: %s Pad: %s' % - (green('SetVLANID'), length, green(str(vlan)), pad)) + (green('SetVLANID'), length, green(str(vlan)), print_pad(pad))) return 'mod_vlan_vid:' + str(vlan) elif action_type == 2: vlan_pc, pad = of10.parser.get_action(action_type, length, payload) print ('Action - Type: %s Length: %s VLAN PCP: %s Pad: %s' % - (green('SetVLANPCP'), length, green(str(vlan_pc)), pad)) + (green('SetVLANPCP'), length, green(str(vlan_pc)), print_pad(pad))) return 'mod_vlan_pcp:' + str(vlan_pc) elif action_type == 3: @@ -183,14 +200,14 @@ def print_ofp_action(action_type, length, payload): setDLSrc, pad = of10.parser.get_action(action_type, length, payload) print ('Action - Type: %s Length: %s SetDLSrc: %s Pad: %s' % (green('SetDLSrc'), length, green(str(eth_addr(setDLSrc))), - pad)) + print_pad(pad))) return 'mod_dl_src:' + str(eth_addr(setDLSrc)) elif action_type == 5: setDLDst, pad = of10.parser.get_action(action_type, length, payload) print ('Action - Type: %s Length: %s SetDLDst: %s Pad: %s' % (green('SetDLDst'), length, green(str(eth_addr(setDLDst))), - pad)) + print_pad(pad))) return 'mod_dl_dst:' + str(eth_addr(setDLDst)) elif action_type == 6: @@ -208,19 +225,19 @@ def print_ofp_action(action_type, length, payload): elif action_type == 8: nw_tos, pad = of10.parser.get_action(action_type, length, payload) print ('Action - Type: %s Length: %s SetNWTos: %s Pad: %s' % - (green('SetNWTos'), length, green(str(nw_tos)), pad)) + (green('SetNWTos'), length, green(str(nw_tos)), print_pad(pad))) return 'mod_nw_tos:' + str(nw_tos) elif action_type == 9: port, pad = of10.parser.get_action(action_type, length, payload) print ('Action - Type: %s Length: %s SetTPSrc: %s Pad: %s' % - (green('SetTPSrc'), length, green(str(port)), pad)) + (green('SetTPSrc'), length, green(str(port)), print_pad(pad))) return 'mod_tp_src:' + str(port) elif action_type == int('a', 16): port, pad = of10.parser.get_action(action_type, length, payload) print ('Action - Type: %s Length: %s SetTPDst: %s Pad: %s' % - (green('SetTPDst'), length, green(str(port)), pad)) + (green('SetTPDst'), length, green(str(port)), print_pad(pad))) return 'mod_tp_dst:' + str(port) elif action_type == int('b', 16): @@ -228,7 +245,7 @@ def print_ofp_action(action_type, length, payload): payload) print (('Action - Type: %s Length: %s Enqueue: %s Pad: %s' ' Queue: %s') % - (green('Enqueue'), length, green(str(port)), pad, + (green('Enqueue'), length, green(str(port)), print_pad(pad), green(str(queue_id)))) return 'set_queue:' + str(queue_id) @@ -286,7 +303,7 @@ def _print_portMod_config_mask(variable, name): def print_of_PortMod(msg): print ('PortMod Port_no: %s HW_Addr %s Pad: %s' % - (msg.port_no, eth_addr(msg.hw_addr), msg.pad)) + (msg.port_no, eth_addr(msg.hw_addr), print_pad(msg.pad))) _print_portMod_config_mask(msg.config, 'config') _print_portMod_config_mask(msg.mask, 'mask') _print_portMod_config_mask(msg.advertise, 'advertise') @@ -311,7 +328,7 @@ def print_ofp_statReq(msg): elif msg.stat_type == 1 or msg.type == 2: print_ofp_statReqFlowAggregate(msg) elif msg.stat_type == 3: - print_ofp_statResTable(msg) + print_ofp_statReqTable(msg) elif msg.stat_type == 4: print_ofp_statReqPort(msg) elif msg.stat_type == 5: @@ -332,8 +349,8 @@ def print_ofp_statReqFlowAggregate(msg): print ('StatReq Type: %s(%s)' % (type_name, msg.stat_type)) print_ofp_match(msg.stats.match) out_port = of10.dissector.get_phy_port_id(msg.stats.out_port) - print ('StatReq Table_id: %s Pad: %d Out_Port: %s' % (msg.stats.table_id, - msg.stats.pad, out_port)) + print ('StatReq Table_id: %s Pad: %s Out_Port: %s' % (msg.stats.table_id, + print_pad(msg.stats.pad), out_port)) def print_ofp_statReqTable(msg): @@ -343,18 +360,20 @@ def print_ofp_statReqTable(msg): def print_ofp_statReqPort(msg): port_number = of10.dissector.get_phy_port_id(msg.stats.port_number) print ('StatReq Type: Port(%s): Port_Number: %s Pad: %s' % - (msg.stat_type, green(port_number), msg.stats.pad)) + (msg.stat_type, green(port_number), print_pad(msg.stats.pad))) def print_ofp_statReqQueue(msg): port_number = of10.dissector.get_phy_port_id(msg.stats.port_number) print ('StatReq Type: Queue(%s): Port_Number: %s Pad: %s Queue_id: %s' % - (msg.stat_type, green(port_number), msg.stats.pad, msg.stats.queue_id)) + (msg.stat_type, green(port_number), print_pad(msg.stats.pad), + msg.stats.queue_id)) def print_ofp_statReqVendor(msg): + vendor = of10.dissector.get_ofp_vendor(msg.stats.vendor_id) print ('StatReq Type: Vendor(%s): Vendor_ID: %s' % (msg.stat_type, - msg.stats.vendor_id)) + vendor)) def print_ofp_statRes(msg): @@ -365,7 +384,7 @@ def print_ofp_statRes(msg): elif msg.stat_type == 2: print_ofp_statResAggregate(msg) elif msg.stat_type == 3: - print_ofp_statResTable(msg) + print_ofp_statResTableArray(msg) elif msg.stat_type == 4: print_ofp_statResPortArray(msg) elif msg.stat_type == 5: @@ -395,7 +414,7 @@ def print_ofp_statResFlowArray(msg): def print_ofp_statResFlow(flow): print ('StatRes Type: Flow(1)') print ('StatRes Length: %s Table_id: %s Pad: %s ' % - (flow.length, flow.table_id, flow.pad)) + (flow.length, flow.table_id, print_pad(flow.pad))) print ('StatRes'), print_ofp_match(flow.match) print ('StatRes duration_sec: %s, duration_nsec: %s, priority: %s,' @@ -403,7 +422,7 @@ def print_ofp_statResFlow(flow): ' packet_count: %s, byte_count: %s' % (flow.duration_sec, flow.duration_nsec, flow.priority, flow.idle_timeout, - flow.hard_timeout, flow.pad, + flow.hard_timeout, print_pad(flow.pad), flow.cookie, flow.packet_count, flow.byte_count)) print ('StatRes'), @@ -415,17 +434,26 @@ def print_ofp_statResAggregate(msg): print ('StatRes packet_count: %s, byte_count: %s flow_count: %s ' 'pad: %s' % (msg.stats.packet_count, msg.stats.byte_count, - msg.stats.flow_count, msg.stats.pad)) + msg.stats.flow_count, print_pad(msg.stats.pad))) -def print_ofp_statResTable(msg): +def print_ofp_statResTableArray(msg): + if len(msg.stats.tables) == 0: + print ('StatRes Type: Table(3)\nNo Tables') + return + print ('StatRes Type: Table(3)') + for table in msg.stats.tables: + print_ofp_statResTable(table) + + +def print_ofp_statResTable(table): print ('StatRes table_id: %s, pad: %s, name: "%s", wildcards: %s, ' 'max_entries: %s, active_count: %s, lookup_count: %s, ' 'matched_count: %s' % - (msg.table_id, msg.pad, msg.name, hex(msg.wildcards), - msg.max_entries, msg.active_count, - msg.lookup_count, msg.matched_count)) + (table.table_id, print_pad(table.pad), table.name, hex(table.wildcards), + table.max_entries, table.active_count, + table.lookup_count, table.matched_count)) def print_ofp_statResPortArray(msg): @@ -447,11 +475,11 @@ def print_ofp_statResPort(port): port.rx_dropped, port.rx_over_err, port.rx_frame_err, red(port.port_number), port.tx_packets, port.tx_bytes, port.tx_errors, - port.tx_dropped, port.collisions, port.pad)) + port.tx_dropped, port.collisions, print_pad(port.pad))) def print_ofp_statResQueueArray(msg): - if len(msg.queues) == 0: + if len(msg.stats.queues) == 0: print 'StatRes Type: Queue(5)\nNo Queues' return @@ -463,7 +491,7 @@ def print_ofp_statResQueue(queue): print 'StatRes Type: Queue(5)' print ('StatRes queue_id: %s length: %s pad: %s' ' tx_bytes: %s tx_packets: %s tx_errors: %s' % - (queue.queue_id, queue.length, queue.pad, + (queue.queue_id, queue.length, print_pad(queue.pad), queue.tx_bytes, queue.tx_packets, queue.tx_errors)) @@ -480,7 +508,7 @@ def print_ofp_statResVendorData(data): def print_ofp_getConfigRes(msg): print ('OpenFlow GetConfigRes - Flag: %s Miss_send_len: %s' % - (msg.flag, msg.miss_send_len)) + (msg.flags, msg.miss_send_len)) def print_ofp_setConfig(msg): @@ -489,17 +517,16 @@ def print_ofp_setConfig(msg): def print_of_echoreq(msg): - # print data print 'OpenFlow Echo Request' def print_of_echores(msg): - # print data print 'OpenFlow Echo Reply' def print_portStatus(msg): - print ('OpenFlow PortStatus - Reason: %s Pad: %s' % (msg.reason, msg.pad)) + print ('OpenFlow PortStatus - Reason: %s Pad: %s' % (msg.reason, + print_pad(msg.pad))) print_of_ports(msg.desc) @@ -517,7 +544,7 @@ def print_of_packetIn(msg): print ('PacketIn: buffer_id: %s total_len: %s in_port: %s reason: %s ' 'pad: %s' % (hex(msg.buffer_id), msg.total_len, green(msg.in_port), - green(msg.reason), msg.pad)) + green(msg.reason), print_pad(msg.pad))) print_data(msg.data) @@ -563,12 +590,12 @@ def print_data(data): def print_queueReq(msg): print ('QueueGetConfigReq Port: %s Pad: %s' % - (msg.port, msg.pad)) + (msg.port, print_pad(msg.pad))) def print_queueRes(msg): print ('QueueGetConfigRes Port: %s Pad: %s' % - (msg.port, msg.pad)) + (msg.port, print_pad(msg.pad))) if len(msg.queues) == 0: print 'QueueGetConfigRes: No Queues' return @@ -578,7 +605,7 @@ def print_queueRes(msg): def print_queueRes_queue(queue): print ('Queue_ID: %s Length: %s Pad: %s' % - (queue.queue_id, queue.length, queue.pad)) + (queue.queue_id, queue.length, print_pad(queue.pad))) if len(queue.properties) == 0: print 'QueueGetConfigRes: No Properties' return @@ -588,10 +615,10 @@ def print_queueRes_queue(queue): def print_queueRes_properties(property): print ('Property: %s Length: %s Pad: %s' % - (property.property, property.length, property.pad)) + (property.property, property.length, print_pad(property.pad))) print_queueRes_prop_payload(property.payload) def print_queueRes_prop_payload(payload): print ('Payload: Rate %s Pad: %s' % - (payload.rate, payload.pad)) + (payload.rate, print_pad(payload.pad))) From ec84ef027e3c6e83acb884568783fbd4bdf1f88e Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Sun, 1 May 2016 23:17:28 -0400 Subject: [PATCH 25/88] Added new filters, improved resilience removing OFMessages cut by MTU issues, added support for user define a specific packet inside a libpcap.file, improved the exceptions --- docs/TODO | 1 - example_filter.json | 80 ++---- gen/cli.py | 35 ++- gen/filters.py | 73 ++++- gen/packet.py | 17 +- of10/prints.py | 1 + of13/packet.py | 633 ++++++++++++++++++++++++++++++++++++++++++++ ofp_sniffer.py | 25 +- tcpiplib/prints.py | 4 +- 9 files changed, 784 insertions(+), 85 deletions(-) create mode 100644 of13/packet.py diff --git a/docs/TODO b/docs/TODO index bc60bf4..e69de29 100644 --- a/docs/TODO +++ b/docs/TODO @@ -1 +0,0 @@ -TODO: diff --git a/example_filter.json b/example_filter.json index 8751d82..832a9d8 100644 --- a/example_filter.json +++ b/example_filter.json @@ -1,61 +1,29 @@ { "allowed_of_versions": { - "1.0": { - "rejected_of_types": [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19 - ] - }, - "1.3": { - "rejected_of_types": [ - ] - } + "1.0": { + "rejected_of_types": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19 + ] + }, + "1.3": { + "rejected_of_types": [ + ] + } }, - "packetIn_filter": { - "switch_dpid": "any", - "in_port": "any" - }, - "packetOut_filter": { - "switch_dpid": "dpid:5", - "out_port": "any" - }, - "flowMod_logs": { - "filter_1": { - "match": { - "vlan": "any", - "in_port": "1" - }, - "action": { - "output": "2", - "mod_dl_src": "14" - }, - "label": "onos" - }, - "filter_2": { - "match": { - "any": "any" - }, - "action": { - "mod_dl_dst": "any" - }, - "label": "oess_test" - }, - "filter_3": { - "match": { - "in_port": "4" - }, - "action": { - "any": "any" - }, - "label": "fibre" - }, - "all": { - "match": { - "any": "any" - }, - "action": { - "any": "any" - }, - "label": 0 - } + "filters":{ + "ethertypes": { + "lldp" : 1, + "fvd" : 0, + "arp" : 1, + "others": [ "88b5" ] + }, + "packetIn_filter": { + "switch_dpid": "any", + "in_port": "any" + }, + "packetOut_filter": { + "switch_dpid": "dpid:5", + "out_port": "any" + } } } diff --git a/gen/cli.py b/gen/cli.py index c74cee3..d72f27c 100644 --- a/gen/cli.py +++ b/gen/cli.py @@ -44,24 +44,40 @@ def read_sanitizer(sanitizer_file): return (json_content) +def check_file_position(file): + """ + Check if -r file was inserted with colon (:) + If yes, only read the position specified after colon + Args: + file: User's input -r + Returns: + position + """ + new_file = file.partition(":")[0] + position = file.partition(":")[2] + return new_file, int(position) if len(position) is not 0 else 0 + + def start_capture(capfile, infilter, dev): try: if len(capfile) > 0: + capfile, position = check_file_position(capfile) print "Using file %s " % capfile cap = pcapy.open_offline(capfile) else: print "Sniffing device %s" % dev cap = pcapy.open_live(dev, 65536, 1, 0) - if len(infilter) is 0: - infilter = " port 6633 " - cap.setfilter(infilter) - return cap - except Exception as exception: print exception return -1 + finally: + if len(infilter) is 0: + infilter = " port 6633 " + cap.setfilter(infilter) + return cap, position + def get_params(argv): # Handle all input params @@ -113,13 +129,12 @@ def get_params(argv): if len(sanitizer_file) == 0: sanitizer = {'allowed_of_versions': {}, - 'packetInOut_filter': {}, - 'flowMod_logs': {}, - 'packetIn_filter': {}} + 'filters': {}} else: print_options['filters'] = 1 sanitizer = read_sanitizer(sanitizer_file) - cap = start_capture(captured_file, input_filter, dev) - return cap, print_options, sanitizer + cap, position = start_capture(captured_file, input_filter, dev) + + return cap, position, print_options, sanitizer diff --git a/gen/filters.py b/gen/filters.py index 84a3093..663bc26 100644 --- a/gen/filters.py +++ b/gen/filters.py @@ -4,13 +4,37 @@ import tcpiplib.tcpip -def filter_of_version(msg): - # Was -F submitted? +def filter_msg(msg): + """ + This method will be the core of all filters. Any new filter comes here + Args: + msg: class OFMessage + Returns: + False: Don' filter packet + True: Filter it (don't print) + """ if msg.print_options['filters'] is 0: + # User hasn't selected -F return False + # Filter per OF Version + if filter_of_version(msg): + return True + + # Filter per OF Message Type + if filter_of_type(msg): + return True + + # Filter Ethertypes from PacketIn/Out messages + if ethertype_filters(msg): + return True + + return False + + +def filter_of_version(msg): # Check if the OpenFlow version is allowed - name_version = tcpiplib.tcpip.get_ofp_version(msg.of_h['version']) + name_version = tcpiplib.tcpip.get_ofp_version(msg.ofp.version) supported_versions = [] for version in msg.sanitizer['allowed_of_versions']: supported_versions.append(version) @@ -20,14 +44,49 @@ def filter_of_version(msg): def filter_of_type(msg): - # Was -F submitted? - if msg.print_options['filters'] is 0: - return False - name_version = tcpiplib.tcpip.get_ofp_version(msg.ofp.version) # OF Types to be ignored through json file (-F) rejected_types = msg.sanitizer['allowed_of_versions'][name_version] if msg.ofp.type in rejected_types['rejected_of_types']: return True + return False + + +def ethertype_filters(msg): + """ + Filter PacketIn and PacketOut messages with LLDP or BDDP + Sanitizer filter (-F), entry "filters", "ethertype" + Args: + msg: class OFMessage + Returns: + False: Don' filter packet + True: Filter it (don't print) + """ + if msg.ofp.type in [10, 13]: + filters = msg.sanitizer['filters']['ethertypes'] + if not len(filters): + # No filters + return False + # Go to payload + idx = 0 + if isinstance(msg.ofp.data[idx], tcpiplib.packet.Ethernet): + next_protocol = msg.ofp.data[idx].protocol + idx += 1 + if isinstance(msg.ofp.data[idx], tcpiplib.packet.VLAN): + next_protocol = msg.ofp.data[idx].protocol + try: + if next_protocol in [35020, 35138] and filters['lldp']: + return True + if next_protocol in [34998] and filters['fvd']: + return True + if next_protocol in [2054] and filters['arp']: + return True + except KeyError: + pass + + # Other Ethertypes listed as hex + for protocol in filters['others']: + if next_protocol == int(protocol, 16): + return True return False diff --git a/gen/packet.py b/gen/packet.py index eac95ab..a380f46 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -48,7 +48,8 @@ def process_openflow_header(self, of_header): if of_header['version'] is 1: self.ofp = of10.packet.instantiate(self, of_header) if type(self.ofp) is type(int()): - print 'Debug: Type not recognized' + print ('Debug: Packet: %s not OpenFlow\n' % + (self.main_packet.position)) self.offset += 8 self.packet = self.packet[8:] return 0 @@ -68,10 +69,7 @@ def handle_malformed_pkts(self, exception): Args: exception = generated expection """ - string = ('!!! MalFormed Packet - Packet Len: %s Informed: %s ' - 'Missing: %s Bytes !!!' % - (len(self.packet), self.ofp.length, - self.ofp.length - len(self.packet))) + string = ('!!! MalFormed Packet: %s' % self.main_packet.position) print 'message %s\n Details about the Error:' % string print exception @@ -100,8 +98,7 @@ def process_openflow_body(self, of_header): return -1 def print_packet(self, pkt): - # TODO: what about the OpenFlow version filter? - if not gen.filters.filter_of_type(self): + if not gen.filters.filter_msg(self): if pkt.printed_header is False: tcpiplib.prints.print_headers(pkt) pkt.printed_header = True @@ -177,6 +174,12 @@ def process_openflow_messages(self): # MalFormed Packet return 0 self.this_packet = self.packet[self.offset:self.offset+length] + + if len(self.this_packet) != length: + # it means packet is smaller than it should be + # propably MTU issue + return 1 + # Instantiate the OpenFlow message in the ofmsgs array # Process the content, using cur_msg position of the array of msgs self.ofmsgs.insert(self.cur_msg, OFMessage(self)) diff --git a/of10/prints.py b/of10/prints.py index 3e2bf87..8047bc7 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -259,6 +259,7 @@ def print_ofp_action(action_type, length, payload): return 'Error' +# TODO: Is it working? Fix it. def print_ofp_ovs(print_options, ofmatch, ofactions, ovs_command, prio): ''' diff --git a/of13/packet.py b/of13/packet.py new file mode 100644 index 0000000..6c1e378 --- /dev/null +++ b/of13/packet.py @@ -0,0 +1,633 @@ +import prints as prints +import parser as parser + + +def instantiate(pkt, of_header): + if of_header['type'] == 0: + return OFPT_HELLO(of_header) + elif of_header['type'] == 1: + return OFPT_ERROR(of_header) + elif of_header['type'] == 2: + return OFPT_ECHO_REQ(of_header) + elif of_header['type'] == 3: + return OFPT_ECHO_RES(of_header) + elif of_header['type'] == 4: + return OFPT_VENDOR(of_header) + elif of_header['type'] == 5: + return OFPT_FEATURE_REQ(of_header) + elif of_header['type'] == 6: + return OFPT_FEATURE_RES(of_header) + elif of_header['type'] == 7: + return OFPT_GET_CONFIG_REQ(of_header) + elif of_header['type'] == 8: + return OFPT_GET_CONFIG_RES(of_header) + elif of_header['type'] == 9: + return OFPT_SET_CONFIG(of_header) + elif of_header['type'] == 10: + return OFPT_PACKET_IN(of_header) + elif of_header['type'] == 11: + return OFPF_FLOW_REMOVED(of_header) + elif of_header['type'] == 12: + return OFPT_PORT_STATUS(of_header) + elif of_header['type'] == 13: + return OFPT_PACKET_OUT(of_header) + elif of_header['type'] == 14: + return OFPT_FLOW_MOD(of_header) + elif of_header['type'] == 15: + return OFPT_PORT_MOD(of_header) + elif of_header['type'] == 16: + return OFPT_STATS_REQ(of_header) + elif of_header['type'] == 17: + return OFPT_STATS_RES(of_header) + elif of_header['type'] == 18: + return OFPT_BARRIER_REQ(of_header) + elif of_header['type'] == 19: + return OFPT_BARRIER_RES(of_header) + elif of_header['type'] == 20: + return OFPT_QUEUE_GET_CONFIG_REQ(of_header) + elif of_header['type'] == 21: + return OFPT_QUEUE_GET_CONFIG_RES(of_header) + else: + return 0 + + +class OFPHeader: + + def __init__(self, of_header): + self.version = 1 + self.type = of_header['type'] + self.length = of_header['length'] + self.xid = of_header['xid'] + + +class OFPT_HELLO(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.data = None + + def process_msg(self, packet): + parser.parse_Hello(self, packet) + + def prints(self): + prints.print_of_hello(self) + + +class OFPT_ERROR(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.type = None + self.code = None + + def process_msg(self, packet): + parser.parse_Error(self, packet) + + def prints(self): + prints.print_of_error(self) + + +class OFPT_ECHO_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.data = None + + def process_msg(self, packet): + parser.parse_EchoReq(self, packet) + + def prints(self): + prints.print_of_echoreq(self) + + +class OFPT_ECHO_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.data = None + + def process_msg(self, packet): + parser.parse_EchoRes(self, packet) + + def prints(self): + prints.print_of_echores(self) + + +class OFPT_VENDOR(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.vendor = None + self.data = None + + def process_msg(self, packet): + parser.parse_Vendor(self, packet) + + def prints(self): + prints.print_of_vendor(self) + + +class OFPT_FEATURE_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + + def process_msg(self, packet): + parser.parse_FeatureReq(self, packet) + + def prints(self): + prints.print_of_feature_req(self) + + +class OFPT_FEATURE_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.datapath_id = None + self.n_buffers = None + self.n_tbls = None + self.pad = [] # 0-3 Bytes + self.capabilities = [] + self.actions = [] + self.ports = [] # array of class ofp_phy_port + + def process_msg(self, packet): + parser.parse_FeatureRes(self, packet) + + def prints(self): + prints.print_of_feature_res(self) + + +class OFPT_GET_CONFIG_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + + def process_msg(self, packet): + parser.parse_GetConfigReq(self, packet) + + def prints(self): + prints.print_of_getconfig_req(self) + + +class OFPT_GET_CONFIG_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.flags = None + self.miss_send_len = None + + def process_msg(self, packet): + parser.parse_GetConfigRes(self, packet) + + def prints(self): + prints.print_ofp_getConfigRes(self) + + +class OFPT_SET_CONFIG(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.flags = None + self.miss_send_len = None + + def process_msg(self, packet): + parser.parse_SetConfig(self, packet) + + def prints(self): + prints.print_ofp_setConfig(self) + + +class OFPT_PACKET_IN(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.buffer_id = None + self.total_len = None + self.in_port = None + self.reason = None + self.pad = None + self.data = None + + def process_msg(self, packet): + parser.parse_PacketIn(self, packet) + + def prints(self): + prints.print_of_packetIn(self) + + +class OFPF_FLOW_REMOVED(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.match = OFP_Match() + self.cookie = None + self.priority = None + self.reason = None + self.pad = None + self.duration_sec = None + self.duration_nsec = None + self.idle_timeout = None + self.pad2 = None + self.pad3 = None + self.packet_count = None + self.byte_count = None + + def process_msg(self, packet): + parser.parse_FlowRemoved(self, packet) + + def prints(self): + prints.print_ofp_flow_removed(self) + + +class OFPT_PORT_STATUS(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.reason = None + self.pad = [] # 0 - 7 Bytes + self.desc = OFP_Phy_port() + + def process_msg(self, packet): + parser.parse_PortStatus(self, packet) + + def prints(self): + prints.print_portStatus(self) + + +class OFPT_PACKET_OUT(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.buffer_id = None + self.in_port = None + self.actions_len = None + self.actions = [] + self.data = None + + def process_msg(self, packet): + parser.parse_PacketOut(self, packet) + + def prints(self): + prints.print_of_packetOut(self) + + +class OFPT_FLOW_MOD(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.match = OFP_Match() + self.cookie = None + self.command = None + self.idle_timeout = None + self.hard_timeout = None + self.priority = None + self.buffer_id = None + self.out_port = None + self.flags = None + self.actions = [] # Class ofp_action_header + + def process_msg(self, packet): + parser.parse_FlowMod(self, packet) + + def prints(self): + prints.print_of_FlowMod(self) + + +class OFPT_PORT_MOD(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.port_no = None + self.hw_addr = None + self.config = None + self.mask = None + self.advertise = None + self.pad = None + + def process_msg(self, packet): + parser.parse_PortMod(self, packet) + + def prints(self): + prints.print_of_PortMod(self) + + +class OFPT_STATS_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.stat_type = None + self.flags = None + self.stats = None + + def instantiate(self, *args): + if self.stat_type in [1,2]: + self.stats = OFP_STATSREQ_FLOWAGG(*args) + elif self.stat_type == 4: + self.stats = OFP_STATREQ_PORT(*args) + elif self.stat_type == 5: + self.stats = OFP_STATREQ_QUEUE(*args) + elif self.stat_type == 65535: + self.stats = OFP_STATREQ_VENDOR(*args) + + def process_msg(self, packet): + parser.parse_StatsReq(self, packet) + + def prints(self): + prints.print_ofp_statReq(self) + + +class OFPT_STATS_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.stat_type = None + self.flags = None + self.stats = None + + def instantiate(self, *args): + if self.stat_type == 0: + self.stats = OFP_STATSRES_DESC(*args) + elif self.stat_type == 1: + self.stats = OFP_STATSRES_FLOW(*args) + elif self.stat_type == 2: + self.stats = OFP_STATSRES_AGG(*args) + elif self.stat_type == 3: + self.stats = OFP_STATSRES_TABLE(*args) + elif self.stat_type == 4: + self.stats = OFP_STATRES_PORT(*args) + elif self.stat_type == 5: + self.stats = OFP_STATRES_QUEUE(*args) + elif self.stat_type == 65535: + self.stats = OFP_STATRES_VENDOR(*args) + + def process_msg(self, packet): + parser.parse_StatsRes(self, packet) + + def prints(self): + prints.print_ofp_statRes(self) + + +class OFPT_BARRIER_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + + def process_msg(self, packet): + parser.parse_BarrierReq(self, packet) + + def prints(self): + pass + + +class OFPT_BARRIER_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + + def process_msg(self, packet): + parser.parse_BarrierReq(self, packet) + + def prints(self): + pass + + +class OFPT_QUEUE_GET_CONFIG_REQ(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.port = None + self.pad = [] # 0 - 2 Bytes + + def process_msg(self, packet): + parser.parse_QueueGetConfigReq(self, packet) + + def prints(self): + prints.print_queueReq(self) + + +class OFPT_QUEUE_GET_CONFIG_RES(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.port = None + self.pad = [] # 0 - 6 Bytes + self.queues = [] # Class OFP_QUEUE[] + + def process_msg(self, packet): + parser.parse_QueueGetConfigRes(self, packet) + + def prints(self): + prints.print_queueRes(self) + + +# Auxiliary Data Structures +class OFP_Phy_port: + + def __init__(self): + self.port_id = None + self.hw_addr = None + self.config = None + self.state = None + self.curr = None + self.advertised = None + self.supported = None + self.peer = None + + +class OFP_Match: + + def __init__(self): + self.wildcards = None + self.in_port = None + self.dl_src = None + self.dl_dst = None + self.dl_vlan = None + self.dl_vlan_pcp = None + self.pad1 = None + self.dl_type = None + self.nw_tos = None + self.nw_proto = None + self.pad2 = None + self.nw_src = None + self.nw_dst = None + self.tp_src = None + self.tp_dst = None + + +class OFP_Action: + + def __init__(self): + self.type = None + self.length = None + self.payload = None + +# OFP_STATS_REQ Auxiliary Classes + +class OFP_STATSREQ_FLOWAGG: + + def __init__(self, match, table_id, pad, out_port): + self.match = match + self.table_id = table_id + self.pad = pad + self.out_port = out_port + + +class OFP_STATREQ_PORT: + + def __init__(self, port_number, pad): + self.port_number = port_number + self.pad = pad + + +class OFP_STATREQ_QUEUE: + + def __init__(self, port_number, pad, queue_id): + self.port_number = port_number + self.pad = pad + self.queue_id = queue_id + + +class OFP_STATREQ_VENDOR: + + def __init__(self, vendor_id): + self.vendor_id = vendor_id + + +# OFP_STATS_RES Auxiliary Classes + +class OFP_STATSRES_DESC: + + def __init__(self, mfr_desc, hw_desc, sw_desc, serial_num, dp_desc): + self.mfr_desc = mfr_desc + self.hw_desc = hw_desc + self.sw_desc = sw_desc + self.serial_num = serial_num + self.dp_desc = dp_desc + + +class OFP_STATSRES_FLOW: + + def __init__(self, flows): + self.flows = flows # Class OFP_STAT_FLOW[] + + +class OFP_STATSRES_AGG: + + def __init__(self, packet_count, byte_count, flow_count, pad): + self.packet_count = packet_count + self.byte_count = byte_count + self.flow_count = flow_count + self.pad = pad + + +class OFP_STATSRES_TABLE: + + def __init__(self, tables): + self.tables = tables # Class OFP_STAT_TABLE[] + + +class OFP_STATRES_PORT: + + def __init__(self, ports): + self.ports = ports # Class OFP_STAT_PORT[] + + +class OFP_STATRES_QUEUE: + + def __init__(self, queues): + self.queues = queues # Class OFP_STAT_QUEUE[] + + +class OFP_STATRES_VENDOR: + + def __init__(self, vendor_id, data): + self.vendor_id = vendor_id + self.data = data + + +class OFP_STAT_FLOW: + + def __init__(self): + self.length = None + self.table_id = None + self.pad = None + self.match = None + self.duration_sec = None + self.duration_nsec = None + self.priority = None + self.idle_timeout = None + self.hard_timeout = None + self.pad2 = None + self.cookie = None + self.packet_count = None + self.byte_count = None + self.actions = None + + +class OFP_STAT_PORT: + + def __init__(self): + self.port_number = None + self.pad = None + self.rx_packets = None + self.tx_packets = None + self.rx_bytes = None + self.tx_bytes = None + self.rx_dropped = None + self.tx_dropped = None + self.rx_errors = None + self.tx_errors = None + self.rx_frame_err = None + self.rx_over_err = None + self.rx_crc_err = None + self.collisions = None + + +class OFP_STAT_TABLE: + + def __init__(self): + self.table_id = None + self.pad = None + self.name = None + self.wildcards = None + self.max_entries = None + self.active_count = None + self.lookup_count = None + self.matched_count = None + + +class OFP_STAT_QUEUE: + + def __init__(self): + self.length = None + self.pad = None + self.queue_id = None + self.tx_bytes = None + self.tx_packets = None + self.tx_errors = None + + +class OFP_QUEUE: + + def __init__(self): + self.queue_id = None + self.length = None + self.pad = None + self.properties = None + + +class OFP_QUEUE_PROPERTIES: + + def __init__(self): + self.property = None + self.length = None + self.pad = None + self.payload = None + + +class OFP_QUEUE_PROP_PAYLOAD: + + def __init__(self): + self.rate = None + self.pad = None \ No newline at end of file diff --git a/ofp_sniffer.py b/ofp_sniffer.py index 24edb93..76b1138 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -32,7 +32,8 @@ def process_packet(header, packet): packet: packet captured from file or interface """ global ctr # packet counter - if len(packet) >= 62: + + if len(packet) >= 62 and position_defined(): time = datetime.datetime.now() pkt = Packet(packet, print_options, sanitizer, ctr) pkt.process_packet_header(header, time) @@ -46,12 +47,32 @@ def process_packet(header, packet): ctr += 1 +def position_defined(): + """ + In case user wants to see a specific packet inside a + specific pcap file, provide file name with the position + -r file.pcap:position + Returns: + True if ctr is good + False: if ctr is not good + """ + if position > 0: + if ctr == position: + return True + else: + return False + else: + return True + + def main(argv): """ This is how it starts: cap.loop continuously capture packets w/ pcapy print_options and sanitizer are global variables """ cap.loop(-1, process_packet) + +# Once code is considered "done", remove comments # try: # cap.loop(-1, process_packet) # except KeyboardInterrupt: @@ -61,5 +82,5 @@ def main(argv): # print exception if __name__ == "__main__": - cap, print_options, sanitizer = gen.cli.get_params(sys.argv) + cap, position, print_options, sanitizer = gen.cli.get_params(sys.argv) main(sys.argv) \ No newline at end of file diff --git a/tcpiplib/prints.py b/tcpiplib/prints.py index fe3a7eb..f316ccb 100644 --- a/tcpiplib/prints.py +++ b/tcpiplib/prints.py @@ -125,8 +125,8 @@ def print_vlan(vlan): Args: vlan: class VLAN """ - print ('VLAN: PCP: %s CFI: %s VID: %s' % - (vlan.pcp, vlan.cfi, red(vlan.vid))) + print ('VLAN: PCP: %s CFI: %s VID: %s Protocol: %s' % + (vlan.pcp, vlan.cfi, red(vlan.vid), hex(vlan.ethertype))) def print_arp(arp): From 2228772d7bb13cad5472d3786d691215a58c762f Mon Sep 17 00:00:00 2001 From: Jeronimo Bezerra Date: Mon, 9 May 2016 22:35:01 -0400 Subject: [PATCH 26/88] Added new filters, improved resilience removing OFMessages cut by MTU issues, added support for user define a specific packet inside a libpcap.file, improved the exceptions --- gen/cli.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gen/cli.py b/gen/cli.py index d72f27c..bdd0593 100644 --- a/gen/cli.py +++ b/gen/cli.py @@ -59,6 +59,8 @@ def check_file_position(file): def start_capture(capfile, infilter, dev): + + position = 0 try: if len(capfile) > 0: capfile, position = check_file_position(capfile) From 695ba1771bb93d0e764ab05809f816186dcb054c Mon Sep 17 00:00:00 2001 From: jab1982 Date: Fri, 22 Jul 2016 14:20:57 +0200 Subject: [PATCH 27/88] Restarting the development of version 0.3. Many bug fixes, PEP8 adjustments and error handling. --- docs/TODO | 10 ++ example_filter.json | 3 +- gen/__init__.py | 1 - gen/cli.py | 81 +++++++---- gen/filters.py | 69 +++++++--- gen/packet.py | 83 ++++++++---- gen/prints.py | 7 +- gen/proxies.py | 48 +++++-- gen/termcolor.py | 168 ----------------------- of10/dissector.py | 124 ++++++++--------- of10/packet.py | 17 ++- of10/parser.py | 90 ++++++------ of10/prints.py | 46 +++---- of10/vendors.py | 7 +- of13/packet.py | 323 ++++++++++++++++++++++++++++++++------------ of13/vendors.py | 0 ofp_sniffer.py | 61 +++++---- tcpiplib/packet.py | 30 ++-- tcpiplib/prints.py | 34 ++--- tcpiplib/tcpip.py | 23 +++- 20 files changed, 688 insertions(+), 537 deletions(-) delete mode 100644 gen/termcolor.py create mode 100644 of13/vendors.py diff --git a/docs/TODO b/docs/TODO index e69de29..ec0c46f 100644 --- a/docs/TODO +++ b/docs/TODO @@ -0,0 +1,10 @@ + # TODO clear all entries inside the code files + + # TODO: Add a debug mode + +Document Installation: + + pcapy + Hexdump - print hexdump output + termcolor - to color some outputs + netaddr - for IPv6 \ No newline at end of file diff --git a/example_filter.json b/example_filter.json index 832a9d8..1f5345a 100644 --- a/example_filter.json +++ b/example_filter.json @@ -2,11 +2,12 @@ "allowed_of_versions": { "1.0": { "rejected_of_types": [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19 + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ] }, "1.3": { "rejected_of_types": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ] } }, diff --git a/gen/__init__.py b/gen/__init__.py index 532e200..e5651ae 100644 --- a/gen/__init__.py +++ b/gen/__init__.py @@ -4,7 +4,6 @@ import gen.packet import gen.prints import gen.proxies -import gen.termcolor # Package of10 - everything specific to OpenFlow 1.0 diff --git a/gen/cli.py b/gen/cli.py index bdd0593..a87e22a 100644 --- a/gen/cli.py +++ b/gen/cli.py @@ -1,3 +1,8 @@ +""" + This code handles the CLI parameters +""" + + import sys import getopt import json @@ -8,9 +13,12 @@ NO_COLOR = False -def usage(file): - """ This funcion prints the Usage in case of errors or help needed. +def usage(filename): + """ + This funcion prints the Usage in case of errors or help needed. Always ends after printing this lines below. + Args: + filename: name of the script called (usually ofp_sniffer.py) """ print (('Usage: \n %s [-p min|full] [-f pcap_filter] [-F filter_file]' ' [-i dev] [-r pcap_file]\n' @@ -25,41 +33,58 @@ def usage(file): '\t -h or --help : prints this guidance\n' '\t -c or --no-colors: removes colors\n' '\t -d or --debug: enable debug\n' - '\t -v or --version : prints version\n') % file) + '\t -v or --version : prints version\n') % filename) sys.exit(0) def read_sanitizer(sanitizer_file): + """ + Read the JSON file provided through -F + Args: + sanitizer_file: file provided + Returns: + json content of the file provided + """ try: - jfile = open(sanitizer_file, 'ro') - json_content = json.loads(jfile.read()) - except: + with open(sanitizer_file) as jfile: + json_content = json.loads(jfile.read()) + except Exception as error: msg = 'Error Opening the sanitizer file\n' msg += 'Please check your JSON file. Maybe the permission is wrong' msg += ' or the JSON syntax is incorrect. Try the following:\n' msg += 'cat %s | python -m json.tool' print msg % sanitizer_file + print "Error seen: %s" % error sys.exit(0) - return (json_content) + return json_content -def check_file_position(file): +def check_file_position(filename): """ Check if -r file was inserted with colon (:) If yes, only read the position specified after colon Args: - file: User's input -r + filename: User's input -r Returns: - position + position number """ - new_file = file.partition(":")[0] - position = file.partition(":")[2] + new_file = filename.partition(":")[0] + position = filename.partition(":")[2] return new_file, int(position) if len(position) is not 0 else 0 def start_capture(capfile, infilter, dev): - + """ + With all information in hand, start capturing packets + Args: + capfile: in case user provides a pcap file + infilter: any tcpdump filters + dev: network device to sniffer + Returns: + cap object + position number + """ position = 0 try: if len(capfile) > 0: @@ -71,17 +96,28 @@ def start_capture(capfile, infilter, dev): cap = pcapy.open_live(dev, 65536, 1, 0) except Exception as exception: - print exception - return -1 + print "Error: %s" % exception + print "Exiting..." + sys.exit(3) + + if len(infilter) is 0: + infilter = " port 6633 " + cap.setfilter(infilter) - finally: - if len(infilter) is 0: - infilter = " port 6633 " - cap.setfilter(infilter) - return cap, position + return cap, position def get_params(argv): + """ + Get CLI params provided by user + Args: + argv: CLI params + Returns: + cap - pcap object + position - position to read + print_options - printing options + sanitizer - sanitizer filter + """ # Handle all input params letters = 'f:F:i:r:p:ohvcd' keywords = ['print=', 'pcap-filter=', 'sanitizer-file=', 'interface=', @@ -90,6 +126,7 @@ def get_params(argv): # Default Values input_filter, sanitizer_file, dev, captured_file = '', '', 'eth0', '' + opts = None try: opts, extraparams = getopt.getopt(argv[1:], letters, keywords) @@ -130,13 +167,11 @@ def get_params(argv): usage(argv[0]) if len(sanitizer_file) == 0: - sanitizer = {'allowed_of_versions': {}, - 'filters': {}} + sanitizer = {'allowed_of_versions': {}, 'filters': {}} else: print_options['filters'] = 1 sanitizer = read_sanitizer(sanitizer_file) - cap, position = start_capture(captured_file, input_filter, dev) return cap, position, print_options, sanitizer diff --git a/gen/filters.py b/gen/filters.py index 663bc26..1854d97 100644 --- a/gen/filters.py +++ b/gen/filters.py @@ -1,25 +1,30 @@ -''' +""" Filters to be used -''' + Any customized print filters should be inserted in this file + Filters are provided via CLI option -F json-file +""" + + import tcpiplib.tcpip +import tcpiplib.packet def filter_msg(msg): """ This method will be the core of all filters. Any new filter comes here Args: - msg: class OFMessage + msg: OFMessage class Returns: False: Don' filter packet True: Filter it (don't print) """ if msg.print_options['filters'] is 0: - # User hasn't selected -F + # User hasn't selected CLI option -F return False # Filter per OF Version if filter_of_version(msg): - return True + return True # Filter per OF Message Type if filter_of_type(msg): @@ -33,22 +38,43 @@ def filter_msg(msg): def filter_of_version(msg): - # Check if the OpenFlow version is allowed + """ + Check if the OpenFlow version is allowed + Args: + msg: OFMessage class + Returns: + False: Don' filter packet + True: Filter it (don't print) + """ name_version = tcpiplib.tcpip.get_ofp_version(msg.ofp.version) supported_versions = [] - for version in msg.sanitizer['allowed_of_versions']: - supported_versions.append(version) - if name_version not in supported_versions: - return True + try: + for version in msg.sanitizer['allowed_of_versions']: + supported_versions.append(version) + if name_version not in supported_versions: + return True + except KeyError: + pass return False def filter_of_type(msg): + """ + Filter per OF Message Type + Args: + msg: OFMessage class + Returns: + False: Don' filter packet + True: Filter it (don't print) + """ name_version = tcpiplib.tcpip.get_ofp_version(msg.ofp.version) # OF Types to be ignored through json file (-F) - rejected_types = msg.sanitizer['allowed_of_versions'][name_version] - if msg.ofp.type in rejected_types['rejected_of_types']: - return True + try: + rejected_types = msg.sanitizer['allowed_of_versions'][name_version] + if msg.ofp.type in rejected_types['rejected_of_types']: + return True + except KeyError: + pass return False @@ -56,14 +82,17 @@ def ethertype_filters(msg): """ Filter PacketIn and PacketOut messages with LLDP or BDDP Sanitizer filter (-F), entry "filters", "ethertype" - Args: - msg: class OFMessage - Returns: - False: Don' filter packet - True: Filter it (don't print) + Args: + msg: class OFMessage + Returns: + False: Don' filter packet + True: Filter it (don't print) """ if msg.ofp.type in [10, 13]: - filters = msg.sanitizer['filters']['ethertypes'] + try: + filters = msg.sanitizer['filters']['ethertypes'] + except KeyError: + return False if not len(filters): # No filters return False @@ -82,6 +111,8 @@ def ethertype_filters(msg): if next_protocol in [2054] and filters['arp']: return True except KeyError: + # If there is no entry 'lldp' for example, Python will complain. + # So, just ignore because user does not want to filter lldp. pass # Other Ethertypes listed as hex diff --git a/gen/packet.py b/gen/packet.py index a380f46..6514c64 100644 --- a/gen/packet.py +++ b/gen/packet.py @@ -11,12 +11,7 @@ class Packet: used to process EACH IP packet. Each IP packet import tcpiplib.prints from tcpiplib.tcpip import get_openflow_header import gen.proxies - - -IP_PROTOCOL = 8 -TCP_PROTOCOL = 6 -TCP_FLAG_PUSH = 8 -OF_HEADER_SIZE = 8 +from tcpiplib.packet import IP_PROTOCOL, TCP_PROTOCOL, TCP_FLAG_PUSH class OFMessage: @@ -24,12 +19,18 @@ class OFMessage: Used to process all data regarding this OpenFlow message """ def __init__(self, pkt): + """ + Instantiate OFMessage class + Args: + self: this class + pkt: Packet class + """ + # main_packet = full TCP/IP packet self.main_packet = pkt self.packet = pkt.this_packet self.offset = 0 self.print_options = self.main_packet.print_options self.sanitizer = self.main_packet.sanitizer - # self.message = None # ofp is the real OpenFlow message self.ofp = None @@ -38,18 +39,18 @@ def process_openflow_header(self, of_header): """ This method instantiate the class equivalent to the OpenFlow message type. - Args: - of_header: dictionary of the OpenFlow header + Args: + of_header: dictionary of the OpenFlow header - Returns: - 0: message type unknown or OpenFlow version non-dissected - 1: No error + Returns: + 0: message type unknown or OpenFlow version non-dissected + 1: No error """ if of_header['version'] is 1: - self.ofp = of10.packet.instantiate(self, of_header) - if type(self.ofp) is type(int()): + self.ofp = of10.packet.instantiate(of_header) + if isinstance(self.ofp, (int, long)): print ('Debug: Packet: %s not OpenFlow\n' % - (self.main_packet.position)) + self.main_packet.position) self.offset += 8 self.packet = self.packet[8:] return 0 @@ -66,8 +67,8 @@ def handle_malformed_pkts(self, exception): """ In case the OpenFlow message processing crashes, this function tries to give some ideas of what happened - Args: - exception = generated expection + Args: + exception: generated expection """ string = ('!!! MalFormed Packet: %s' % self.main_packet.position) print 'message %s\n Details about the Error:' % string @@ -76,42 +77,63 @@ def handle_malformed_pkts(self, exception): def process_openflow_body(self, of_header): """ Process the OpenFlow content - starts with header - Args: - of_header: dictionary of the OpenFlow header - - Returns: - 0: Error with the OpenFlow header - 1: Success - -1: Error processing the OpenFlow content + Args: + of_header: dictionary of the OpenFlow header + Returns: + 0: Error with the OpenFlow header + 1: Success + -1: Error processing the OpenFlow content """ if not self.process_openflow_header(of_header): return 0 try: # support for proxies + # PacketOut will be used to collect DPID, but at this moment + # just save DEST IP and DEST TCP port if of_header['type'] is 13: gen.proxies.insert_ip_port(self.main_packet.l3.d_addr, self.main_packet.l4.dest_port) + self.ofp.process_msg(self.packet) return 1 + except Exception as exception: self.handle_malformed_pkts(exception) return -1 def print_packet(self, pkt): + """ + Generic printing function + Args: + pkt: Packet class + """ + # Check if there is any printing filter if not gen.filters.filter_msg(self): + # Only prints TCP/IP header once + # A TCP/IP packet might contain multiple OpenFlow messages if pkt.printed_header is False: tcpiplib.prints.print_headers(pkt) pkt.printed_header = True + # Print OpenFlow header - version independent tcpiplib.prints.print_openflow_header(self.ofp) + # Print OpenFlow message body self.ofp.prints() print class Packet: """ - Used to save all data about the packet + Used to save all data about the TCP/IP packet """ def __init__(self, packet, print_options, sanitizer, ctr): + """ + Instantiate this class + Args: + packet: the whole captured packet from NIC or pcap file + print_options: printing options provided by user + sanitizer: filter file + ctr: position of this packet in the packet capture + """ # Raw packet self.packet = packet @@ -128,7 +150,7 @@ def __init__(self, packet, print_options, sanitizer, ctr): self.print_options = print_options self.sanitizer = sanitizer - # TCP/IP header + # Instantiate TCP/IP headers self.l1 = tcpiplib.packet.L1() self.l2 = tcpiplib.packet.Ethernet() self.l3 = tcpiplib.packet.IP() @@ -144,9 +166,9 @@ def process_packet_header(self, header, time): Process TCP/IP Header, from Layer 1 to TCP. Each layer has a different class. Methods parse are used per layer to dissect it - Args: - header: header of the captured packet - time: time the packet was captured + Args: + header: header of the captured packet + time: time the packet was captured """ self.l1.parse(header, time) self.offset = self.l2.parse(self.packet) @@ -171,7 +193,7 @@ def process_openflow_messages(self): # let's remove the current OpenFlow message from the packet of_header, length = self.get_of_message_length() if length < 8: - # MalFormed Packet + # MalFormed Packet - it could be a fragment return 0 self.this_packet = self.packet[self.offset:self.offset+length] @@ -181,6 +203,7 @@ def process_openflow_messages(self): return 1 # Instantiate the OpenFlow message in the ofmsgs array + # A TCP/IP packet might contain multiple OpenFlow messages # Process the content, using cur_msg position of the array of msgs self.ofmsgs.insert(self.cur_msg, OFMessage(self)) diff --git a/gen/prints.py b/gen/prints.py index a417a3b..41311ff 100644 --- a/gen/prints.py +++ b/gen/prints.py @@ -1,4 +1,9 @@ -from gen.termcolor import colored +""" + Generic printing functions +""" + + +from termcolor import colored import gen.cli diff --git a/gen/proxies.py b/gen/proxies.py index f3a6ee2..67f03ae 100644 --- a/gen/proxies.py +++ b/gen/proxies.py @@ -1,41 +1,59 @@ +""" + This code is used to associate IP address seen to a switch when partitioning is in place + If FlowSpace Firewall or FlowVisor is not used, this module is not useful. +""" + + D_ADDR = None DEST_PORT = None NET = {} -name = {"cc4e249102000000": "andes2", - "cc4e249126000000": "andes1", - "cc4e244b11000000": "sol2", - "0024389406000000": "mct01", - "002438af17000000": "mct02", - "2438af17000000": "mct02", - "24389406000000": "mct01"} + +# TODO: This dictionary with DPID and names should be moved to a configuration file +dpid_dict = {"cc4e249102000000": "andes2", + "cc4e249126000000": "andes1", + "cc4e244b11000000": "sol2", + "0024389406000000": "mct01", + "002438af17000000": "mct02", + "2438af17000000": "mct02", + "24389406000000": "mct01"} def insert_ip_port(dest_ip, dest_port): + """ + Once the TCP/IP packet is dissected and a OpenFlow message type 13 + (PacketOut) is seen, save both destination IP and TCP port + Args: + dest_ip: destination IP address + dest_port: destination TCP port + """ global D_ADDR global DEST_PORT D_ADDR = dest_ip DEST_PORT = dest_port -def support_fsfw(lldp): +def save_dpid(lldp): + """ + Get the DPID from the LLDP.c_id + Args: + lldp: LLDP class + """ global NET ip = D_ADDR port = DEST_PORT try: dpid = lldp.c_id.split(':')[1] - except: + except IndexError: dpid = lldp.c_id - name = get_name_dpid(dpid) - NET[ip, port] = name - return + sw_name = get_name_dpid(dpid) + NET[ip, port] = sw_name def get_name_dpid(dpid): - sw_name = name.get(dpid) + sw_name = dpid_dict.get(dpid) if sw_name is not None: return sw_name - return 'OFswitch' @@ -43,4 +61,4 @@ def get_ip_name(ip, port): for i, j in NET.iteritems(): if i == (ip, port): return '%s(%s)' % (ip, j) - return ip \ No newline at end of file + return ip diff --git a/gen/termcolor.py b/gen/termcolor.py deleted file mode 100644 index f11b824..0000000 --- a/gen/termcolor.py +++ /dev/null @@ -1,168 +0,0 @@ -# coding: utf-8 -# Copyright (c) 2008-2011 Volvox Development Team -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -# Author: Konstantin Lepa - -"""ANSII Color formatting for output in terminal.""" - -from __future__ import print_function -import os - - -__ALL__ = [ 'colored', 'cprint' ] - -VERSION = (1, 1, 0) - -ATTRIBUTES = dict( - list(zip([ - 'bold', - 'dark', - '', - 'underline', - 'blink', - '', - 'reverse', - 'concealed' - ], - list(range(1, 9)) - )) - ) -del ATTRIBUTES[''] - - -HIGHLIGHTS = dict( - list(zip([ - 'on_grey', - 'on_red', - 'on_green', - 'on_yellow', - 'on_blue', - 'on_magenta', - 'on_cyan', - 'on_white' - ], - list(range(40, 48)) - )) - ) - - -COLORS = dict( - list(zip([ - 'grey', - 'red', - 'green', - 'yellow', - 'blue', - 'magenta', - 'cyan', - 'white', - ], - list(range(30, 38)) - )) - ) - - -RESET = '\033[0m' - - -def colored(text, color=None, on_color=None, attrs=None): - """Colorize text. - - Available text colors: - red, green, yellow, blue, magenta, cyan, white. - - Available text highlights: - on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan, on_white. - - Available attributes: - bold, dark, underline, blink, reverse, concealed. - - Example: - colored('Hello, World!', 'red', 'on_grey', ['blue', 'blink']) - colored('Hello, World!', 'green') - """ - if os.getenv('ANSI_COLORS_DISABLED') is None: - fmt_str = '\033[%dm%s' - if color is not None: - text = fmt_str % (COLORS[color], text) - - if on_color is not None: - text = fmt_str % (HIGHLIGHTS[on_color], text) - - if attrs is not None: - for attr in attrs: - text = fmt_str % (ATTRIBUTES[attr], text) - - text += RESET - return text - - -def cprint(text, color=None, on_color=None, attrs=None, **kwargs): - """Print colorize text. - - It accepts arguments of print function. - """ - - print((colored(text, color, on_color, attrs)), **kwargs) - - -if __name__ == '__main__': - print('Current terminal type: %s' % os.getenv('TERM')) - print('Test basic colors:') - cprint('Grey color', 'grey') - cprint('Red color', 'red') - cprint('Green color', 'green') - cprint('Yellow color', 'yellow') - cprint('Blue color', 'blue') - cprint('Magenta color', 'magenta') - cprint('Cyan color', 'cyan') - cprint('White color', 'white') - print(('-' * 78)) - - print('Test highlights:') - cprint('On grey color', on_color='on_grey') - cprint('On red color', on_color='on_red') - cprint('On green color', on_color='on_green') - cprint('On yellow color', on_color='on_yellow') - cprint('On blue color', on_color='on_blue') - cprint('On magenta color', on_color='on_magenta') - cprint('On cyan color', on_color='on_cyan') - cprint('On white color', color='grey', on_color='on_white') - print('-' * 78) - - print('Test attributes:') - cprint('Bold grey color', 'grey', attrs=['bold']) - cprint('Dark red color', 'red', attrs=['dark']) - cprint('Underline green color', 'green', attrs=['underline']) - cprint('Blink yellow color', 'yellow', attrs=['blink']) - cprint('Reversed blue color', 'blue', attrs=['reverse']) - cprint('Concealed Magenta color', 'magenta', attrs=['concealed']) - cprint('Bold underline reverse cyan color', 'cyan', - attrs=['bold', 'underline', 'reverse']) - cprint('Dark blink concealed white color', 'white', - attrs=['dark', 'blink', 'concealed']) - print(('-' * 78)) - - print('Test mixing:') - cprint('Underline red on grey color', 'red', 'on_grey', - ['underline']) - cprint('Reversed green on red color', 'green', 'on_red', ['reverse']) - diff --git a/of10/dissector.py b/of10/dissector.py index c7c1a40..bad27d3 100644 --- a/of10/dissector.py +++ b/of10/dissector.py @@ -1,7 +1,7 @@ -''' +""" This is the OpenFlow 1.0 dictionary/dissector - Here messages, types and codes are converted to names -''' + Here messages, types and codes are converted to names. +""" def get_ofp_type(of_type): @@ -29,17 +29,17 @@ def get_ofp_type(of_type): 21: 'QueueGetConfigRes'} try: return of_types[of_type] - except: + except KeyError: return 'UnknownType(%s)' % of_type def get_ofp_error(error_type, code): - errors_types = {} - codes = {} + errors_types = dict() + error_codes = dict() - # Starts with an Error + # Starts with an Error - exception errors_types[error_type] = 'UnknownType(%s)' % error_type - codes[code] = 'UnknownCode(%s)' % code + error_codes[code] = 'UnknownCode(%s)' % code # Error Types if error_type in range(0, 6): @@ -52,61 +52,61 @@ def get_ofp_error(error_type, code): # Error Codes per Error Type if error_type == 0: - if code in range(0, 2): - codes = {0: 'Incompatible(0)', - 1: 'EPerm(1)'} + if error_codes in range(0, 2): + error_codes = {0: 'Incompatible(0)', + 1: 'EPerm(1)'} elif error_type == 1: - if code in range(0, 9): - codes = {0: 'BadVersion(0)', - 1: 'BadType(1)', - 2: 'BadStat(2)', - 3: 'BadVendor(3)', - 4: 'BadSubtype(4)', - 5: 'EPerm(5)', - 6: 'BadLength(6)', - 7: 'BufferEmpty(7)', - 8: 'BufferUnknown(8)'} + if error_codes in range(0, 9): + error_codes = {0: 'BadVersion(0)', + 1: 'BadType(1)', + 2: 'BadStat(2)', + 3: 'BadVendor(3)', + 4: 'BadSubtype(4)', + 5: 'EPerm(5)', + 6: 'BadLength(6)', + 7: 'BufferEmpty(7)', + 8: 'BufferUnknown(8)'} elif error_type == 2: - if code in range(0, 9): - codes = {0: 'BadType', - 1: 'BadLength', - 2: 'BadVendor', - 3: 'BadVendorType', - 4: 'BadOutPort', - 5: 'BadArgument', - 6: 'EPerm', - 7: 'TooMany', - 8: 'BadQueue'} + if error_codes in range(0, 9): + error_codes = {0: 'BadType', + 1: 'BadLength', + 2: 'BadVendor', + 3: 'BadVendorType', + 4: 'BadOutPort', + 5: 'BadArgument', + 6: 'EPerm', + 7: 'TooMany', + 8: 'BadQueue'} elif error_type == 3: - if code == 0 or code in range(2, 7): - codes = {0: 'AllTablesFull(0)', - 2: 'Overlap(2)', - 3: 'EPerm(3)', - 4: 'BadEmergTimeout(4)', - 5: 'BadCommand(5)', - 6: 'Unsupported(6)'} + if error_codes == 0 or error_codes in range(2, 7): + error_codes = {0: 'AllTablesFull(0)', + 2: 'Overlap(2)', + 3: 'EPerm(3)', + 4: 'BadEmergTimeout(4)', + 5: 'BadCommand(5)', + 6: 'Unsupported(6)'} elif error_type == 4: - if code in range(0, 2): - codes = {0: 'BadPort(0)', - 1: 'BadHwAddr(1)'} + if error_codes in range(0, 2): + error_codes = {0: 'BadPort(0)', + 1: 'BadHwAddr(1)'} elif error_type == 5: - if code in range(0, 3): - codes = {0: 'BadPort(0)', - 1: 'BadQueue(1)', - 2: 'EPerm(2)'} + if error_codes in range(0, 3): + error_codes = {0: 'BadPort(0)', + 1: 'BadQueue(1)', + 2: 'EPerm(2)'} - return errors_types[error_type], codes[code] + return errors_types[error_type], error_codes[code] def get_ofp_vendor(vendor_id): # NICIRA / OVS: 0x2320 or 8992 if vendor_id == 8992: - return 'NICIRA(' + hex(vendor_id) + ')' + return "NICIRA(%s)" % (hex(vendor_id)) else: return str(vendor_id) @@ -119,7 +119,7 @@ def get_ofp_command(command): 4: 'DeleteStrict(4)'} try: return commands[command] - except: + except KeyError: return 'UnknownCommand(%s)' % command @@ -127,7 +127,7 @@ def get_vlan(vlan): vlans = {65535: 'Untagged(0xFFFF)'} try: return vlans[vlan] - except: + except KeyError: return vlan @@ -138,7 +138,7 @@ def get_ofp_flags(flag): 3: 'Emerg(3)'} try: return flags[flag] - except: + except KeyError: return 'UnknownFlag(%s)' % flag @@ -148,7 +148,7 @@ def get_flow_removed_reason(reason): 2: 'Delete(2)'} try: return rsn[reason] - except: + except KeyError: return 'UnknownReason(%s)' % reason @@ -163,7 +163,7 @@ def get_feature_res_capabilities(cap): 128: 'ARP_MATCH_IP(0x80)'} try: return caps[cap] - except: + except KeyError: return 'UnknownCapability(%s)' % cap @@ -182,7 +182,7 @@ def get_feature_res_actions(action): 2048: 'ENQUEUE(0x800)'} try: return actions[action] - except: + except KeyError: return 'UnknownAction(%s)' % action @@ -198,7 +198,7 @@ def get_phy_port_id(p_id): 65535: 'None(0xFFFF)'} try: return ids[p_id] - except: + except KeyError: return '%s' % p_id @@ -212,7 +212,7 @@ def get_phy_config(p_cfg): 64: 'NoPacketIn(0x40)'} try: return cfg[p_cfg] - except: + except KeyError: return 'UnknownConfig(%s)' % p_cfg @@ -225,7 +225,7 @@ def get_phy_state(p_state): 16: 'STPMask(0x10)'} try: return state[p_state] - except: + except KeyError: return 'UnknownState(%s)' % p_state @@ -244,7 +244,7 @@ def get_phy_feature(p_feature): 2048: 'PauseAsym(0x800)'} try: return ftr[p_feature] - except: + except KeyError: return 'UnknownFeature(%s)' % p_feature @@ -255,24 +255,24 @@ def get_configres_flags(flag): 3: 'FRAG_MASK(3)'} try: return flags[flag] - except: + except KeyError: return 'UnknownFlag(%s)' % flag -def get_portStatus_reason(reason): +def get_port_status_reason(reason): reasons = {0: 'OFPPR_ADD(0)', 1: 'OFPPR_DELETE(1)', 2: 'OFPPR_MODIFY(2)'} try: return reasons[reason] - except: + except KeyError: return 'UnknownReason(%s)' % reason -def get_packetIn_reason(reason): +def get_packet_in_reason(reason): reasons = {0: 'OFPR_NO_MATCH(0)', 1: 'OFPR_ACTION(1)'} try: return reasons[reason] - except: + except KeyError: return 'UnknownReason(%s)' % reason diff --git a/of10/packet.py b/of10/packet.py index 6c1e378..17da5f9 100644 --- a/of10/packet.py +++ b/of10/packet.py @@ -1,8 +1,18 @@ +""" + This code has the OpenFlow 1.0 associated classes + Module parser.py will be used to parse the pcap content + Module prints.py will be used to print the class content + + Classes on this file are not using the PEP8 CamelCase specification + The idea is to use the same name as used in the OpenFlow specification +""" + + import prints as prints import parser as parser -def instantiate(pkt, of_header): +def instantiate(of_header): if of_header['type'] == 0: return OFPT_HELLO(of_header) elif of_header['type'] == 1: @@ -321,7 +331,7 @@ def __init__(self, of_header): self.stats = None def instantiate(self, *args): - if self.stat_type in [1,2]: + if self.stat_type in [1, 2]: self.stats = OFP_STATSREQ_FLOWAGG(*args) elif self.stat_type == 4: self.stats = OFP_STATREQ_PORT(*args) @@ -427,6 +437,7 @@ class OFP_Phy_port: def __init__(self): self.port_id = None self.hw_addr = None + self.name = None self.config = None self.state = None self.curr = None @@ -462,8 +473,10 @@ def __init__(self): self.length = None self.payload = None + # OFP_STATS_REQ Auxiliary Classes + class OFP_STATSREQ_FLOWAGG: def __init__(self, match, table_id, pad, out_port): diff --git a/of10/parser.py b/of10/parser.py index 635f615..4f3ef13 100644 --- a/of10/parser.py +++ b/of10/parser.py @@ -10,6 +10,7 @@ import of10.dissector import of10.prints import of10.vendors +import of10.packet import tcpiplib.tcpip import tcpiplib.packet @@ -25,6 +26,7 @@ def parse_Error(msg, packet): ofe = unpack('!HH', of_error) msg.type = ofe[0] msg.code = ofe[1] + msg.data = packet[4:] # ************ EchoReq ***************** @@ -127,7 +129,7 @@ def parse_FeatureRes(msg, packet): while len(packet[start:]) > 0: port = _parse_phy_ports(packet[start:start+48]) ports_array.append(port) - start = start + 48 + start += 48 msg.ports = ports_array return 1 @@ -163,6 +165,7 @@ def process_data(packet, start, msg): Args: packet: class OFMessage start: offset + msg: Returns: payload: array with all classes """ @@ -175,7 +178,7 @@ def process_data(packet, start, msg): # VLAN or not - ETYPE 0x8100 or 33024 etype = '0x0000' - start = start + 14 + start += 14 if eth.protocol in [33024]: """ Frame has VLAN @@ -184,7 +187,7 @@ def process_data(packet, start, msg): vlan.parse(packet[start:start + 4]) payload.append(vlan) etype = vlan.protocol - start = start + 4 + start += 4 else: etype = eth.protocol @@ -196,7 +199,7 @@ def process_data(packet, start, msg): lldp.c_id = 0 else: if msg.type is 13: - gen.proxies.support_fsfw(lldp) + gen.proxies.save_dpid(lldp) payload.append(lldp) return payload @@ -225,7 +228,7 @@ def parse_PacketIn(msg, packet): # buffer_id(32), total_len(16), in_port(16), reason(8), pad(8) pkt_raw = packet[0:10] p_in = unpack('!LHHB1s', pkt_raw) - reason = of10.dissector.get_packetIn_reason(p_in[3]) + reason = of10.dissector.get_packet_in_reason(p_in[3]) msg.buffer_id = p_in[0] msg.total_len = p_in[1] msg.in_port = p_in[2] @@ -235,9 +238,10 @@ def parse_PacketIn(msg, packet): return 1 + # ******************** FlowRemoved *************************** def parse_FlowRemoved(msg, packet): - msg.match = _parse_OFMatch(msg, packet, 0) + msg.match = _parse_OFMatch(packet, 0) of_rem_body = packet[40:40+40] ofrem = unpack('!QHB1sLLH1s1sQQ', of_rem_body) @@ -262,7 +266,7 @@ def parse_FlowRemoved(msg, packet): def parse_PortStatus(msg, packet): port_raw = packet[0:8] port = unpack('!B7s', port_raw) - reason = of10.dissector.get_portStatus_reason(port[0]) + reason = of10.dissector.get_port_status_reason(port[0]) msg.reason = reason msg.pad = port[1] msg.desc = _parse_phy_ports(packet[8:64]) @@ -299,14 +303,14 @@ def process_dst_subnet(wcard): OFPFW_NW_DST_SHIFT = 14 OFPFW_NW_DST_MASK = 1032192 nw_dst_bits = (wcard & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT - return ((32 - nw_dst_bits) if nw_dst_bits < 32 else 0) + return (32 - nw_dst_bits) if nw_dst_bits < 32 else 0 def process_src_subnet(wcard): OFPFW_NW_SRC_SHIFT = 8 OFPFW_NW_SRC_MASK = 16128 nw_src_bits = (wcard & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT - return ((32 - nw_src_bits) if nw_src_bits < 32 else 0) + return (32 - nw_src_bits) if nw_src_bits < 32 else 0 def _process_wildcard(wcard): @@ -325,10 +329,10 @@ def _process_wildcard(wcard): def get_ip_from_long(long_ip): - return (socket.inet_ntoa(struct.pack('!L', long_ip))) + return socket.inet_ntoa(struct.pack('!L', long_ip)) -def _parse_OFMatch(msg, packet, h_size): +def _parse_OFMatch(packet, h_size): match_tmp = of10.packet.OFP_Match() of_match = packet[h_size:h_size+40] ofm = unpack('!LH6s6sHBBHBBHLLHH', of_match) @@ -346,11 +350,9 @@ def _parse_OFMatch(msg, packet, h_size): 'tp_dst': ofm[14]} if wildcard >= ((1 << 22) - 1): - # msg.match.wildcards = 4194303 match_tmp.wildcards = 4194303 return match_tmp elif wildcard == 0: - # msg.match.wildcards = 0 match_tmp.wildcards = 0 return match_tmp else: @@ -381,7 +383,7 @@ def _parse_OFMatch(msg, packet, h_size): # Convert from Dict(ofmatch) to Class ofp_match # For each item on ofmatch, associate the value to the equivalent on # class ofp_match. For example, if there is an ofmatch['in_port'] - # msg.match.inport = ofmatch['in_port']. Others will be None + # match.inport = ofmatch['in_port']. Others will be None require_str = ['dl_src', 'dl_dst', 'nw_src', 'nw_dst'] for match in ofmatch: if match in require_str: @@ -410,7 +412,7 @@ def _parse_OFBody(msg, packet, h_size): msg.flags = ofmod[7] -def get_action(action_type, length, payload): +def get_action(action_type, payload): # 0 - OUTPUT. Returns port and max_length if action_type == 0: type_0 = unpack('!HH', payload) @@ -465,9 +467,9 @@ def get_action(action_type, length, payload): def _parse_OFAction(packet, start): - ''' + """ Actions - ''' + """ # Actions: Header = 4 , plus each possible action # Payload varies: # 4 for types 0,1,2,6,7,8,9,a,ffff @@ -476,7 +478,7 @@ def _parse_OFAction(packet, start): action_header = 4 # Add all actions to a list for future printing actions_list = [] - while (1): + while 1: ofp_action = packet[start:start + action_header] if len(ofp_action) > 0: # Get type and length @@ -484,7 +486,7 @@ def _parse_OFAction(packet, start): ofa_type = ofa[0] ofa_length = ofa[1] - start = start + action_header + start += action_header if ofa_type == 4 or ofa_type == 5 or ofa_type == int('b', 16): total_length = 12 else: @@ -506,7 +508,7 @@ def _parse_OFAction(packet, start): def parse_FlowMod(msg, packet): - msg.match = _parse_OFMatch(msg, packet, 0) + msg.match = _parse_OFMatch(packet, 0) _parse_OFBody(msg, packet, 0) # Actions: Header = 4 , plus each possible action actions_start = 64 @@ -533,14 +535,11 @@ def parse_PortMod(msg, packet): # ******************** StatReq **************************** def parse_StatsReq(msg, packet): - """ Parse StatReq messages - - Args: - msg: - packet: - - Returns: - + """ + Parse StatReq messages + Args: + msg: + packet: """ # Get type = 16bits @@ -561,7 +560,7 @@ def parse_StatsReq(msg, packet): elif msg.stat_type == 1 or msg.stat_type == 2: # Flow(1) or Aggregate(2) # Fields: match(40), table_id(8), pad(8), out_port(16) - match = _parse_OFMatch(msg, packet, start) + match = _parse_OFMatch(packet, start) # 44 Bytes (40B from Match, 4 from header) of_stat_req = packet[start+40:start+40+4] table_id, pad, out_port = unpack('!B1sH', of_stat_req) @@ -646,11 +645,11 @@ def parse_StatsRes(msg, packet): eflow = of10.packet.OFP_STAT_FLOW() - eflow.length = flow[0] + eflow.length = flow[0] eflow.table_id = flow[1] eflow.pad = flow[2] - eflow.match = _parse_OFMatch(msg, packet, start+4) + eflow.match = _parse_OFMatch(packet, start+4) flow_raw = packet[start+44:start+44+44] flow = unpack('!LLHHH6sQQQ', flow_raw) @@ -680,7 +679,6 @@ def parse_StatsRes(msg, packet): msg.instantiate(flows) - elif msg.stat_type == 2: """ Parses Aggregate(2) @@ -782,8 +780,8 @@ def parse_StatsRes(msg, packet): queue.tx_errors = flow[5] queues.append(queue) - count = count - 32 - start = start + 32 + count -= 32 + start += 32 del queue msg.instantiate(queues) @@ -802,7 +800,7 @@ def parse_StatsRes(msg, packet): msg.instantiate(vendor_id, data) else: - print ('StatRes: Unknown Type: %s' % (msg.stat_type)) + print 'StatRes: Unknown Type: %s' % msg.stat_type return 1 @@ -833,7 +831,7 @@ def parse_QueueGetConfigRes(msg, packet): start = 8 queues = [] - while (packet[start:] > 0): + while packet[start:] > 0: # Queues - it could be multiple # queue_id(32), length(16), pad(16) queue_raw = packet[start:start+8] @@ -851,20 +849,20 @@ def parse_QueueGetConfigRes(msg, packet): properties = packet[q_start:q_start+equeue.length-8] properties_list = [] - while len(properties[q_start:] > 0): + while len(properties[q_start:]) > 0: prop_raw = packet[q_start:q_start+8] prop = unpack('!HH4sH6s', prop_raw) - property = of10.packet.OFP_QUEUE_PROPERTIES() - property.property = prop[0] - property.length = prop[1] - property.pad = prop[2] - property.payload = of10.packet.OFP_QUEUE_PROP_PAYLOAD() - property.payload.rate = prop[3] - property.payload.pad = prop[4] + qproperty = of10.packet.OFP_QUEUE_PROPERTIES() + qproperty.property = prop[0] + qproperty.length = prop[1] + qproperty.pad = prop[2] + qproperty.payload = of10.packet.OFP_QUEUE_PROP_PAYLOAD() + qproperty.payload.rate = prop[3] + qproperty.payload.pad = prop[4] - properties_list.append(property) - del property + properties_list.append(qproperty) + del qproperty equeue.properties = properties_list diff --git a/of10/prints.py b/of10/prints.py index 8047bc7..3562693 100644 --- a/of10/prints.py +++ b/of10/prints.py @@ -20,9 +20,9 @@ def print_type_unknown(pkt): def print_pad(pad): """ Used to print pads as a sequence of 0s: 0, 00, 000.. - Args: - pad: pad in str format - Returns: string with '0' + Args: + pad: pad in str format + Returns: string with '0' """ pad_len = len(pad) string = '0' @@ -40,6 +40,7 @@ def print_of_hello(msg): def print_of_error(msg): nCode, tCode = of10.dissector.get_ofp_error(msg.type, msg.code) print ('OpenFlow Error - Type: %s Code: %s' % (red(nCode), red(tCode))) + # TODO: Print data def print_of_feature_req(msg): @@ -107,7 +108,7 @@ def print_ofp_phy_port(port): printed = _dont_print_0(printed) print - # fix it + # TODO: fix it print_port_field(port_id, port.curr, 'curr') print_port_field(port_id, port.advertised, 'advertised') print_port_field(port_id, port.supported, 'supported') @@ -171,7 +172,7 @@ def print_actions(actions): def print_ofp_action(action_type, length, payload): if action_type == 0: - port, max_len = of10.parser.get_action(action_type, length, payload) + port, max_len = of10.parser.get_action(action_type, payload) port = of10.dissector.get_phy_port_id(port) print ('Action - Type: %s Length: %s Port: %s ' @@ -180,13 +181,13 @@ def print_ofp_action(action_type, length, payload): return 'output:' + port elif action_type == 1: - vlan, pad = of10.parser.get_action(action_type, length, payload) + vlan, pad = of10.parser.get_action(action_type, payload) print ('Action - Type: %s Length: %s VLAN ID: %s Pad: %s' % (green('SetVLANID'), length, green(str(vlan)), print_pad(pad))) return 'mod_vlan_vid:' + str(vlan) elif action_type == 2: - vlan_pc, pad = of10.parser.get_action(action_type, length, payload) + vlan_pc, pad = of10.parser.get_action(action_type, payload) print ('Action - Type: %s Length: %s VLAN PCP: %s Pad: %s' % (green('SetVLANPCP'), length, green(str(vlan_pc)), print_pad(pad))) return 'mod_vlan_pcp:' + str(vlan_pc) @@ -197,52 +198,51 @@ def print_ofp_action(action_type, length, payload): return 'strip_vlan' elif action_type == 4: - setDLSrc, pad = of10.parser.get_action(action_type, length, payload) + setDLSrc, pad = of10.parser.get_action(action_type, payload) print ('Action - Type: %s Length: %s SetDLSrc: %s Pad: %s' % (green('SetDLSrc'), length, green(str(eth_addr(setDLSrc))), print_pad(pad))) return 'mod_dl_src:' + str(eth_addr(setDLSrc)) elif action_type == 5: - setDLDst, pad = of10.parser.get_action(action_type, length, payload) + setDLDst, pad = of10.parser.get_action(action_type, payload) print ('Action - Type: %s Length: %s SetDLDst: %s Pad: %s' % (green('SetDLDst'), length, green(str(eth_addr(setDLDst))), print_pad(pad))) return 'mod_dl_dst:' + str(eth_addr(setDLDst)) elif action_type == 6: - nw_addr = of10.parser.get_action(action_type, length, payload) + nw_addr = of10.parser.get_action(action_type, payload) print ('Action - Type: %s Length: %s SetNWSrc: %s' % (green('SetNWSrc'), length, green(str(nw_addr)))) return 'mod_nw_src:' + str(nw_addr) elif action_type == 7: - nw_addr = of10.parser.get_action(action_type, length, payload) + nw_addr = of10.parser.get_action(action_type, payload) print ('Action - Type: %s Length: %s SetNWDst: %s' % (green('SetNWDst'), length, green(str(nw_addr)))) return 'mod_nw_src:' + str(nw_addr) elif action_type == 8: - nw_tos, pad = of10.parser.get_action(action_type, length, payload) + nw_tos, pad = of10.parser.get_action(action_type, payload) print ('Action - Type: %s Length: %s SetNWTos: %s Pad: %s' % (green('SetNWTos'), length, green(str(nw_tos)), print_pad(pad))) return 'mod_nw_tos:' + str(nw_tos) elif action_type == 9: - port, pad = of10.parser.get_action(action_type, length, payload) + port, pad = of10.parser.get_action(action_type, payload) print ('Action - Type: %s Length: %s SetTPSrc: %s Pad: %s' % (green('SetTPSrc'), length, green(str(port)), print_pad(pad))) return 'mod_tp_src:' + str(port) elif action_type == int('a', 16): - port, pad = of10.parser.get_action(action_type, length, payload) + port, pad = of10.parser.get_action(action_type, payload) print ('Action - Type: %s Length: %s SetTPDst: %s Pad: %s' % (green('SetTPDst'), length, green(str(port)), print_pad(pad))) return 'mod_tp_dst:' + str(port) elif action_type == int('b', 16): - port, pad, queue_id = of10.parser.get_action(action_type, length, - payload) + port, pad, queue_id = of10.parser.get_action(action_type, payload) print (('Action - Type: %s Length: %s Enqueue: %s Pad: %s' ' Queue: %s') % (green('Enqueue'), length, green(str(port)), print_pad(pad), @@ -250,7 +250,7 @@ def print_ofp_action(action_type, length, payload): return 'set_queue:' + str(queue_id) elif action_type == int('ffff', 16): - vendor = of10.parser.get_action(action_type, length, payload) + vendor = of10.parser.get_action(action_type, payload) print ('Action - Type: %s Length: %s Vendor: %s' % (green('VENDOR'), length, green(str(vendor)))) return 'VendorType' @@ -292,7 +292,7 @@ def print_of_FlowMod(msg): def _print_portMod_config_mask(variable, name): - print ('PortMod %s:' % (name)), + print ('PortMod %s:' % name), printed = False for i in variable: print of10.dissector.get_phy_config(i), @@ -561,8 +561,8 @@ def print_of_packetOut(msg): def print_data(data): """ Print msg.data from both PacketIn and Packetout - Args: - data: msg.data - array of protocols + Args: + data: msg.data - array of protocols """ next_protocol = '0x0000' eth = data.pop(0) @@ -614,10 +614,10 @@ def print_queueRes_queue(queue): print_queueRes_properties(property) -def print_queueRes_properties(property): +def print_queueRes_properties(qproperty): print ('Property: %s Length: %s Pad: %s' % - (property.property, property.length, print_pad(property.pad))) - print_queueRes_prop_payload(property.payload) + (qproperty.property, qproperty.length, print_pad(qproperty.pad))) + print_queueRes_prop_payload(qproperty.payload) def print_queueRes_prop_payload(payload): diff --git a/of10/vendors.py b/of10/vendors.py index 37cf2e1..c2f2b3d 100644 --- a/of10/vendors.py +++ b/of10/vendors.py @@ -1,3 +1,8 @@ +""" + This code is incomplete + It will be finished on version 0.4 +""" + from struct import unpack @@ -6,4 +11,4 @@ def parse_nicira(packet, start, of_xid): while len(packet[start:start+4]) > 0: ofv_subtype = unpack('!L', packet[start:start+4]) print ('%s ' % ofv_subtype[0]), - start = start + 4 + start += 4 diff --git a/of13/packet.py b/of13/packet.py index 6c1e378..88aa68c 100644 --- a/of13/packet.py +++ b/of13/packet.py @@ -8,19 +8,19 @@ def instantiate(pkt, of_header): elif of_header['type'] == 1: return OFPT_ERROR(of_header) elif of_header['type'] == 2: - return OFPT_ECHO_REQ(of_header) + return OFPT_ECHO_REQUEST(of_header) elif of_header['type'] == 3: - return OFPT_ECHO_RES(of_header) + return OFPT_ECHO_REPLY(of_header) elif of_header['type'] == 4: - return OFPT_VENDOR(of_header) + return OFPT_EXPERIMENTER(of_header) elif of_header['type'] == 5: - return OFPT_FEATURE_REQ(of_header) + return OFPT_FEATURE_REQUEST(of_header) elif of_header['type'] == 6: - return OFPT_FEATURE_RES(of_header) + return OFPT_FEATURE_REPLY(of_header) elif of_header['type'] == 7: - return OFPT_GET_CONFIG_REQ(of_header) + return OFPT_GET_CONFIG_REQUEST(of_header) elif of_header['type'] == 8: - return OFPT_GET_CONFIG_RES(of_header) + return OFPT_GET_CONFIG_REPLY(of_header) elif of_header['type'] == 9: return OFPT_SET_CONFIG(of_header) elif of_header['type'] == 10: @@ -34,19 +34,35 @@ def instantiate(pkt, of_header): elif of_header['type'] == 14: return OFPT_FLOW_MOD(of_header) elif of_header['type'] == 15: - return OFPT_PORT_MOD(of_header) + return OFPT_GROUP_MOD(of_header) elif of_header['type'] == 16: - return OFPT_STATS_REQ(of_header) + return OFPT_PORT_MOD(of_header) elif of_header['type'] == 17: - return OFPT_STATS_RES(of_header) + return OFPT_TABLE_MOD(of_header) elif of_header['type'] == 18: - return OFPT_BARRIER_REQ(of_header) + return OFPT_MULTIPART_REQUEST(of_header) elif of_header['type'] == 19: - return OFPT_BARRIER_RES(of_header) + return OFPT_MULTIPART_REPLY(of_header) elif of_header['type'] == 20: - return OFPT_QUEUE_GET_CONFIG_REQ(of_header) + return OFPT_BARRIER_REQUEST(of_header) elif of_header['type'] == 21: - return OFPT_QUEUE_GET_CONFIG_RES(of_header) + return OFPT_BARRIER_REPLY(of_header) + elif of_header['type'] == 22: + return OFPT_QUEUE_GET_CONFIG_REQUEST(of_header) + elif of_header['type'] == 23: + return OFPT_QUEUE_GET_CONFIG_REPLY(of_header) + elif of_header['type'] == 24: + return OFPT_ROLE_REQUEST(of_header) + elif of_header['type'] == 25: + return OFPT_ROLE_REPLY(of_header) + elif of_header['type'] == 26: + return OFPT_GET_ASYNC_REQUEST(of_header) + elif of_header['type'] == 27: + return OFPT_GET_ASYNC_REPLY(of_header) + elif of_header['type'] == 28: + return OFPT_SET_ASYNC(of_header) + elif of_header['type'] == 29: + return OFPT_METER_MOD(of_header) else: return 0 @@ -64,7 +80,7 @@ class OFPT_HELLO(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.data = None + self.elements = [] # Class ofp_hello_elem_header def process_msg(self, packet): parser.parse_Hello(self, packet) @@ -77,8 +93,9 @@ class OFPT_ERROR(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.type = None - self.code = None + self.type = None # 16 bits + self.code = None # 16 bits + self.data = None def process_msg(self, packet): parser.parse_Error(self, packet) @@ -87,7 +104,7 @@ def prints(self): prints.print_of_error(self) -class OFPT_ECHO_REQ(OFPHeader): +class OFPT_ECHO_REQUEST(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) @@ -100,7 +117,7 @@ def prints(self): prints.print_of_echoreq(self) -class OFPT_ECHO_RES(OFPHeader): +class OFPT_ECHO_REPLY(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) @@ -113,12 +130,12 @@ def prints(self): prints.print_of_echores(self) -class OFPT_VENDOR(OFPHeader): +class OFPT_EXPERIMENTER(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.vendor = None - self.data = None + self.experimenter = None # 32 bits + self.exp_type = None def process_msg(self, packet): parser.parse_Vendor(self, packet) @@ -127,7 +144,7 @@ def prints(self): prints.print_of_vendor(self) -class OFPT_FEATURE_REQ(OFPHeader): +class OFPT_FEATURE_REQUEST(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) @@ -139,17 +156,17 @@ def prints(self): prints.print_of_feature_req(self) -class OFPT_FEATURE_RES(OFPHeader): +class OFPT_FEATURE_REPLY(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.datapath_id = None - self.n_buffers = None - self.n_tbls = None - self.pad = [] # 0-3 Bytes - self.capabilities = [] - self.actions = [] - self.ports = [] # array of class ofp_phy_port + self.datapath_id = None # 64 bits + self.n_buffers = None # 32 bits + self.n_tbls = None # 8 bits + self.auxiliary_id = None # 8 bits + self.pad = [] # 0-2 Bytes + self.capabilities = [] # 32 bits + self.reserved = None # 32 bits def process_msg(self, packet): parser.parse_FeatureRes(self, packet) @@ -158,7 +175,7 @@ def prints(self): prints.print_of_feature_res(self) -class OFPT_GET_CONFIG_REQ(OFPHeader): +class OFPT_GET_CONFIG_REQUEST(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) @@ -170,7 +187,7 @@ def prints(self): prints.print_of_getconfig_req(self) -class OFPT_GET_CONFIG_RES(OFPHeader): +class OFPT_GET_CONFIG_REPLY(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) @@ -202,11 +219,13 @@ class OFPT_PACKET_IN(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.buffer_id = None - self.total_len = None - self.in_port = None - self.reason = None - self.pad = None + self.buffer_id = None # 32 bits + self.total_len = None # 16 bits + self.reason = None # 8 bits + self.table_id = None # 8 bits + self.cookie = None # 64 bits + self.match = None # class ofp_match + self.pad = None # 2 bytes self.data = None def process_msg(self, packet): @@ -220,18 +239,17 @@ class OFPF_FLOW_REMOVED(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.match = OFP_Match() - self.cookie = None - self.priority = None - self.reason = None - self.pad = None - self.duration_sec = None - self.duration_nsec = None - self.idle_timeout = None - self.pad2 = None - self.pad3 = None - self.packet_count = None - self.byte_count = None + self.cookie = None # 64 bits + self.priority = None # 16 bits + self.reason = None # 8 bits + self.table_id = None # 8 bits + self.duration_sec = None # 32 bits + self.duration_nsec = None # 32 bits + self.idle_timeout = None # 16 bits + self.hard_timeout = None # 16 bits + self.packet_count = None # 64 bits + self.byte_count = None # 64 bits + self.match = OFP_Match() # class ofp_match() def process_msg(self, packet): parser.parse_FlowRemoved(self, packet) @@ -244,7 +262,7 @@ class OFPT_PORT_STATUS(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.reason = None + self.reason = None # 8 bits self.pad = [] # 0 - 7 Bytes self.desc = OFP_Phy_port() @@ -259,10 +277,11 @@ class OFPT_PACKET_OUT(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.buffer_id = None - self.in_port = None - self.actions_len = None - self.actions = [] + self.buffer_id = None # 32 bits + self.in_port = None # 32 bits + self.actions_len = None # 16 bits + self.pad = None # 6 bytes + self.actions = [] # class ofp_action_header self.data = None def process_msg(self, packet): @@ -276,16 +295,21 @@ class OFPT_FLOW_MOD(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.match = OFP_Match() - self.cookie = None - self.command = None - self.idle_timeout = None - self.hard_timeout = None - self.priority = None - self.buffer_id = None - self.out_port = None - self.flags = None - self.actions = [] # Class ofp_action_header + self.cookie = None # 64 bits + self.cookie_mask = None # 64 bits + self.table_id = None # 8 bits + self.command = None # 8 bits + + self.idle_timeout = None # 16 bits + self.hard_timeout = None # 16 bits + self.priority = None # 16 bits + self.buffer_id = None # 32 bits + self.out_port = None # 32 bits + self.out_group = None # 32 bits + self.flags = None # 16 bits + self.pad = None # 2 Bytes + self.match = None # Class ofp_match() + self.instructions = [] # Class ofp_instructions def process_msg(self, packet): parser.parse_FlowMod(self, packet) @@ -294,16 +318,35 @@ def prints(self): prints.print_of_FlowMod(self) +class OFPT_GROUP_MOD(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.command = None # 16 bits + self.type = None # 8 bits + self.pad = None # 1 byte + self.group_id = None # 32 bits + self.buckets = [] # class ofp_bucket + + def process_msg(self, packet): + pass + + def prints(self): + pass + + class OFPT_PORT_MOD(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.port_no = None - self.hw_addr = None - self.config = None - self.mask = None - self.advertise = None - self.pad = None + self.port_no = None # 32 bits + self.pad = None # 4 Bytes + self.hw_addr = None # 48 bits + self.pad2 = None # 2 Bytes + self.config = None # 32 bits + self.mask = None # 32 bits + self.advertise = None # advertise + self.pad3 = None # 4 Bytes def process_msg(self, packet): parser.parse_PortMod(self, packet) @@ -312,13 +355,30 @@ def prints(self): prints.print_of_PortMod(self) -class OFPT_STATS_REQ(OFPHeader): +class OFPT_TABLE_MOD(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.stat_type = None - self.flags = None - self.stats = None + self.table_id = None # 8 bits + self.pad = None # 3 x8 bits + self.config = None # 32 bits + + def process_msg(self, packet): + pass + + def prints(self): + pass + + +class OFPT_MULTIPART_REQUEST(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.stat_type = None # 16 bits + self.flags = None # 16 bits + self.pad = None # 4 Bytes + self.body = [] # + self.stats = None # legacy? def instantiate(self, *args): if self.stat_type in [1,2]: @@ -337,13 +397,15 @@ def prints(self): prints.print_ofp_statReq(self) -class OFPT_STATS_RES(OFPHeader): +class OFPT_MULTIPART_REPLY(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.stat_type = None - self.flags = None - self.stats = None + self.stat_type = None # 16 bits + self.flags = None # 16 bits + self.pad = None # 4 bytes + self.body = None # + self.stats = None # legacy? def instantiate(self, *args): if self.stat_type == 0: @@ -368,7 +430,7 @@ def prints(self): prints.print_ofp_statRes(self) -class OFPT_BARRIER_REQ(OFPHeader): +class OFPT_BARRIER_REQUEST(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) @@ -380,7 +442,7 @@ def prints(self): pass -class OFPT_BARRIER_RES(OFPHeader): +class OFPT_BARRIER_REPLY(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) @@ -392,12 +454,12 @@ def prints(self): pass -class OFPT_QUEUE_GET_CONFIG_REQ(OFPHeader): +class OFPT_QUEUE_GET_CONFIG_REQUEST(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.port = None - self.pad = [] # 0 - 2 Bytes + self.port = None # 32 bits + self.pad = [] # 4 Bytes def process_msg(self, packet): parser.parse_QueueGetConfigReq(self, packet) @@ -406,12 +468,12 @@ def prints(self): prints.print_queueReq(self) -class OFPT_QUEUE_GET_CONFIG_RES(OFPHeader): +class OFPT_QUEUE_GET_CONFIG_REPLY(OFPHeader): def __init__(self, of_header): OFPHeader.__init__(self, of_header) - self.port = None - self.pad = [] # 0 - 6 Bytes + self.port = None # 32 bits + self.pad = [] # 4 Bytes self.queues = [] # Class OFP_QUEUE[] def process_msg(self, packet): @@ -421,6 +483,93 @@ def prints(self): prints.print_queueRes(self) +class OFPT_ROLE_REQUEST(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.role = None # 16 bits + self.pad = None # 4 bytes + self.generation_id = None # 64 bits + + def process_msg(self, packet): + pass + + def prints(self): + pass + + +class OFPT_ROLE_REPLY(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.role = None # 16 bits + self.pad = None # 4 bytes + self.generation_id = None # 64 bits + + def process_msg(self, packet): + pass + + def prints(self): + pass + +class OFPT_GET_ASYNC_REQUEST(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + + def process_msg(self, packet): + pass + + def prints(self): + pass + + +class OFPT_GET_ASYNC_REPLY(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.packet_in_mask = None # 2 x 32 bits + self.port_status_mask = None # 2 x 32 bits + self.flow_removed_mask = None # 2 x 32 bits + + def process_msg(self, packet): + pass + + def prints(self): + pass + + +class OFPT_SET_ASYNC(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.packet_in_mask = None # 2 x 32 bits + self.port_status_mask = None # 2 x 32 bits + self.flow_removed_mask = None # 2 x 32 bits + + def process_msg(self, packet): + pass + + def prints(self): + pass + + +class OFPT_METER_MOD(OFPHeader): + + def __init__(self, of_header): + OFPHeader.__init__(self, of_header) + self.command = None # 16 bits + self.flags = None # 16 bits + self.meter_id = None # 32 bits + self.bands = [] # class ofp_mter_band_header + + def process_msg(self, packet): + pass + + def prints(self): + pass + + # Auxiliary Data Structures class OFP_Phy_port: diff --git a/of13/vendors.py b/of13/vendors.py new file mode 100644 index 0000000..e69de29 diff --git a/ofp_sniffer.py b/ofp_sniffer.py index 76b1138..8d52a88 100755 --- a/ofp_sniffer.py +++ b/ofp_sniffer.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ - This code acts as an OpenFlow troubleshoot toolkit: it acts as a sniffer + This code is an OpenFlow troubleshooting tool: it acts as a sniffer and as an OpenFlow message checker, to make sure the ONF standards are being followed. @@ -9,7 +9,7 @@ Current version: 0.3 - Author: Jeronimo Bezerra + Author: Jeronimo Bezerra """ import datetime @@ -18,23 +18,26 @@ from gen.packet import Packet +# Global Variable +# Others are instantiated later: cap, position, print_options, sanitizer ctr = 1 def process_packet(header, packet): """ Every packet captured by cap.loop is then processed here. - If packets are bigger than 62, we process. If it is 0, means there is + If packets are bigger than 62 Bytes, we process. If it is 0, means there is no more packets. If it is something in between, it is a fragment, - just ignore. - Args: - header: header of the captured packet - packet: packet captured from file or interface + we ignore for now. + Args: + header: header of the captured packet + packet: packet captured from file or interface """ global ctr # packet counter if len(packet) >= 62 and position_defined(): time = datetime.datetime.now() + # global variables: print_options, sanitizer, ctr pkt = Packet(packet, print_options, sanitizer, ctr) pkt.process_packet_header(header, time) if pkt.openflow_packet: @@ -52,35 +55,37 @@ def position_defined(): In case user wants to see a specific packet inside a specific pcap file, provide file name with the position -r file.pcap:position - Returns: - True if ctr is good - False: if ctr is not good + Returns: + True if ctr is good + False: if ctr is not good """ - if position > 0: - if ctr == position: - return True - else: - return False - else: - return True + return (True if ctr == position else False) if position > 0 else True -def main(argv): +def main(): """ This is how it starts: cap.loop continuously capture packets w/ pcapy print_options and sanitizer are global variables + Exits: + 0 - Normal, reached end of file + 1 - Normal, user requested with CRTL + C + 2 - Error + 3 - Interface or file not found """ - cap.loop(-1, process_packet) + exit_code = 0 + try: + cap.loop(-1, process_packet) + except KeyboardInterrupt: + exit_code = 1 + except Exception as exception: + print 'Error: %s ' % exception + exit_code = 2 + finally: + print 'Exiting...' + sys.exit(exit_code) -# Once code is considered "done", remove comments -# try: -# cap.loop(-1, process_packet) -# except KeyboardInterrupt: -# print 'Exiting...' -# sys.exit(0) -# except Exception as exception: -# print exception if __name__ == "__main__": + # Get CLI params and call the pcapy loop cap, position, print_options, sanitizer = gen.cli.get_params(sys.argv) - main(sys.argv) \ No newline at end of file + main() diff --git a/tcpiplib/packet.py b/tcpiplib/packet.py index 0dbf7fe..bce7ccb 100644 --- a/tcpiplib/packet.py +++ b/tcpiplib/packet.py @@ -6,9 +6,15 @@ import socket +IP_PROTOCOL = 8 +TCP_PROTOCOL = 6 +TCP_FLAG_PUSH = 8 +OF_HEADER_SIZE = 8 + + class L1: """ - Class to manage L1 fields + Class to dissect L1 fields """ def __init__(self): self.caplen = None @@ -23,14 +29,13 @@ def parse(self, header, time): class Ethernet: """ - Class to manage Ethernet fields + Class to dissect Ethernet fields """ def __init__(self): - self.src_mac = None self.dst_mac = None self.protocol = None - self.length = 14 # Ethernet Header has 14 bytes + self.length = 14 # Ethernet header has 14 bytes def parse(self, packet, host_order=0): eth_raw = packet[:self.length] @@ -38,6 +43,9 @@ def parse(self, packet, host_order=0): self.dst_mac = ethernet[0] self.src_mac = ethernet[1] + # When Ethernet is captured directly from the wire, + # use host_order big-endian. When the frame is encapsulated + # inside an OpenFlow PacketIn or Out, it is little-endian if not host_order: self.protocol = socket.ntohs(ethernet[2]) else: @@ -47,7 +55,7 @@ def parse(self, packet, host_order=0): class IP: """ - Class to manage IP fields + Class to dissect IP fields """ def __init__(self): self.version = None @@ -74,7 +82,7 @@ def parse(self, packet, offset): class TCP: """ - Class to manage TCP fields + Class to dissect TCP fields """ def __init__(self): self.source_port = None @@ -101,7 +109,7 @@ def parse(self, packet, offset): doff_reserved = tcph[4] tcph_length = doff_reserved >> 4 self.length = tcph_length * 4 - flags = tcph[5] # Ignoring Flag NS + flags = tcph[5] # TODO: Flag NS self.flag_cwr = flags & 0x80 self.flag_ece = flags & 0x40 self.flag_urg = flags & 0x20 @@ -115,7 +123,7 @@ def parse(self, packet, offset): class VLAN: """ - Class to manage VLAN fields + Class to dissect VLAN fields """ def __init__(self): self.vid = None @@ -138,7 +146,9 @@ def parse(self, packet): class LLDP: """ - Class to manage LLDP fields + Class to dissect LLDP fields + This is not a full LLDP dissection, just basic fields + The idea is to get the DPID and ports """ def __init__(self): self.c_type = None @@ -243,7 +253,7 @@ def parse(self, packet): class ARP: """ - Class to manage ARP fields + Class to dissect ARP fields """ def __init__(self): self.hw_type = None diff --git a/tcpiplib/prints.py b/tcpiplib/prints.py index f316ccb..16beb97 100644 --- a/tcpiplib/prints.py +++ b/tcpiplib/prints.py @@ -1,6 +1,6 @@ -''' - Generic/Protocol-independent prints -''' +""" + Printing TCP/IP classes +""" import socket import struct @@ -33,7 +33,7 @@ def get_ip_from_long(long_ip): Returns: IP in the format x.x.x.x """ - return (socket.inet_ntoa(struct.pack('!L', long_ip))) + return socket.inet_ntoa(struct.pack('!L', long_ip)) def datapath_id(a): @@ -55,7 +55,7 @@ def print_headers(pkt): Print TCP/IP header. It uses command line option -p to print 'mininal' or 'full' headers Args: - pkt: class OFMessage + pkt: OFMessage class """ if pkt.print_options['min'] == 1: print_minimal(pkt.position, pkt.l1.time, pkt.l1.caplen, pkt.l3, @@ -75,8 +75,8 @@ def print_minimal(position, date, getlen, ip, tcp): position: packet count date: date/time packet was captured getlen: total number of bytes captured - ip: class IP - tcp: class TCP + ip: IP class + tcp: TCP class """ string = 'Packet #%s - %s %s:%s -> %s:%s Size: %s Bytes' @@ -112,7 +112,7 @@ def print_layer2(eth): """ Prints the Ethernet frame Args: - eth: class Ethernet + eth: Ethernet class """ print ('Ethernet: Destination MAC: %s Source MAC: %s Protocol: %s' % (eth_addr(eth.dst_mac), eth_addr(eth.src_mac), @@ -123,7 +123,7 @@ def print_vlan(vlan): """ Print VLAN fields Args: - vlan: class VLAN + vlan: VLAN class """ print ('VLAN: PCP: %s CFI: %s VID: %s Protocol: %s' % (vlan.pcp, vlan.cfi, red(vlan.vid), hex(vlan.ethertype))) @@ -133,7 +133,7 @@ def print_arp(arp): """ Print ARP fields Args: - arp: class ARP + arp: ARP class """ print ('ARP: Hardware Type: %s Protocol Type: %s ' 'HW Length: %s Prot Length: %s Opcode: %s ' @@ -149,11 +149,11 @@ def print_layer3(ip): """ Prints IP headers Args: - ip: class IP + ip: IP class """ print (('IP Version: %d IP Header Length: %d TTL: %d Protocol: %d ' 'Source Address: %s Destination Address: %s') % - (ip.version, (ip.length), ip.ttl, ip.protocol, + (ip.version, ip.length, ip.ttl, ip.protocol, blue(ip.s_addr), blue(ip.d_addr))) @@ -161,13 +161,13 @@ def print_tcp(tcp): """ Print TCP headers Args: - tcp: class TCP + tcp: TCP class """ print ('TCP Source Port: %s Dest Port: %s Sequence Number: %s ' 'Acknowledgement: %s TCP header length: %s Flags: CWR: %s ' 'ECE: %s URG: %s ACK: %s PSH: %s RST: %s SYN: %s FYN: %s' % (tcp.source_port, tcp.dest_port, tcp.sequence, - tcp.acknowledgement, (tcp.length), tcp.flag_cwr, + tcp.acknowledgement, tcp.length, tcp.flag_cwr, tcp.flag_ece, tcp.flag_urg, tcp.flag_ack, tcp.flag_psh, tcp.flag_rst, tcp.flag_syn, tcp.flag_fyn)) @@ -176,7 +176,7 @@ def print_openflow_header(ofp): """ Print OpenFlow header Args: - ofp: class OFMessage + ofp: OFMessage class """ version = tcpiplib.tcpip.get_ofp_version(ofp.version) name_version = '%s(%s)' % (version, ofp.version) @@ -187,7 +187,7 @@ def print_openflow_header(ofp): name = of13.dissector.get_ofp_type(ofp.type) name_type = '%s(%s)' % (name, ofp.type) else: - name_type = '%s' % (ofp.type) + name_type = '%s' % ofp.type print ('OpenFlow Version: %s Type: %s Length: %s XID: %s' % (name_version, yellow(name_type), ofp.length, red(ofp.xid))) @@ -197,7 +197,7 @@ def print_lldp(lldp): """ Print LLDP fields Args: - lldp: class LLDP + lldp: LLDP class """ print ('LLDP: Chassis Type(%s) Length: %s SubType: %s ID: %s\n' 'LLDP: Port Type(%s) Length: %s SubType: %s ID: %s\n' diff --git a/tcpiplib/tcpip.py b/tcpiplib/tcpip.py index fc8cec2..ffabf56 100644 --- a/tcpiplib/tcpip.py +++ b/tcpiplib/tcpip.py @@ -2,6 +2,13 @@ def get_ethertype(etype): + """ + Converts Ethertype from number to name + Args: + etype: etype number collected + Returns: + etype name + """ etypes = {8: 'IP', 2048: 'IP', 2054: 'ARP', @@ -13,11 +20,18 @@ def get_ethertype(etype): 34998: 'PRIVATE'} try: return '%s(%s)' % (etypes[etype], hex(etype)) - except: + except KeyError: return hex(etype) def get_ofp_version(version): + """ + Converts OpenFlow version number to a human version + Args: + version: integer version of the OpenFlow version + Returns: + human version of the OpenFlow version + """ of_versions = {0: 'Experimental', 1: '1.0', 2: '1.1', @@ -27,14 +41,17 @@ def get_ofp_version(version): 6: '1.5'} try: return of_versions[version] - except: + except KeyError: return 'Unknown(%s)' % version def get_openflow_header(packet, start): """ Returns OpenFlow header - It is non-version aware + It is not a version aware + Args: + packet: packet content + start: offset """ of_header_length = 8 of_header = packet[start:of_header_length+start] From c20e75ece87d4312dd06eb8ad5b5a43e2c8a3e87 Mon Sep 17 00:00:00 2001 From: jab1982 Date: Thu, 28 Jul 2016 15:23:54 -0400 Subject: [PATCH 28/88] More additions to OF1.3 --- .idea/webServers.xml | 4 +- README.md | 3 +- __init__.py | 7 - docs/TODO | 13 +- gen/__init__.py | 7 +- gen/cli.py | 9 +- gen/debugging.py | 33 + gen/packet.py | 14 +- of10/__init__.py | 6 - of10/parser.py | 2 - of10/vendors/__init__.py | 0 of10/vendors/nicira/__init__.py | 0 of10/{vendors.py => vendors/nicira/parser.py} | 0 of13/__init__.py | 7 +- of13/dissector.py | 462 ++++++---- of13/packet.py | 839 ++++++++++++------ of13/parser.py | 611 ++++++------- of13/prints.py | 325 ++++--- of13/vendors/__init__.py | 0 of13/vendors/nicira/__init__.py | 0 tcpiplib/__init__.py | 10 +- 21 files changed, 1409 insertions(+), 943 deletions(-) create mode 100644 gen/debugging.py create mode 100644 of10/vendors/__init__.py create mode 100644 of10/vendors/nicira/__init__.py rename of10/{vendors.py => vendors/nicira/parser.py} (100%) create mode 100644 of13/vendors/__init__.py create mode 100644 of13/vendors/nicira/__init__.py diff --git a/.idea/webServers.xml b/.idea/webServers.xml index 7b50d76..fee5a27 100644 --- a/.idea/webServers.xml +++ b/.idea/webServers.xml @@ -2,8 +2,8 @@