# scapy.contrib.description = CARP # scapy.contrib.status = loads from scapy.packet import * from scapy.layers.inet import IP from scapy.fields import BitField, ByteField, XShortField, IntField, XIntField from scapy.utils import checksum import struct, hmac, hashlib class CARP(Packet): name = "CARP" fields_desc = [ BitField("version", 4, 4), BitField("type", 4, 4), ByteField("vhid", 1), ByteField("advskew", 0), ByteField("authlen", 0), ByteField("demotion", 0), ByteField("advbase", 0), XShortField("chksum", 0), XIntField("counter1", 0), XIntField("counter2", 0), XIntField("hmac1", 0), XIntField("hmac2", 0), XIntField("hmac3", 0), XIntField("hmac4", 0), XIntField("hmac5", 0) ] def post_build(self, pkt, pay): if self.chksum == None: pkt = pkt[:6] + struct.pack("!H", checksum(pkt)) + pkt[8:] return pkt def build_hmac_sha1(pkt, pw = '\0' * 20, ip4l = [], ip6l = []): if not pkt.haslayer(CARP): return None p = pkt[CARP] h = hmac.new(pw, digestmod = hashlib.sha1) # XXX: this is a dirty hack. it needs to pack version and type into a single 8bit field h.update('\x21') # XXX: mac addy if different from special link layer. comes before vhid h.update(struct.pack('!B', p.vhid)) sl = [] for i in ip4l: # sort ips from smallest to largest sl.append(inet_aton(i)) sl.sort() for i in sl: h.update(i) # XXX: do ip6l sorting return h.digest() """ XXX: Usually CARP is multicast to 224.0.0.18 but because of virtual setup, it'll be unicast between nodes. Uncomment the following line for normal use bind_layers(IP, CARP, proto=112, dst='224.0.0.18') """ bind_layers(IP, CARP, proto=112)