diff --git a/scapy/layers/hsrp.py b/scapy/layers/hsrp.py index 82e82606357..b64b9425d16 100644 --- a/scapy/layers/hsrp.py +++ b/scapy/layers/hsrp.py @@ -13,25 +13,47 @@ """ from scapy.config import conf -from scapy.fields import ByteEnumField, ByteField, IPField, SourceIPField, \ - StrFixedLenField, XIntField, XShortField +from scapy.compat import orb +from scapy.fields import ByteEnumField, ByteField, IntField, IPField, \ + ShortEnumField, ShortField, SourceIPField, StrFixedLenField, \ + XIntField, XShortField from scapy.packet import Packet, bind_layers, bind_bottom_up from scapy.layers.inet import DestIPField, UDP +_HSRP_OPCODES = {0: "Hello", 1: "Coup", 2: "Resign", 3: "Advertise"} +_HSRP_STATES = { + 0: "Initial", + 1: "Learn", + 2: "Listen", + 4: "Speak", + 8: "Standby", + 16: "Active", +} +_HSRP_ADVERTISE_TYPES = {1: "HSRP interface state"} +_HSRP_ADVERTISE_STATES = {1: "Active", 2: "Passive"} + + class HSRP(Packet): name = "HSRP" fields_desc = [ ByteField("version", 0), - ByteEnumField("opcode", 0, {0: "Hello", 1: "Coup", 2: "Resign", 3: "Advertise"}), # noqa: E501 - ByteEnumField("state", 16, {0: "Initial", 1: "Learn", 2: "Listen", 4: "Speak", 8: "Standby", 16: "Active"}), # noqa: E501 + ByteEnumField("opcode", 0, _HSRP_OPCODES), + ByteEnumField("state", 16, _HSRP_STATES), ByteField("hellotime", 3), ByteField("holdtime", 10), ByteField("priority", 120), ByteField("group", 1), ByteField("reserved", 0), StrFixedLenField("auth", b"cisco" + b"\00" * 3, 8), - IPField("virtualIP", "192.168.1.1")] + IPField("virtualIP", "192.168.1.1") + ] + + @classmethod + def dispatch_hook(cls, _pkt=None, *args, **kargs): + if _pkt and len(_pkt) >= 2 and orb(_pkt[1:2]) == 3: + return HSRPAdvertise + return cls def guess_payload_class(self, payload): if self.underlayer.len > 28: @@ -40,6 +62,27 @@ def guess_payload_class(self, payload): return Packet.guess_payload_class(self, payload) +class HSRPAdvertise(Packet): + name = "HSRP Advertise" + fields_desc = [ + ByteField("version", 0), + ByteEnumField("opcode", 3, _HSRP_OPCODES), + ShortEnumField("type", 1, _HSRP_ADVERTISE_TYPES), + ShortField("length", 10), + ByteEnumField("state", 1, _HSRP_ADVERTISE_STATES), + ByteField("reserved1", 0), + ShortField("activegroups", 0), + ShortField("passivegroups", 0), + IntField("reserved2", 0), + ] + + @classmethod + def dispatch_hook(cls, _pkt=None, *args, **kargs): + if _pkt and len(_pkt) >= 2 and orb(_pkt[1:2]) != 3: + return HSRP + return cls + + class HSRPmd5(Packet): name = "HSRP MD5 Authentication" fields_desc = [ diff --git a/test/scapy/layers/hsrp.uts b/test/scapy/layers/hsrp.uts index eeabeb0fea3..00bbbb7340d 100644 --- a/test/scapy/layers/hsrp.uts +++ b/test/scapy/layers/hsrp.uts @@ -12,4 +12,23 @@ assert pkt[IP].dst == "224.0.0.2" and pkt[UDP].sport == pkt[UDP].dport == 1985 assert pkt[HSRP].opcode == 0 and pkt[HSRP].state == 16 assert pkt[HSRPmd5].type == 4 and pkt[HSRPmd5].sourceip == defaddr - += HSRP - Advertise build & dissection +advertise_raw = b"\x00\x03\x00\x01\x00\x0e\x02\x00\x00\x00\x00\x01o\x00\x00\x00" +pkt = HSRP(advertise_raw) +assert isinstance(pkt, HSRPAdvertise) +assert pkt.opcode == 3 +assert pkt.type == 1 and pkt.length == 14 +assert pkt.state == 2 and pkt.reserved1 == 0 +assert pkt.activegroups == 0 and pkt.passivegroups == 1 +assert pkt.reserved2 == 0x6f000000 +assert raw( + HSRPAdvertise( + type=1, + length=14, + state=2, + reserved1=0, + activegroups=0, + passivegroups=1, + reserved2=0x6f000000, + ) +) == advertise_raw