1# This file is part of Scapy
2# Scapy is free software: you can redistribute it and/or modify
3# it under the terms of the GNU General Public License as published by
4# the Free Software Foundation, either version 2 of the License, or
5# any later version.
6#
7# Scapy is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with Scapy. If not, see <http://www.gnu.org/licenses/>.
14
15# scapy.contrib.description = Common Address Redundancy Protocol (CARP)
16# scapy.contrib.status = loads
17
18import struct
19import hmac
20import hashlib
21
22from scapy.packet import Packet, split_layers, bind_layers
23from scapy.layers.inet import IP
24from scapy.fields import BitField, ByteField, XShortField, XIntField
25from scapy.layers.vrrp import IPPROTO_VRRP, VRRP, VRRPv3
26from scapy.utils import checksum, inet_aton
27from scapy.error import warning
28
29
30class CARP(Packet):
31    name = "CARP"
32    fields_desc = [BitField("version", 4, 4),
33                   BitField("type", 4, 4),
34                   ByteField("vhid", 1),
35                   ByteField("advskew", 0),
36                   ByteField("authlen", 0),
37                   ByteField("demotion", 0),
38                   ByteField("advbase", 0),
39                   XShortField("chksum", None),
40                   XIntField("counter1", 0),
41                   XIntField("counter2", 0),
42                   XIntField("hmac1", 0),
43                   XIntField("hmac2", 0),
44                   XIntField("hmac3", 0),
45                   XIntField("hmac4", 0),
46                   XIntField("hmac5", 0)
47                   ]
48
49    def post_build(self, pkt, pay):
50        if self.chksum is None:
51            pkt = pkt[:6] + struct.pack("!H", checksum(pkt)) + pkt[8:]
52
53        return pkt
54
55    def build_hmac_sha1(self, pw=b'\x00' * 20, ip4l=[], ip6l=[]):
56        h = hmac.new(pw, digestmod=hashlib.sha1)
57        # XXX: this is a dirty hack. it needs to pack version and type into a single 8bit field  # noqa: E501
58        h.update(b'\x21')
59        # XXX: mac addy if different from special link layer. comes before vhid
60        h.update(struct.pack('!B', self.vhid))
61
62        sl = []
63        for i in ip4l:
64            # sort ips from smallest to largest
65            sl.append(inet_aton(i))
66        sl.sort()
67
68        for i in sl:
69            h.update(i)
70
71        # XXX: do ip6l sorting
72
73        return h.digest()
74
75
76warning("CARP overwrites VRRP !")
77# This cancel the bindings done in vrrp.py
78split_layers(IP, VRRP, proto=IPPROTO_VRRP)
79split_layers(IP, VRRPv3, proto=IPPROTO_VRRP)
80# CARP bindings
81bind_layers(IP, CARP, proto=112, dst='224.0.0.18')
82