1# SPDX-License-Identifier: GPL-2.0-only
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) Mathieu RENARD <mathieu.renard(at)gmail.com>
5
6"""
7HSRP (Hot Standby Router Protocol)
8A proprietary redundancy protocol for Cisco routers.
9
10- HSRP Version 1: RFC 2281
11- HSRP Version 2:
12 http://www.smartnetworks.jp/2006/02/hsrp_8_hsrp_version_2.html
13"""
14
15from scapy.config import conf
16from scapy.fields import ByteEnumField, ByteField, IPField, SourceIPField, \
17 StrFixedLenField, XIntField, XShortField
18from scapy.packet import Packet, bind_layers, bind_bottom_up
19from scapy.layers.inet import DestIPField, UDP
20
21
22class HSRP(Packet):
23 name = "HSRP"
24 fields_desc = [
25 ByteField("version", 0),
26 ByteEnumField("opcode", 0, {0: "Hello", 1: "Coup", 2: "Resign", 3: "Advertise"}), # noqa: E501
27 ByteEnumField("state", 16, {0: "Initial", 1: "Learn", 2: "Listen", 4: "Speak", 8: "Standby", 16: "Active"}), # noqa: E501
28 ByteField("hellotime", 3),
29 ByteField("holdtime", 10),
30 ByteField("priority", 120),
31 ByteField("group", 1),
32 ByteField("reserved", 0),
33 StrFixedLenField("auth", b"cisco" + b"\00" * 3, 8),
34 IPField("virtualIP", "192.168.1.1")]
35
36 def guess_payload_class(self, payload):
37 if self.underlayer.len > 28:
38 return HSRPmd5
39 else:
40 return Packet.guess_payload_class(self, payload)
41
42
43class HSRPmd5(Packet):
44 name = "HSRP MD5 Authentication"
45 fields_desc = [
46 ByteEnumField("type", 4, {4: "MD5 authentication"}),
47 ByteField("len", None),
48 ByteEnumField("algo", 0, {1: "MD5"}),
49 ByteField("padding", 0x00),
50 XShortField("flags", 0x00),
51 SourceIPField("sourceip"),
52 XIntField("keyid", 0x00),
53 StrFixedLenField("authdigest", b"\00" * 16, 16)]
54
55 def post_build(self, p, pay):
56 if self.len is None and pay:
57 tmp_len = len(pay)
58 p = p[:1] + hex(tmp_len)[30:] + p[30:]
59 return p
60
61
62bind_bottom_up(UDP, HSRP, dport=1985)
63bind_bottom_up(UDP, HSRP, sport=1985)
64bind_bottom_up(UDP, HSRP, dport=2029)
65bind_bottom_up(UDP, HSRP, sport=2029)
66bind_layers(UDP, HSRP, dport=1985, sport=1985)
67bind_layers(UDP, HSRP, dport=2029, sport=2029)
68DestIPField.bind_addr(UDP, "224.0.0.2", dport=1985)
69if conf.ipv6_enabled:
70 from scapy.layers.inet6 import DestIP6Field
71 DestIP6Field.bind_addr(UDP, "ff02::66", dport=2029)