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 = CARP 16 # scapy.contrib.status = loads 17 18 import struct, hmac, hashlib 19 20 from scapy.packet import * 21 from scapy.layers.inet import IP 22 from scapy.fields import BitField, ByteField, XShortField, IntField, XIntField 23 from scapy.utils import checksum, inet_aton 24 25 class CARP(Packet): 26 name = "CARP" 27 fields_desc = [ BitField("version", 4, 4), 28 BitField("type", 4, 4), 29 ByteField("vhid", 1), 30 ByteField("advskew", 0), 31 ByteField("authlen", 0), 32 ByteField("demotion", 0), 33 ByteField("advbase", 0), 34 XShortField("chksum", 0), 35 XIntField("counter1", 0), 36 XIntField("counter2", 0), 37 XIntField("hmac1", 0), 38 XIntField("hmac2", 0), 39 XIntField("hmac3", 0), 40 XIntField("hmac4", 0), 41 XIntField("hmac5", 0) 42 ] 43 44 def post_build(self, pkt, pay): 45 if self.chksum == None: 46 pkt = pkt[:6] + struct.pack("!H", checksum(pkt)) + pkt[8:] 47 48 return pkt 49 50 def build_hmac_sha1(pkt, pw = b'\0' * 20, ip4l=None, ip6l=None): 51 if ip4l is None: 52 ip4l = [] 53 if ip6l is None: 54 ip6l = [] 55 if not pkt.haslayer(CARP): 56 return None 57 58 p = pkt[CARP] 59 h = hmac.new(pw, digestmod = hashlib.sha1) 60 # XXX: this is a dirty hack. it needs to pack version and type into a single 8bit field 61 h.update(b'\x21') 62 # XXX: mac addy if different from special link layer. comes before vhid 63 h.update(struct.pack('!B', p.vhid)) 64 65 sl = [] 66 for i in ip4l: 67 # sort ips from smallest to largest 68 sl.append(inet_aton(i)) 69 sl.sort() 70 71 for i in sl: 72 h.update(i) 73 74 # XXX: do ip6l sorting 75 76 return h.digest() 77 78 """ 79 XXX: Usually CARP is multicast to 224.0.0.18 but because of virtual setup, it'll 80 be unicast between nodes. Uncomment the following line for normal use 81 bind_layers(IP, CARP, proto=112, dst='224.0.0.18') 82 """ 83 bind_layers(IP, CARP, proto=112) 84