From b89efa188810bf95a9d245e69e2961b5721c3b0f Mon Sep 17 00:00:00 2001 From: imarom Date: Mon, 21 Mar 2016 16:03:47 +0200 Subject: scapy python 2/3 --- .../scapy-2.3.1/python3/scapy/contrib/igmpv3.py | 270 +++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 scripts/external_libs/scapy-2.3.1/python3/scapy/contrib/igmpv3.py (limited to 'scripts/external_libs/scapy-2.3.1/python3/scapy/contrib/igmpv3.py') diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/contrib/igmpv3.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/contrib/igmpv3.py new file mode 100644 index 00000000..8322c7a3 --- /dev/null +++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/contrib/igmpv3.py @@ -0,0 +1,270 @@ +#! /usr/bin/env python + +# http://trac.secdev.org/scapy/ticket/31 + +# scapy.contrib.description = IGMPv3 +# scapy.contrib.status = loads + +from scapy.packet import * + +""" Based on the following references + http://www.iana.org/assignments/igmp-type-numbers + http://www.rfc-editor.org/rfc/pdfrfc/rfc3376.txt.pdf + +""" + +# TODO: Merge IGMPv3 packet Bindlayers correct for +# membership source/Group records +# ConditionalField parameters for IGMPv3 commented out +# +# See RFC3376, Section 4. Message Formats for definitions of proper IGMPv3 message format +# http://www.faqs.org/rfcs/rfc3376.html +# +# See RFC4286, For definitions of proper messages for Multicast Router Discovery. +# http://www.faqs.org/rfcs/rfc4286.html +# + +#import sys, socket, struct, time +from scapy.all import * +print("IGMPv3 is still under development - Nov 2010") + + +class IGMPv3gr(Packet): + """IGMP Group Record for IGMPv3 Membership Report + + This class is derived from class Packet and should be concatenated to an + instantiation of class IGMPv3. Within the IGMPv3 instantiation, the numgrp + element will need to be manipulated to indicate the proper number of + group records. + """ + name = "IGMPv3gr" + igmpv3grtypes = { 1 : "Mode Is Include", + 2 : "Mode Is Exclude", + 3 : "Change To Include Mode", + 4 : "Change To Exclude Mode", + 5 : "Allow New Sources", + 6 : "Block Old Sources"} + + fields_desc = [ ByteEnumField("rtype", 1, igmpv3grtypes), + ByteField("auxdlen",0), + FieldLenField("numsrc", None, "srcaddrs"), + IPField("maddr", "0.0.0.0"), + FieldListField("srcaddrs", None, IPField("sa", "0.0.0.0"), "numsrc") ] + #show_indent=0 +#-------------------------------------------------------------------------- + def post_build(self, p, pay): + """Called implicitly before a packet is sent. + """ + p += pay + if self.auxdlen != 0: + print("NOTICE: A properly formatted and complaint V3 Group Record should have an Auxiliary Data length of zero (0).") + print(" Subsequent Group Records are lost!") + return p +#-------------------------------------------------------------------------- + def mysummary(self): + """Display a summary of the IGMPv3 group record.""" + return self.sprintf("IGMPv3 Group Record %IGMPv3gr.type% %IGMPv3gr.maddr%") + + +class IGMPv3(Packet): + """IGMP Message Class for v3. + + This class is derived from class Packet. + The fields defined below are a + direct interpretation of the v3 Membership Query Message. + Fields 'type' through 'qqic' are directly assignable. + For 'numsrc', do not assign a value. + Instead add to the 'srcaddrs' list to auto-set 'numsrc'. To + assign values to 'srcaddrs', use the following methods: + c = IGMPv3() + c.srcaddrs = ['1.2.3.4', '5.6.7.8'] + c.srcaddrs += ['192.168.10.24'] + At this point, 'c.numsrc' is three (3) + + 'chksum' is automagically calculated before the packet is sent. + + 'mrcode' is also the Advertisement Interval field + + """ + name = "IGMPv3" + igmpv3types = { 0x11 : "Membership Query", + 0x22 : "Version 3 Membership Report", + 0x30 : "Multicast Router Advertisement", + 0x31 : "Multicast Router Solicitation", + 0x32 : "Multicast Router Termination"} + + fields_desc = [ ByteEnumField("type", 0x11, igmpv3types), + ByteField("mrcode",0), + XShortField("chksum", None), + IPField("gaddr", "0.0.0.0") + ] + # use float_encode() + + # if type = 0x11 (Membership Query), the next field is group address + # ConditionalField(IPField("gaddr", "0.0.0.0"), "type", lambda x:x==0x11), + # else if type = 0x22 (Membership Report), the next fields are + # reserved and number of group records + #ConditionalField(ShortField("rsvd2", 0), "type", lambda x:x==0x22), + #ConditionalField(ShortField("numgrp", 0), "type", lambda x:x==0x22), +# FieldLenField("numgrp", None, "grprecs")] + # else if type = 0x30 (Multicast Router Advertisement), the next fields are + # query interval and robustness + #ConditionalField(ShortField("qryIntvl", 0), "type", lambda x:x==0x30), + #ConditionalField(ShortField("robust", 0), "type", lambda x:x==0x30), +# The following are only present for membership queries + # ConditionalField(BitField("resv", 0, 4), "type", lambda x:x==0x11), + # ConditionalField(BitField("s", 0, 1), "type", lambda x:x==0x11), + # ConditionalField(BitField("qrv", 0, 3), "type", lambda x:x==0x11), + # ConditionalField(ByteField("qqic",0), "type", lambda x:x==0x11), + # ConditionalField(FieldLenField("numsrc", None, "srcaddrs"), "type", lambda x:x==0x11), + # ConditionalField(FieldListField("srcaddrs", None, IPField("sa", "0.0.0.0"), "numsrc"), "type", lambda x:x==0x11), + +#-------------------------------------------------------------------------- + def float_encode(self, value): + """Convert the integer value to its IGMPv3 encoded time value if needed. + + If value < 128, return the value specified. If >= 128, encode as a floating + point value. Value can be 0 - 31744. + """ + if value < 128: + code = value + elif value > 31743: + code = 255 + else: + exp=0 + value>>=3 + while(value>31): + exp+=1 + value>>=1 + exp<<=4 + code = 0x80 | exp | (value & 0x0F) + return code + +#-------------------------------------------------------------------------- + def post_build(self, p, pay): + """Called implicitly before a packet is sent to compute and place IGMPv3 checksum. + + Parameters: + self The instantiation of an IGMPv3 class + p The IGMPv3 message in hex in network byte order + pay Additional payload for the IGMPv3 message + """ + p += pay + if self.type in [0, 0x31, 0x32, 0x22]: # for these, field is reserved (0) + p = p[:1]+chr(0)+p[2:] + if self.chksum is None: + ck = checksum(p) + p = p[:2]+chr(ck>>8)+chr(ck&0xff)+p[4:] + return p + +#-------------------------------------------------------------------------- + def mysummary(self): + """Display a summary of the IGMPv3 object.""" + + if isinstance(self.underlayer, IP): + return self.underlayer.sprintf("IGMPv3: %IP.src% > %IP.dst% %IGMPv3.type% %IGMPv3.gaddr%") + else: + return self.sprintf("IGMPv3 %IGMPv3.type% %IGMPv3.gaddr%") + +#-------------------------------------------------------------------------- + def igmpize(self, ip=None, ether=None): + """Called to explicitely fixup associated IP and Ethernet headers + + Parameters: + self The instantiation of an IGMP class. + ip The instantiation of the associated IP class. + ether The instantiation of the associated Ethernet. + + Returns: + True The tuple ether/ip/self passed all check and represents + a proper IGMP packet. + False One of more validation checks failed and no fields + were adjusted. + + The function will examine the IGMP message to assure proper format. + Corrections will be attempted if possible. The IP header is then properly + adjusted to ensure correct formatting and assignment. The Ethernet header + is then adjusted to the proper IGMP packet format. + """ + +# The rules are: +# 1. ttl = 1 (RFC 2236, section 2) +# igmp_binds = [ (IP, IGMP, { "proto": 2 , "ttl": 1 }), +# 2. tos = 0xC0 (RFC 3376, section 4) +# (IP, IGMPv3, { "proto": 2 , "ttl": 1, "tos":0xc0 }), +# (IGMPv3, IGMPv3gr, { }) ] +# The rules are: +# 1. the Max Response time is meaningful only in Membership Queries and should be zero +# otherwise (RFC 2236, section 2.2) + + if (self.type != 0x11): #rule 1 + self.mrtime = 0 + + if (self.adjust_ip(ip) == True): + if (self.adjust_ether(ip, ether) == True): return True + return False + +#-------------------------------------------------------------------------- + def adjust_ether (self, ip=None, ether=None): + """Called to explicitely fixup an associated Ethernet header + + The function adjusts the ethernet header destination MAC address based on + the destination IP address. + """ +# The rules are: +# 1. send to the group mac address address corresponding to the IP.dst + if ip != None and ip.haslayer(IP) and ether != None and ether.haslayer(Ether): + iplong = atol(ip.dst) + ether.dst = "01:00:5e:%02x:%02x:%02x" % ( (iplong>>16)&0x7F, (iplong>>8)&0xFF, (iplong)&0xFF ) + # print "igmpize ip " + ip.dst + " as mac " + ether.dst + return True + else: + return False + +#-------------------------------------------------------------------------- + def adjust_ip (self, ip=None): + """Called to explicitely fixup an associated IP header + + The function adjusts the IP header based on conformance rules + and the group address encoded in the IGMP message. + The rules are: + 1. Send General Group Query to 224.0.0.1 (all systems) + 2. Send Leave Group to 224.0.0.2 (all routers) + 3a.Otherwise send the packet to the group address + 3b.Send reports/joins to the group address + 4. ttl = 1 (RFC 2236, section 2) + 5. send the packet with the router alert IP option (RFC 2236, section 2) + """ + if ip != None and ip.haslayer(IP): + if (self.type == 0x11): + if (self.gaddr == "0.0.0.0"): + ip.dst = "224.0.0.1" # IP rule 1 + retCode = True + elif isValidMCAddr(self.gaddr): + ip.dst = self.gaddr # IP rule 3a + retCode = True + else: + print("Warning: Using invalid Group Address") + retCode = False + elif ((self.type == 0x17) and isValidMCAddr(self.gaddr)): + ip.dst = "224.0.0.2" # IP rule 2 + retCode = True + elif ((self.type == 0x12) or (self.type == 0x16)) and (isValidMCAddr(self.gaddr)): + ip.dst = self.gaddr # IP rule 3b + retCode = True + else: + print("Warning: Using invalid IGMP Type") + retCode = False + else: + print("Warning: No IGMP Group Address set") + retCode = False + if retCode == True: + ip.ttl=1 # IP Rule 4 + ip.options=[IPOption_Router_Alert()] # IP rule 5 + return retCode + + +bind_layers( IP, IGMPv3, frag=0, proto=2, ttl=1, tos=0xc0) +bind_layers( IGMPv3, IGMPv3gr, frag=0, proto=2) +bind_layers( IGMPv3gr, IGMPv3gr, frag=0, proto=2) + -- cgit