diff --git a/scapy/layers/inet.py b/scapy/layers/inet.py index 4450df188..e38a0990d 100644 --- a/scapy/layers/inet.py +++ b/scapy/layers/inet.py @@ -475,6 +475,33 @@ class IP(Packet, IPTools): lst.append(q) return lst +def in4_chksum(proto, u, p): + """ + As Specified in RFC 2460 - 8.1 Upper-Layer Checksums + + Performs IPv4 Upper Layer checksum computation. Provided parameters are: + - 'proto' : value of upper layer protocol + - 'u' : IP upper layer instance + - 'p' : the payload of the upper layer provided as a string + """ + if not isinstance(u, IP): + warning("No IP underlayer to compute checksum. Leaving null.") + return 0 + if u.len is not None: + if u.ihl is None: + olen = sum(len(x) for x in u.options) + ihl = 5 + olen / 4 + (1 if olen % 4 else 0) + else: + ihl = u.ihl + ln = u.len - 4 * ihl + else: + ln = len(p) + psdhdr = struct.pack("!4s4sHH", + inet_aton(u.src), + inet_aton(u.dst), + proto, + ln) + return checksum(psdhdr+p) class TCP(Packet): name = "TCP" @@ -497,21 +524,7 @@ class TCP(Packet): p = p[:12]+chr((dataofs << 4) | ord(p[12])&0x0f)+p[13:] if self.chksum is None: if isinstance(self.underlayer, IP): - if self.underlayer.len is not None: - if self.underlayer.ihl is None: - olen = sum(len(x) for x in self.underlayer.options) - ihl = 5 + olen / 4 + (1 if olen % 4 else 0) - else: - ihl = self.underlayer.ihl - ln = self.underlayer.len - 4 * ihl - else: - ln = len(p) - psdhdr = struct.pack("!4s4sHH", - inet_aton(self.underlayer.src), - inet_aton(self.underlayer.dst), - self.underlayer.proto, - ln) - ck=checksum(psdhdr+p) + ck = in4_chksum(socket.IPPROTO_TCP, self.underlayer, p) p = p[:16]+struct.pack("!H", ck)+p[18:] elif conf.ipv6_enabled and isinstance(self.underlayer, scapy.layers.inet6.IPv6) or isinstance(self.underlayer, scapy.layers.inet6._IPv6ExtHdr): ck = scapy.layers.inet6.in6_chksum(socket.IPPROTO_TCP, self.underlayer, p) @@ -576,21 +589,7 @@ class UDP(Packet): p = p[:4]+struct.pack("!H",l)+p[6:] if self.chksum is None: if isinstance(self.underlayer, IP): - if self.underlayer.len is not None: - if self.underlayer.ihl is None: - olen = sum(len(x) for x in self.underlayer.options) - ihl = 5 + olen / 4 + (1 if olen % 4 else 0) - else: - ihl = self.underlayer.ihl - ln = self.underlayer.len - 4 * ihl - else: - ln = len(p) - psdhdr = struct.pack("!4s4sHH", - inet_aton(self.underlayer.src), - inet_aton(self.underlayer.dst), - self.underlayer.proto, - ln) - ck = checksum(psdhdr+p) + ck = in4_chksum(socket.IPPROTO_UDP, self.underlayer, p) # According to RFC768 if the result checksum is 0, it should be set to 0xFFFF if ck == 0: ck = 0xFFFF diff --git a/scapy/layers/inet6.py b/scapy/layers/inet6.py index 5c25420ed..e7e73cc48 100644 --- a/scapy/layers/inet6.py +++ b/scapy/layers/inet6.py @@ -292,6 +292,7 @@ ipv6nh = { 0:"Hop-by-Hop Option Header", 58:"ICMPv6", 59:"No Next Header", 60:"Destination Option Header", + 112:"VRRP", 132:"SCTP", 135:"Mobility Header"} @@ -643,8 +644,9 @@ class PseudoIPv6(Packet): # IPv6 Pseudo-header for checksum computation def in6_chksum(nh, u, p): """ - Performs IPv6 Upper Layer checksum computation. Provided parameters are: + As Specified in RFC 2460 - 8.1 Upper-Layer Checksums + Performs IPv6 Upper Layer checksum computation. Provided parameters are: - 'nh' : value of upper layer protocol - 'u' : upper layer instance (TCP, UDP, ICMPv6*, ). Instance must be provided with all under layers (IPv6 and all extension headers, diff --git a/scapy/layers/vrrp.py b/scapy/layers/vrrp.py index f874b352a..bd50e45b2 100644 --- a/scapy/layers/vrrp.py +++ b/scapy/layers/vrrp.py @@ -10,15 +10,17 @@ VRRP (Virtual Router Redundancy Protocol). from scapy.packet import * from scapy.fields import * -from scapy.layers.inet import IP +from scapy.layers.inet import * +from scapy.layers.inet6 import * +from scapy.error import warning IPPROTO_VRRP=112 # RFC 3768 - Virtual Router Redundancy Protocol (VRRP) class VRRP(Packet): fields_desc = [ - BitField("version" , 2, 4), - BitField("type" , 1, 4), + BitField("version", 2, 4), + BitField("type", 1, 4), ByteField("vrid", 1), ByteField("priority", 100), FieldLenField("ipcount", None, count_of="addrlist", fmt="B"), @@ -36,4 +38,51 @@ class VRRP(Packet): p = p[:6]+chr(ck>>8)+chr(ck&0xff)+p[8:] return p + @classmethod + def dispatch_hook(cls, _pkt=None, *args, **kargs): + if _pkt and len(_pkt) >= 9: + ver_n_type = ord(_pkt[0]) + if ver_n_type >= 48 and ver_n_type <= 57: # Version == 3 + return VRRPv3 + return VRRP + + +# RFC 5798 - Virtual Router Redundancy Protocol (VRRP) Version 3 +class VRRPv3(Packet): + fields_desc = [ + BitField("version", 3, 4), + BitField("type", 1, 4), + ByteField("vrid", 1), + ByteField("priority", 100), + FieldLenField("ipcount", None, count_of="addrlist", fmt="B"), + BitField("res", 0, 4), + BitField("adv", 100, 12), + XShortField("chksum", None), + # FIXME: addrlist should also allow IPv6 addresses :/ + FieldListField("addrlist", [], IPField("", "0.0.0.0"), + count_from = lambda pkt: pkt.ipcount)] + + def post_build(self, p, pay): + if self.chksum is None: + if isinstance(self.underlayer, IP): + ck = in4_chksum(112, self.underlayer, p) + elif isinstance(self.underlayer, IPv6): + ck = in6_chksum(112, self.underlayer, p) + else: + warning("No IP(v6) layer to compute checksum on VRRP. Leaving null") + ck = 0 + p = p[:6]+chr(ck>>8)+chr(ck&0xff)+p[8:] + return p + + @classmethod + def dispatch_hook(cls, _pkt=None, *args, **kargs): + if _pkt and len(_pkt) >= 16: + ver_n_type = ord(_pkt[0]) + if ver_n_type < 48 or ver_n_type > 57: # Version != 3 + return VRRP + return VRRPv3 + +# IPv6 is supported only on VRRPv3 bind_layers( IP, VRRP, proto=IPPROTO_VRRP) +bind_layers( IP, VRRPv3, proto=IPPROTO_VRRP) +bind_layers( IPv6, VRRPv3, nh=IPPROTO_VRRP)