summaryrefslogtreecommitdiffstats
path: root/scripts/external_libs/scapy-2.3.1/python3/scapy/layers
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/external_libs/scapy-2.3.1/python3/scapy/layers')
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/__init__.py8
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/all.py45
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/bluetooth.py213
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dhcp.py381
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dhcp6.py1718
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dns.py712
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dot11.py560
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/gprs.py21
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/hsrp.py79
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/inet.py1569
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/inet6.py3047
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ipsec.py995
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ir.py44
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/isakmp.py355
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/l2.py543
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/l2tp.py36
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/llmnr.py65
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/mgcp.py45
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/mobileip.py47
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/netbios.py222
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/netflow.py48
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ntp.py77
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/pflog.py59
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ppp.py349
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/radius.py65
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/rip.py74
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/rtp.py40
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/sctp.py439
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/sebek.py109
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/skinny.py161
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/smb.py354
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/snmp.py255
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/tftp.py477
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/vrrp.py39
-rw-r--r--scripts/external_libs/scapy-2.3.1/python3/scapy/layers/x509.py108
35 files changed, 13359 insertions, 0 deletions
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/__init__.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/__init__.py
new file mode 100644
index 00000000..a3f2afb9
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/__init__.py
@@ -0,0 +1,8 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+Layer package.
+"""
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/all.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/all.py
new file mode 100644
index 00000000..8104b6a2
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/all.py
@@ -0,0 +1,45 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+All layers. Configurable with conf.load_layers.
+"""
+
+import importlib
+from scapy.config import conf
+from scapy.error import log_loading
+import logging
+log = logging.getLogger("scapy.loading")
+
+#log_loading.info("Please, report issues to https://github.com/phaethon/scapy")
+
+def _import_star(m):
+ #mod = __import__("." + m, globals(), locals())
+ mod = importlib.import_module("scapy.layers." + m)
+ for k,v in mod.__dict__.items():
+ globals()[k] = v
+
+
+for _l in ['l2','inet','inet6']:
+ log_loading.debug("Loading layer %s" % _l)
+ #print "load ",_l
+ _import_star(_l)
+
+#def _import_star(m):
+ #mod = __import__("." + m, globals(), locals())
+# mod = importlib.import_module("scapy.layers." + m)
+# for k,v in mod.__dict__.items():
+# globals()[k] = v
+
+#for _l in conf.load_layers:
+# log_loading.debug("Loading layer %s" % _l)
+# try:
+# _import_star(_l)
+# except Exception as e:
+# log.warning("can't import layer %s: %s" % (_l,e))
+
+
+
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/bluetooth.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/bluetooth.py
new file mode 100644
index 00000000..5dd365a4
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/bluetooth.py
@@ -0,0 +1,213 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+Bluetooth layers, sockets and send/receive functions.
+"""
+
+import socket,struct
+
+from scapy.config import conf
+from scapy.packet import *
+from scapy.fields import *
+from scapy.supersocket import SuperSocket
+from scapy.data import MTU
+
+
+class HCI_Hdr(Packet):
+ name = "HCI header"
+ fields_desc = [ ByteEnumField("type",2,{1:"command",2:"ACLdata",3:"SCOdata",4:"event",5:"vendor"}),]
+
+ def mysummary(self):
+ return self.sprintf("HCI %type%")
+
+class HCI_ACL_Hdr(Packet):
+ name = "HCI ACL header"
+ fields_desc = [ ByteField("handle",0), # Actually, handle is 12 bits and flags is 4.
+ ByteField("flags",0), # I wait to write a LEBitField
+ LEShortField("len",None), ]
+ def post_build(self, p, pay):
+ p += pay
+ if self.len is None:
+ l = len(p)-4
+ #p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:]
+ p = p[:2]+bytes([(l&0xff),((l>>8)&0xff)])+p[4:]
+ return p
+
+
+class L2CAP_Hdr(Packet):
+ name = "L2CAP header"
+ fields_desc = [ LEShortField("len",None),
+ LEShortEnumField("cid",0,{1:"control"}),]
+
+ def post_build(self, p, pay):
+ p += pay
+ if self.len is None:
+ l = len(p)-4
+ #p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:]
+ p = p[:2]+bytes([(l&0xff),((l>>8)&0xff)])+p[4:]
+ return p
+
+
+
+class L2CAP_CmdHdr(Packet):
+ name = "L2CAP command header"
+ fields_desc = [
+ ByteEnumField("code",8,{1:"rej",2:"conn_req",3:"conn_resp",
+ 4:"conf_req",5:"conf_resp",6:"disconn_req",
+ 7:"disconn_resp",8:"echo_req",9:"echo_resp",
+ 10:"info_req",11:"info_resp"}),
+ ByteField("id",0),
+ LEShortField("len",None) ]
+ def post_build(self, p, pay):
+ p += pay
+ if self.len is None:
+ l = len(p)-4
+ #p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:]
+ p = p[:2]+bytes([(l&0xff),((l>>8)&0xff)])+p[4:]
+ return p
+ def answers(self, other):
+ if other.id == self.id:
+ if self.code == 1:
+ return 1
+ if other.code in [2,4,6,8,10] and self.code == other.code+1:
+ if other.code == 8:
+ return 1
+ return self.payload.answers(other.payload)
+ return 0
+
+class L2CAP_ConnReq(Packet):
+ name = "L2CAP Conn Req"
+ fields_desc = [ LEShortEnumField("psm",0,{1:"SDP",3:"RFCOMM",5:"telephony control"}),
+ LEShortField("scid",0),
+ ]
+
+class L2CAP_ConnResp(Packet):
+ name = "L2CAP Conn Resp"
+ fields_desc = [ LEShortField("dcid",0),
+ LEShortField("scid",0),
+ LEShortEnumField("result",0,["no_info","authen_pend","author_pend"]),
+ LEShortEnumField("status",0,["success","pend","bad_psm",
+ "cr_sec_block","cr_no_mem"]),
+ ]
+ def answers(self, other):
+ return self.scid == other.scid
+
+class L2CAP_CmdRej(Packet):
+ name = "L2CAP Command Rej"
+ fields_desc = [ LEShortField("reason",0),
+ ]
+
+
+class L2CAP_ConfReq(Packet):
+ name = "L2CAP Conf Req"
+ fields_desc = [ LEShortField("dcid",0),
+ LEShortField("flags",0),
+ ]
+
+class L2CAP_ConfResp(Packet):
+ name = "L2CAP Conf Resp"
+ fields_desc = [ LEShortField("scid",0),
+ LEShortField("flags",0),
+ LEShortEnumField("result",0,["success","unaccept","reject","unknown"]),
+ ]
+ def answers(self, other):
+ return self.scid == other.scid
+
+
+class L2CAP_DisconnReq(Packet):
+ name = "L2CAP Disconn Req"
+ fields_desc = [ LEShortField("dcid",0),
+ LEShortField("scid",0), ]
+
+class L2CAP_DisconnResp(Packet):
+ name = "L2CAP Disconn Resp"
+ fields_desc = [ LEShortField("dcid",0),
+ LEShortField("scid",0), ]
+ def answers(self, other):
+ return self.scid == other.scid
+
+
+
+class L2CAP_InfoReq(Packet):
+ name = "L2CAP Info Req"
+ fields_desc = [ LEShortEnumField("type",0,{1:"CL_MTU",2:"FEAT_MASK"}),
+ StrField("data","")
+ ]
+
+
+class L2CAP_InfoResp(Packet):
+ name = "L2CAP Info Resp"
+ fields_desc = [ LEShortField("type",0),
+ LEShortEnumField("result",0,["success","not_supp"]),
+ StrField("data",""), ]
+ def answers(self, other):
+ return self.type == other.type
+
+
+
+bind_layers( HCI_Hdr, HCI_ACL_Hdr, type=2)
+bind_layers( HCI_Hdr, conf.raw_layer, )
+bind_layers( HCI_ACL_Hdr, L2CAP_Hdr, )
+bind_layers( L2CAP_Hdr, L2CAP_CmdHdr, cid=1)
+bind_layers( L2CAP_CmdHdr, L2CAP_CmdRej, code=1)
+bind_layers( L2CAP_CmdHdr, L2CAP_ConnReq, code=2)
+bind_layers( L2CAP_CmdHdr, L2CAP_ConnResp, code=3)
+bind_layers( L2CAP_CmdHdr, L2CAP_ConfReq, code=4)
+bind_layers( L2CAP_CmdHdr, L2CAP_ConfResp, code=5)
+bind_layers( L2CAP_CmdHdr, L2CAP_DisconnReq, code=6)
+bind_layers( L2CAP_CmdHdr, L2CAP_DisconnResp, code=7)
+bind_layers( L2CAP_CmdHdr, L2CAP_InfoReq, code=10)
+bind_layers( L2CAP_CmdHdr, L2CAP_InfoResp, code=11)
+
+class BluetoothL2CAPSocket(SuperSocket):
+ desc = "read/write packets on a connected L2CAP socket"
+ def __init__(self, peer):
+ s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW,
+ socket.BTPROTO_L2CAP)
+ s.connect((peer,0))
+
+ self.ins = self.outs = s
+
+ def recv(self, x=MTU):
+ return L2CAP_CmdHdr(self.ins.recv(x))
+
+
+class BluetoothHCISocket(SuperSocket):
+ desc = "read/write on a BlueTooth HCI socket"
+ def __init__(self, iface=0x10000, type=None):
+ s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI)
+ s.setsockopt(socket.SOL_HCI, socket.HCI_DATA_DIR,1)
+ s.setsockopt(socket.SOL_HCI, socket.HCI_TIME_STAMP,1)
+ s.setsockopt(socket.SOL_HCI, socket.HCI_FILTER, struct.pack("IIIh2x", 0xffffffff,0xffffffff,0xffffffff,0)) #type mask, event mask, event mask, opcode
+ s.bind((iface,))
+ self.ins = self.outs = s
+# s.connect((peer,0))
+
+
+ def recv(self, x):
+ return HCI_Hdr(self.ins.recv(x))
+
+## Bluetooth
+
+
+@conf.commands.register
+def srbt(peer, pkts, inter=0.1, *args, **kargs):
+ """send and receive using a bluetooth socket"""
+ s = conf.BTsocket(peer=peer)
+ a,b = sndrcv(s,pkts,inter=inter,*args,**kargs)
+ s.close()
+ return a,b
+
+@conf.commands.register
+def srbt1(peer, pkts, *args, **kargs):
+ """send and receive 1 packet using a bluetooth socket"""
+ a,b = srbt(peer, pkts, *args, **kargs)
+ if len(a) > 0:
+ return a[0][1]
+
+
+
+conf.BTsocket = BluetoothL2CAPSocket
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dhcp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dhcp.py
new file mode 100644
index 00000000..e2b7c1f1
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dhcp.py
@@ -0,0 +1,381 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+DHCP (Dynamic Host Configuration Protocol) d BOOTP
+"""
+
+import struct
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.ansmachine import *
+from scapy.layers.inet import UDP,IP
+from scapy.layers.l2 import Ether
+from scapy.base_classes import Net
+from scapy.volatile import RandField
+
+from scapy.arch import get_if_raw_hwaddr
+from scapy.sendrecv import srp1
+from scapy.utils import str2bytes
+
+dhcpmagic=b"c\x82Sc"
+
+
+class BOOTP(Packet):
+ name = "BOOTP"
+ fields_desc = [ ByteEnumField("op",1, {1:"BOOTREQUEST", 2:"BOOTREPLY"}),
+ ByteField("htype",1),
+ ByteField("hlen",6),
+ ByteField("hops",0),
+ IntField("xid",0),
+ ShortField("secs",0),
+ FlagsField("flags", 0, 16, "???????????????B"),
+ IPField("ciaddr","0.0.0.0"),
+ IPField("yiaddr","0.0.0.0"),
+ IPField("siaddr","0.0.0.0"),
+ IPField("giaddr","0.0.0.0"),
+ Field("chaddr",b"", "16s"),
+ Field("sname",b"","64s"),
+ Field("file",b"","128s"),
+ StrField("options",b"") ]
+ def guess_payload_class(self, payload):
+ if self.options[:len(dhcpmagic)] == dhcpmagic:
+ return DHCP
+ else:
+ return Packet.guess_payload_class(self, payload)
+ def extract_padding(self,s):
+ if self.options[:len(dhcpmagic)] == dhcpmagic:
+ # set BOOTP options to DHCP magic cookie and make rest a payload of DHCP options
+ payload = self.options[len(dhcpmagic):]
+ self.options = self.options[:len(dhcpmagic)]
+ return payload, None
+ else:
+ return b"", None
+ def hashret(self):
+ return struct.pack("L", self.xid)
+ def answers(self, other):
+ if not isinstance(other, BOOTP):
+ return 0
+ return self.xid == other.xid
+
+
+
+#DHCP_UNKNOWN, DHCP_IP, DHCP_IPLIST, DHCP_TYPE \
+#= range(4)
+#
+
+DHCPTypes = {
+ 1: "discover",
+ 2: "offer",
+ 3: "request",
+ 4: "decline",
+ 5: "ack",
+ 6: "nak",
+ 7: "release",
+ 8: "inform",
+ 9: "force_renew",
+ 10:"lease_query",
+ 11:"lease_unassigned",
+ 12:"lease_unknown",
+ 13:"lease_active",
+ }
+
+DHCPOptions = {
+ 0: "pad",
+ 1: IPField("subnet_mask", "0.0.0.0"),
+ 2: "time_zone",
+ 3: IPField("router","0.0.0.0"),
+ 4: IPField("time_server","0.0.0.0"),
+ 5: IPField("IEN_name_server","0.0.0.0"),
+ 6: IPField("name_server","0.0.0.0"),
+ 7: IPField("log_server","0.0.0.0"),
+ 8: IPField("cookie_server","0.0.0.0"),
+ 9: IPField("lpr_server","0.0.0.0"),
+ 12: "hostname",
+ 14: "dump_path",
+ 15: "domain",
+ 17: "root_disk_path",
+ 22: "max_dgram_reass_size",
+ 23: "default_ttl",
+ 24: "pmtu_timeout",
+ 28: IPField("broadcast_address","0.0.0.0"),
+ 35: "arp_cache_timeout",
+ 36: "ether_or_dot3",
+ 37: "tcp_ttl",
+ 38: "tcp_keepalive_interval",
+ 39: "tcp_keepalive_garbage",
+ 40: "NIS_domain",
+ 41: IPField("NIS_server","0.0.0.0"),
+ 42: IPField("NTP_server","0.0.0.0"),
+ 43: "vendor_specific",
+ 44: IPField("NetBIOS_server","0.0.0.0"),
+ 45: IPField("NetBIOS_dist_server","0.0.0.0"),
+ 50: IPField("requested_addr","0.0.0.0"),
+ 51: IntField("lease_time", 43200),
+ 54: IPField("server_id","0.0.0.0"),
+ 55: "param_req_list",
+ 57: ShortField("max_dhcp_size", 1500),
+ 58: IntField("renewal_time", 21600),
+ 59: IntField("rebinding_time", 37800),
+ 60: "vendor_class_id",
+ 61: "client_id",
+
+ 64: "NISplus_domain",
+ 65: IPField("NISplus_server","0.0.0.0"),
+ 69: IPField("SMTP_server","0.0.0.0"),
+ 70: IPField("POP3_server","0.0.0.0"),
+ 71: IPField("NNTP_server","0.0.0.0"),
+ 72: IPField("WWW_server","0.0.0.0"),
+ 73: IPField("Finger_server","0.0.0.0"),
+ 74: IPField("IRC_server","0.0.0.0"),
+ 75: IPField("StreetTalk_server","0.0.0.0"),
+ 76: "StreetTalk_Dir_Assistance",
+ 82: "relay_agent_Information",
+ 53: ByteEnumField("message-type", 1, DHCPTypes),
+ # 55: DHCPRequestListField("request-list"),
+ 255: "end"
+ }
+
+DHCPRevOptions = {}
+
+for k,v in DHCPOptions.items():
+ if type(v) is str:
+ n = v
+ v = None
+ else:
+ n = v.name
+ DHCPRevOptions[n] = (k,v)
+del(n)
+del(v)
+del(k)
+
+
+
+
+class RandDHCPOptions(RandField):
+ def __init__(self, size=None, rndstr=None):
+ if size is None:
+ size = RandNumExpo(0.05)
+ self.size = size
+ if rndstr is None:
+ rndstr = RandBin(RandNum(0,255))
+ self.rndstr=rndstr
+ self._opts = list(DHCPOptions.values())
+ self._opts.remove("pad")
+ self._opts.remove("end")
+ def _fix(self):
+ op = []
+ for k in range(self.size):
+ o = random.choice(self._opts)
+ if type(o) is str:
+ op.append((o,self.rndstr*1))
+ else:
+ op.append((o.name, o.randval()._fix()))
+ return op
+
+
+class DHCPOptionsField(StrField):
+ islist=1
+ def i2repr(self,pkt,x):
+ s = []
+ for v in x:
+ if type(v) is tuple and len(v) >= 2:
+ if v[0] in DHCPRevOptions and isinstance(DHCPRevOptions[v[0]][1],Field):
+ f = DHCPRevOptions[v[0]][1]
+ vv = ",".join(f.i2repr(pkt,val) for val in v[1:])
+ else:
+ vv = ",".join(repr(val) for val in v[1:])
+ r = "%s=%s" % (v[0],vv)
+ s.append(r)
+ else:
+ s.append(sane(v))
+ return "[%s]" % (" ".join(s))
+
+ def getfield(self, pkt, s):
+ return b"", self.m2i(pkt, s)
+
+ def m2i(self, pkt, x):
+ opt = []
+ while x:
+ #o = ord(x[0])
+ o = x[0]
+ if o == 255:
+ opt.append("end")
+ x = x[1:]
+ continue
+ if o == 0:
+ opt.append("pad")
+ x = x[1:]
+ continue
+ #if len(x) < 2 or len(x) < ord(x[1])+2:
+ if len(x) < 2 or len(x) < x[1]+2:
+ opt.append(x)
+ break
+ elif o in DHCPOptions:
+ f = DHCPOptions[o]
+
+ if isinstance(f, str):
+ #olen = ord(x[1])
+ olen = x[1]
+ opt.append( (f,x[2:olen+2]) )
+ x = x[olen+2:]
+ else:
+ olen = x[1]
+ lval = [f.name]
+ try:
+ left = x[2:olen+2]
+ while left:
+ left, val = f.getfield(pkt,left)
+ lval.append(val)
+ except:
+ opt.append(x)
+ break
+ else:
+ otuple = tuple(lval)
+ opt.append(otuple)
+ x = x[olen+2:]
+ else:
+ #olen = ord(x[1])
+ olen = x[1]
+ opt.append((o, x[2:olen+2]))
+ x = x[olen+2:]
+ return opt
+ def i2m(self, pkt, x):
+ if type(x) is str:
+ return x
+ s = b""
+ for o in x:
+ if type(o) is tuple and len(o) >= 2:
+ name = o[0]
+ lval = o[1:]
+
+ if isinstance(name, int):
+ onum, oval = name, b"".join(lval)
+ elif name in DHCPRevOptions:
+ onum, f = DHCPRevOptions[name]
+ if f is not None:
+ lval = [f.addfield(pkt,b"",f.any2i(pkt,val)) for val in lval]
+ oval = b"".join(lval)
+ else:
+ warning("Unknown field option %s" % name)
+ continue
+
+ s += bytes([onum])
+ s += bytes([len(oval)])
+ s += oval
+
+ elif (type(o) is str and o in DHCPRevOptions and
+ DHCPRevOptions[o][1] == None):
+ s += bytes([DHCPRevOptions[o][0]])
+ elif type(o) is int:
+ s += chr(o)+b"\0"
+ elif type(o) is str:
+ s += str2bytes(o)
+ elif type(o) is bytes:
+ s += o
+ else:
+ warning("Malformed option %s" % o)
+ return s
+
+
+class DHCP(Packet):
+ name = "DHCP options"
+ fields_desc = [ DHCPOptionsField("options",b"") ]
+
+
+bind_layers( UDP, BOOTP, dport=67, sport=68)
+bind_layers( UDP, BOOTP, dport=68, sport=67)
+bind_bottom_up( UDP, BOOTP, dport=67, sport=67)
+bind_layers( BOOTP, DHCP, options=b'c\x82Sc')
+
+def dhcp_request(iface=None,**kargs):
+ if conf.checkIPaddr != 0:
+ warning("conf.checkIPaddr is not 0, I may not be able to match the answer")
+ if iface is None:
+ iface = conf.iface
+ hw = get_if_raw_hwaddr(iface)
+ return srp1(Ether(dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67)
+ /BOOTP(chaddr=hw)/DHCP(options=[("message-type","discover"),"end"]),iface=iface,**kargs)
+
+
+class BOOTP_am(AnsweringMachine):
+ function_name = "bootpd"
+ filter = "udp and port 68 and port 67"
+ send_function = staticmethod(sendp)
+ def parse_options(self, pool=Net("192.168.1.128/25"), network="192.168.1.0/24",gw="192.168.1.1",
+ domain="localnet", renewal_time=60, lease_time=1800):
+ if type(pool) is str:
+ poom = Net(pool)
+ self.domain = domain
+ netw,msk = (network.split("/")+["32"])[:2]
+ msk = itom(int(msk))
+ self.netmask = ltoa(msk)
+ self.network = ltoa(atol(netw)&msk)
+ self.broadcast = ltoa( atol(self.network) | (0xffffffff&~msk) )
+ self.gw = gw
+ if isinstance(pool,Gen):
+ pool = [k for k in pool if k not in [gw, self.network, self.broadcast]]
+ pool.reverse()
+ if len(pool) == 1:
+ pool, = pool
+ self.pool = pool
+ self.lease_time = lease_time
+ self.renewal_time = renewal_time
+ self.leases = {}
+
+ def is_request(self, req):
+ if not req.haslayer(BOOTP):
+ return 0
+ reqb = req.getlayer(BOOTP)
+ if reqb.op != 1:
+ return 0
+ return 1
+
+ def print_reply(self, req, reply):
+ print("Reply %s to %s" % (reply.getlayer(IP).dst,reply.dst))
+
+ def make_reply(self, req):
+ mac = req.src
+ if type(self.pool) is list:
+ if not mac in self.leases:
+ self.leases[mac] = self.pool.pop()
+ ip = self.leases[mac]
+ else:
+ ip = self.pool
+
+ repb = req.getlayer(BOOTP).copy()
+ repb.op="BOOTREPLY"
+ repb.yiaddr = ip
+ repb.siaddr = self.gw
+ repb.ciaddr = self.gw
+ repb.giaddr = self.gw
+ del(repb.payload)
+ rep=Ether(dst=mac)/IP(dst=ip)/UDP(sport=req.dport,dport=req.sport)/repb
+ return rep
+
+
+class DHCP_am(BOOTP_am):
+ function_name="dhcpd"
+ def make_reply(self, req):
+ resp = BOOTP_am.make_reply(self, req)
+ if DHCP in req:
+ dhcp_options = [(op[0],{1:2,3:5}.get(op[1],op[1]))
+ for op in req[DHCP].options
+ if type(op) is tuple and op[0] == "message-type"]
+ dhcp_options += [("server_id",self.gw),
+ ("domain", self.domain),
+ ("router", self.gw),
+ ("name_server", self.gw),
+ ("broadcast_address", self.broadcast),
+ ("subnet_mask", self.netmask),
+ ("renewal_time", self.renewal_time),
+ ("lease_time", self.lease_time),
+ "end"
+ ]
+ resp /= DHCP(options=dhcp_options)
+ return resp
+
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dhcp6.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dhcp6.py
new file mode 100644
index 00000000..a11a4149
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dhcp6.py
@@ -0,0 +1,1718 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+## Copyright (C) 2005 Guillaume Valadon <guedou@hongo.wide.ad.jp>
+## Arnaud Ebalard <arnaud.ebalard@eads.net>
+
+"""
+DHCPv6: Dynamic Host Configuration Protocol for IPv6. [RFC 3315]
+"""
+
+import socket
+from scapy.packet import *
+from scapy.fields import *
+from scapy.utils6 import *
+from scapy.layers.inet6 import *
+from scapy.ansmachine import AnsweringMachine
+
+#############################################################################
+# Helpers ##
+#############################################################################
+
+def get_cls(name, fallback_cls):
+ return globals().get(name, fallback_cls)
+
+
+#############################################################################
+#############################################################################
+### DHCPv6 ###
+#############################################################################
+#############################################################################
+
+All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"
+All_DHCP_Servers = "ff05::1:3" # Site-Local scope : deprecated by 3879
+
+dhcp6opts = { 1: "CLIENTID",
+ 2: "SERVERID",
+ 3: "IA_NA",
+ 4: "IA_TA",
+ 5: "IAADDR",
+ 6: "ORO",
+ 7: "PREFERENCE",
+ 8: "ELAPSED_TIME",
+ 9: "RELAY_MSG",
+ 11: "AUTH",
+ 12: "UNICAST",
+ 13: "STATUS_CODE",
+ 14: "RAPID_COMMIT",
+ 15: "USER_CLASS",
+ 16: "VENDOR_CLASS",
+ 17: "VENDOR_OPTS",
+ 18: "INTERFACE_ID",
+ 19: "RECONF_MSG",
+ 20: "RECONF_ACCEPT",
+ 21: "SIP Servers Domain Name List", #RFC3319
+ 22: "SIP Servers IPv6 Address List", #RFC3319
+ 23: "DNS Recursive Name Server Option", #RFC3646
+ 24: "Domain Search List option", #RFC3646
+ 25: "OPTION_IA_PD", #RFC3633
+ 26: "OPTION_IAPREFIX", #RFC3633
+ 27: "OPTION_NIS_SERVERS", #RFC3898
+ 28: "OPTION_NISP_SERVERS", #RFC3898
+ 29: "OPTION_NIS_DOMAIN_NAME", #RFC3898
+ 30: "OPTION_NISP_DOMAIN_NAME", #RFC3898
+ 31: "OPTION_SNTP_SERVERS", #RFC4075
+ 32: "OPTION_INFORMATION_REFRESH_TIME", #RFC4242
+ 33: "OPTION_BCMCS_SERVER_D", #RFC4280
+ 34: "OPTION_BCMCS_SERVER_A", #RFC4280
+ 36: "OPTION_GEOCONF_CIVIC", #RFC-ietf-geopriv-dhcp-civil-09.txt
+ 37: "OPTION_REMOTE_ID", #RFC4649
+ 38: "OPTION_SUBSCRIBER_ID", #RFC4580
+ 39: "OPTION_CLIENT_FQDN" } #RFC4704
+
+dhcp6opts_by_code = { 1: "DHCP6OptClientId",
+ 2: "DHCP6OptServerId",
+ 3: "DHCP6OptIA_NA",
+ 4: "DHCP6OptIA_TA",
+ 5: "DHCP6OptIAAddress",
+ 6: "DHCP6OptOptReq",
+ 7: "DHCP6OptPref",
+ 8: "DHCP6OptElapsedTime",
+ 9: "DHCP6OptRelayMsg",
+ 11: "DHCP6OptAuth",
+ 12: "DHCP6OptServerUnicast",
+ 13: "DHCP6OptStatusCode",
+ 14: "DHCP6OptRapidCommit",
+ 15: "DHCP6OptUserClass",
+ 16: "DHCP6OptVendorClass",
+ 17: "DHCP6OptVendorSpecificInfo",
+ 18: "DHCP6OptIfaceId",
+ 19: "DHCP6OptReconfMsg",
+ 20: "DHCP6OptReconfAccept",
+ 21: "DHCP6OptSIPDomains", #RFC3319
+ 22: "DHCP6OptSIPServers", #RFC3319
+ 23: "DHCP6OptDNSServers", #RFC3646
+ 24: "DHCP6OptDNSDomains", #RFC3646
+ 25: "DHCP6OptIA_PD", #RFC3633
+ 26: "DHCP6OptIAPrefix", #RFC3633
+ 27: "DHCP6OptNISServers", #RFC3898
+ 28: "DHCP6OptNISPServers", #RFC3898
+ 29: "DHCP6OptNISDomain", #RFC3898
+ 30: "DHCP6OptNISPDomain", #RFC3898
+ 31: "DHCP6OptSNTPServers", #RFC4075
+ 32: "DHCP6OptInfoRefreshTime", #RFC4242
+ 33: "DHCP6OptBCMCSDomains", #RFC4280
+ 34: "DHCP6OptBCMCSServers", #RFC4280
+ #36: "DHCP6OptGeoConf", #RFC-ietf-geopriv-dhcp-civil-09.txt
+ 37: "DHCP6OptRemoteID", #RFC4649
+ 38: "DHCP6OptSubscriberID", #RFC4580
+ 39: "DHCP6OptClientFQDN", #RFC4704
+ #40: "DHCP6OptPANAAgent", #RFC-ietf-dhc-paa-option-05.txt
+ #41: "DHCP6OptNewPOSIXTimeZone, #RFC4833
+ #42: "DHCP6OptNewTZDBTimeZone, #RFC4833
+ 43: "DHCP6OptRelayAgentERO" #RFC4994
+ #44: "DHCP6OptLQQuery", #RFC5007
+ #45: "DHCP6OptLQClientData", #RFC5007
+ #46: "DHCP6OptLQClientTime", #RFC5007
+ #47: "DHCP6OptLQRelayData", #RFC5007
+ #48: "DHCP6OptLQClientLink", #RFC5007
+}
+
+
+# sect 5.3 RFC 3315 : DHCP6 Messages types
+dhcp6types = { 1:"SOLICIT",
+ 2:"ADVERTISE",
+ 3:"REQUEST",
+ 4:"CONFIRM",
+ 5:"RENEW",
+ 6:"REBIND",
+ 7:"REPLY",
+ 8:"RELEASE",
+ 9:"DECLINE",
+ 10:"RECONFIGURE",
+ 11:"INFORMATION-REQUEST",
+ 12:"RELAY-FORW",
+ 13:"RELAY-REPL" }
+
+
+#####################################################################
+### DHCPv6 DUID related stuff ###
+#####################################################################
+
+duidtypes = { 1: "Link-layer address plus time",
+ 2: "Vendor-assigned unique ID based on Enterprise Number",
+ 3: "Link-layer Address" }
+
+# DUID hardware types - RFC 826 - Extracted from
+# http://www.iana.org/assignments/arp-parameters on 31/10/06
+# We should add the length of every kind of address.
+duidhwtypes = { 0: "NET/ROM pseudo", # Not referenced by IANA
+ 1: "Ethernet (10Mb)",
+ 2: "Experimental Ethernet (3Mb)",
+ 3: "Amateur Radio AX.25",
+ 4: "Proteon ProNET Token Ring",
+ 5: "Chaos",
+ 6: "IEEE 802 Networks",
+ 7: "ARCNET",
+ 8: "Hyperchannel",
+ 9: "Lanstar",
+ 10: "Autonet Short Address",
+ 11: "LocalTalk",
+ 12: "LocalNet (IBM PCNet or SYTEK LocalNET)",
+ 13: "Ultra link",
+ 14: "SMDS",
+ 15: "Frame Relay",
+ 16: "Asynchronous Transmission Mode (ATM)",
+ 17: "HDLC",
+ 18: "Fibre Channel",
+ 19: "Asynchronous Transmission Mode (ATM)",
+ 20: "Serial Line",
+ 21: "Asynchronous Transmission Mode (ATM)",
+ 22: "MIL-STD-188-220",
+ 23: "Metricom",
+ 24: "IEEE 1394.1995",
+ 25: "MAPOS",
+ 26: "Twinaxial",
+ 27: "EUI-64",
+ 28: "HIPARP",
+ 29: "IP and ARP over ISO 7816-3",
+ 30: "ARPSec",
+ 31: "IPsec tunnel",
+ 32: "InfiniBand (TM)",
+ 33: "TIA-102 Project 25 Common Air Interface (CAI)" }
+
+class UTCTimeField(IntField):
+ epoch = (2000, 1, 1, 0, 0, 0, 5, 1, 0) # required Epoch
+ def i2repr(self, pkt, x):
+ x = self.i2h(pkt, x)
+ from time import gmtime, strftime, mktime
+ delta = mktime(self.epoch) - mktime(gmtime(0))
+ x = x + delta
+ t = strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime(x))
+ return "%s (%d)" % (t, x)
+
+class _LLAddrField(MACField):
+ pass
+
+# XXX We only support Ethernet addresses at the moment. _LLAddrField
+# will be modified when needed. Ask us. --arno
+class DUID_LLT(Packet): # sect 9.2 RFC 3315
+ name = "DUID - Link-layer address plus time"
+ fields_desc = [ ShortEnumField("type", 1, duidtypes),
+ XShortEnumField("hwtype", 1, duidhwtypes),
+ UTCTimeField("timeval", 0), # i.e. 01 Jan 2000
+ _LLAddrField("lladdr", ETHER_ANY) ]
+
+# In fact, IANA enterprise-numbers file available at
+# http//www.iana.org/asignments/enterprise-numbers)
+# is simply huge (more than 2Mo and 600Ko in bz2). I'll
+# add only most common vendors, and encountered values.
+# -- arno
+iana_enterprise_num = { 9: "ciscoSystems",
+ 35: "Nortel Networks",
+ 43: "3Com",
+ 311: "Microsoft",
+ 2636: "Juniper Networks, Inc.",
+ 4526: "Netgear",
+ 5771: "Cisco Systems, Inc.",
+ 5842: "Cisco Systems",
+ 16885: "Nortel Networks" }
+
+class DUID_EN(Packet): # sect 9.3 RFC 3315
+ name = "DUID - Assigned by Vendor Based on Enterprise Number"
+ fields_desc = [ ShortEnumField("type", 2, duidtypes),
+ IntEnumField("enterprisenum", 311, iana_enterprise_num),
+ StrField("id",b"") ]
+
+class DUID_LL(Packet): # sect 9.4 RFC 3315
+ name = "DUID - Based on Link-layer Address"
+ fields_desc = [ ShortEnumField("type", 3, duidtypes),
+ XShortEnumField("hwtype", 1, duidhwtypes),
+ _LLAddrField("lladdr", ETHER_ANY) ]
+
+duid_cls = { 1: "DUID_LLT",
+ 2: "DUID_EN",
+ 3: "DUID_LL"}
+
+#####################################################################
+### DHCPv6 Options classes ###
+#####################################################################
+
+class _DHCP6OptGuessPayload(Packet):
+ def guess_payload_class(self, payload):
+ cls = conf.raw_layer
+ if len(payload) > 2 :
+ opt = struct.unpack("!H", payload[:2])[0]
+ cls = get_cls(dhcp6opts_by_code.get(opt, "DHCP6OptUnknown"), DHCP6OptUnknown)
+ return cls
+
+class DHCP6OptUnknown(_DHCP6OptGuessPayload): # A generic DHCPv6 Option
+ name = "Unknown DHCPv6 OPtion"
+ fields_desc = [ ShortEnumField("optcode", 0, dhcp6opts),
+ FieldLenField("optlen", None, length_of="data", fmt="!H"),
+ StrLenField("data", b"",
+ length_from = lambda pkt: pkt.optlen)]
+
+class _DUIDField(PacketField):
+ holds_packets=1
+ def __init__(self, name, default, length_from=None):
+ StrField.__init__(self, name, default)
+ self.length_from = length_from
+
+ def i2m(self, pkt, i):
+ return bytes(i)
+
+ def m2i(self, pkt, x):
+ cls = conf.raw_layer
+ if len(x) > 4:
+ o = struct.unpack("!H", x[:2])[0]
+ cls = get_cls(duid_cls.get(o, conf.raw_layer), conf.raw_layer)
+ return cls(x)
+
+ def getfield(self, pkt, s):
+ l = self.length_from(pkt)
+ return s[l:], self.m2i(pkt,s[:l])
+
+
+class DHCP6OptClientId(_DHCP6OptGuessPayload): # RFC sect 22.2
+ name = "DHCP6 Client Identifier Option"
+ fields_desc = [ ShortEnumField("optcode", 1, dhcp6opts),
+ FieldLenField("optlen", None, length_of="duid", fmt="!H"),
+ _DUIDField("duid", "",
+ length_from = lambda pkt: pkt.optlen) ]
+
+
+class DHCP6OptServerId(DHCP6OptClientId): # RFC sect 22.3
+ name = "DHCP6 Server Identifier Option"
+ optcode = 2
+
+# Should be encapsulated in the option field of IA_NA or IA_TA options
+# Can only appear at that location.
+# TODO : last field IAaddr-options is not defined in the reference document
+class DHCP6OptIAAddress(_DHCP6OptGuessPayload): # RFC sect 22.6
+ name = "DHCP6 IA Address Option (IA_TA or IA_NA suboption)"
+ fields_desc = [ ShortEnumField("optcode", 5, dhcp6opts),
+ FieldLenField("optlen", None, length_of="iaaddropts",
+ fmt="!H", adjust = lambda pkt,x: x+24),
+ IP6Field("addr", "::"),
+ IntField("preflft", 0),
+ IntField("validlft", 0),
+ XIntField("iaid", None),
+ StrLenField("iaaddropts", b"",
+ length_from = lambda pkt: pkt.optlen - 24) ]
+ def guess_payload_class(self, payload):
+ return conf.padding_layer
+
+class _IANAOptField(PacketListField):
+ def i2len(self, pkt, z):
+ if z is None or z == []:
+ return 0
+ return sum(map(lambda x: len(bytes(x)) ,z))
+
+ def getfield(self, pkt, s):
+ l = self.length_from(pkt)
+ lst = []
+ remain, payl = s[:l], s[l:]
+ while len(remain)>0:
+ p = self.m2i(pkt,remain)
+ if conf.padding_layer in p:
+ pad = p[conf.padding_layer]
+ remain = pad.load
+ del(pad.underlayer.payload)
+ else:
+ remain = ""
+ lst.append(p)
+ return payl,lst
+
+class DHCP6OptIA_NA(_DHCP6OptGuessPayload): # RFC sect 22.4
+ name = "DHCP6 Identity Association for Non-temporary Addresses Option"
+ fields_desc = [ ShortEnumField("optcode", 3, dhcp6opts),
+ FieldLenField("optlen", None, length_of="ianaopts",
+ fmt="!H", adjust = lambda pkt,x: x+12),
+ XIntField("iaid", None),
+ IntField("T1", None),
+ IntField("T2", None),
+ _IANAOptField("ianaopts", [], DHCP6OptIAAddress,
+ length_from = lambda pkt: pkt.optlen-12) ]
+
+class _IATAOptField(_IANAOptField):
+ pass
+
+class DHCP6OptIA_TA(_DHCP6OptGuessPayload): # RFC sect 22.5
+ name = "DHCP6 Identity Association for Temporary Addresses Option"
+ fields_desc = [ ShortEnumField("optcode", 4, dhcp6opts),
+ FieldLenField("optlen", None, length_of="iataopts",
+ fmt="!H", adjust = lambda pkt,x: x+4),
+ XIntField("iaid", None),
+ _IATAOptField("iataopts", [], DHCP6OptIAAddress,
+ length_from = lambda pkt: pkt.optlen-4) ]
+
+
+#### DHCPv6 Option Request Option ###################################
+
+class _OptReqListField(StrLenField):
+ islist = 1
+ def i2h(self, pkt, x):
+ if x is None:
+ return []
+ return x
+
+ def i2len(self, pkt, x):
+ return 2*len(x)
+
+ def any2i(self, pkt, x):
+ return x
+
+ def i2repr(self, pkt, x):
+ s = []
+ for y in self.i2h(pkt, x):
+ if y in dhcp6opts:
+ s.append(dhcp6opts[y])
+ else:
+ s.append("%d" % y)
+ return "[%s]" % ", ".join(s)
+
+ def m2i(self, pkt, x):
+ r = []
+ while len(x) != 0:
+ if len(x)<2:
+ warning("Odd length for requested option field. Rejecting last byte")
+ return r
+ r.append(struct.unpack("!H", x[:2])[0])
+ x = x[2:]
+ return r
+
+ def i2m(self, pkt, x):
+ return b"".join(map(lambda y: struct.pack("!H", y), x))
+
+# A client may include an ORO in a solicit, Request, Renew, Rebind,
+# Confirm or Information-request
+class DHCP6OptOptReq(_DHCP6OptGuessPayload): # RFC sect 22.7
+ name = "DHCP6 Option Request Option"
+ fields_desc = [ ShortEnumField("optcode", 6, dhcp6opts),
+ FieldLenField("optlen", None, length_of="reqopts", fmt="!H"),
+ _OptReqListField("reqopts", [23, 24],
+ length_from = lambda pkt: pkt.optlen) ]
+
+
+#### DHCPv6 Preference Option #######################################
+
+# emise par un serveur pour affecter le choix fait par le client. Dans
+# les messages Advertise, a priori
+class DHCP6OptPref(_DHCP6OptGuessPayload): # RFC sect 22.8
+ name = "DHCP6 Preference Option"
+ fields_desc = [ ShortEnumField("optcode", 7, dhcp6opts),
+ ShortField("optlen", 1 ),
+ ByteField("prefval",255) ]
+
+
+#### DHCPv6 Elapsed Time Option #####################################
+
+class _ElapsedTimeField(ShortField):
+ def i2repr(self, pkt, x):
+ if x == 0xffff:
+ return "infinity (0xffff)"
+ return "%.2f sec" % (self.i2h(pkt, x)/100.)
+
+class DHCP6OptElapsedTime(_DHCP6OptGuessPayload):# RFC sect 22.9
+ name = "DHCP6 Elapsed Time Option"
+ fields_desc = [ ShortEnumField("optcode", 8, dhcp6opts),
+ ShortField("optlen", 2),
+ _ElapsedTimeField("elapsedtime", 0) ]
+
+
+#### DHCPv6 Relay Message Option ####################################
+
+# Relayed message is seen as a payload.
+class DHCP6OptRelayMsg(_DHCP6OptGuessPayload):# RFC sect 22.10
+ name = "DHCP6 Relay Message Option"
+ fields_desc = [ ShortEnumField("optcode", 9, dhcp6opts),
+ ShortField("optlen", None ) ]
+ def post_build(self, p, pay):
+ if self.optlen is None:
+ l = len(pay)
+ p = p[:2]+struct.pack("!H", l)
+ return p + pay
+
+
+#### DHCPv6 Authentication Option ###################################
+
+# The following fields are set in an Authentication option for the
+# Reconfigure Key Authentication Protocol:
+#
+# protocol 3
+#
+# algorithm 1
+#
+# RDM 0
+#
+# The format of the Authentication information for the Reconfigure Key
+# Authentication Protocol is:
+#
+# 0 1 2 3
+# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+# | Type | Value (128 bits) |
+# +-+-+-+-+-+-+-+-+ |
+# . .
+# . .
+# . +-+-+-+-+-+-+-+-+
+# | |
+# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+#
+# Type Type of data in Value field carried in this option:
+#
+# 1 Reconfigure Key value (used in Reply message).
+#
+# 2 HMAC-MD5 digest of the message (used in Reconfigure
+# message).
+#
+# Value Data as defined by field.
+
+
+# TODO : Decoding only at the moment
+class DHCP6OptAuth(_DHCP6OptGuessPayload): # RFC sect 22.11
+ name = "DHCP6 Option - Authentication"
+ fields_desc = [ ShortEnumField("optcode", 11, dhcp6opts),
+ FieldLenField("optlen", None, length_of="authinfo",
+ adjust = lambda pkt,x: x+11),
+ ByteField("proto", 3), # TODO : XXX
+ ByteField("alg", 1), # TODO : XXX
+ ByteField("rdm", 0), # TODO : XXX
+ StrFixedLenField("replay", b"A"*8, 8), # TODO: XXX
+ StrLenField("authinfo", b"",
+ length_from = lambda pkt: pkt.optlen - 11) ]
+
+#### DHCPv6 Server Unicast Option ###################################
+
+class _SrvAddrField(IP6Field):
+ def i2h(self, pkt, x):
+ if x is None:
+ return "::"
+ return x
+
+ def i2m(self, pkt, x):
+ return inet_pton(socket.AF_INET6, self.i2h(pkt,x))
+
+class DHCP6OptServerUnicast(_DHCP6OptGuessPayload):# RFC sect 22.12
+ name = "DHCP6 Server Unicast Option"
+ fields_desc = [ ShortEnumField("optcode", 12, dhcp6opts),
+ ShortField("optlen", 16 ),
+ _SrvAddrField("srvaddr",None) ]
+
+
+#### DHCPv6 Status Code Option ######################################
+
+dhcp6statuscodes = { 0:"Success", # sect 24.4
+ 1:"UnspecFail",
+ 2:"NoAddrsAvail",
+ 3:"NoBinding",
+ 4:"NotOnLink",
+ 5:"UseMulticast",
+ 6:"NoPrefixAvail"} # From RFC3633
+
+class DHCP6OptStatusCode(_DHCP6OptGuessPayload):# RFC sect 22.13
+ name = "DHCP6 Status Code Option"
+ fields_desc = [ ShortEnumField("optcode", 13, dhcp6opts),
+ FieldLenField("optlen", None, length_of="statusmsg",
+ fmt="!H", adjust = lambda pkt,x:x+2),
+ ShortEnumField("statuscode",None,dhcp6statuscodes),
+ StrLenField("statusmsg", b"",
+ length_from = lambda pkt: pkt.optlen-2) ]
+
+
+#### DHCPv6 Rapid Commit Option #####################################
+
+class DHCP6OptRapidCommit(_DHCP6OptGuessPayload): # RFC sect 22.14
+ name = "DHCP6 Rapid Commit Option"
+ fields_desc = [ ShortEnumField("optcode", 14, dhcp6opts),
+ ShortField("optlen", 0)]
+
+
+#### DHCPv6 User Class Option #######################################
+
+class _UserClassDataField(PacketListField):
+ def i2len(self, pkt, z):
+ if z is None or z == []:
+ return 0
+ return sum(map(lambda x: len(bytes(x)) ,z))
+
+ def getfield(self, pkt, s):
+ l = self.length_from(pkt)
+ lst = []
+ remain, payl = s[:l], s[l:]
+ while len(remain)>0:
+ p = self.m2i(pkt,remain)
+ if conf.padding_layer in p:
+ pad = p[conf.padding_layer]
+ remain = pad.load
+ del(pad.underlayer.payload)
+ else:
+ remain = b""
+ lst.append(p)
+ return payl,lst
+
+
+class USER_CLASS_DATA(Packet):
+ name = "user class data"
+ fields_desc = [ FieldLenField("len", None, length_of="data"),
+ StrLenField("data", b"",
+ length_from = lambda pkt: pkt.len) ]
+ def guess_payload_class(self, payload):
+ return conf.padding_layer
+
+class DHCP6OptUserClass(_DHCP6OptGuessPayload):# RFC sect 22.15
+ name = "DHCP6 User Class Option"
+ fields_desc = [ ShortEnumField("optcode", 15, dhcp6opts),
+ FieldLenField("optlen", None, fmt="!H",
+ length_of="userclassdata"),
+ _UserClassDataField("userclassdata", [], USER_CLASS_DATA,
+ length_from = lambda pkt: pkt.optlen) ]
+
+
+#### DHCPv6 Vendor Class Option #####################################
+
+class _VendorClassDataField(_UserClassDataField):
+ pass
+
+class VENDOR_CLASS_DATA(USER_CLASS_DATA):
+ name = "vendor class data"
+
+class DHCP6OptVendorClass(_DHCP6OptGuessPayload):# RFC sect 22.16
+ name = "DHCP6 Vendor Class Option"
+ fields_desc = [ ShortEnumField("optcode", 16, dhcp6opts),
+ FieldLenField("optlen", None, length_of="vcdata", fmt="!H",
+ adjust = lambda pkt,x: x+4),
+ IntEnumField("enterprisenum",None , iana_enterprise_num ),
+ _VendorClassDataField("vcdata", [], VENDOR_CLASS_DATA,
+ length_from = lambda pkt: pkt.optlen-4) ]
+
+#### DHCPv6 Vendor-Specific Information Option ######################
+
+class VENDOR_SPECIFIC_OPTION(_DHCP6OptGuessPayload):
+ name = "vendor specific option data"
+ fields_desc = [ ShortField("optcode", None),
+ FieldLenField("optlen", None, length_of="optdata"),
+ StrLenField("optdata", b"",
+ length_from = lambda pkt: pkt.optlen) ]
+ def guess_payload_class(self, payload):
+ return conf.padding_layer
+
+# The third one that will be used for nothing interesting
+class DHCP6OptVendorSpecificInfo(_DHCP6OptGuessPayload):# RFC sect 22.17
+ name = "DHCP6 Vendor-specific Information Option"
+ fields_desc = [ ShortEnumField("optcode", 17, dhcp6opts),
+ FieldLenField("optlen", None, length_of="vso", fmt="!H",
+ adjust = lambda pkt,x: x+4),
+ IntEnumField("enterprisenum",None , iana_enterprise_num),
+ _VendorClassDataField("vso", [], VENDOR_SPECIFIC_OPTION,
+ length_from = lambda pkt: pkt.optlen-4) ]
+
+#### DHCPv6 Interface-ID Option #####################################
+
+# Repasser sur cette option a la fin. Elle a pas l'air d'etre des
+# masses critique.
+class DHCP6OptIfaceId(_DHCP6OptGuessPayload):# RFC sect 22.18
+ name = "DHCP6 Interface-Id Option"
+ fields_desc = [ ShortEnumField("optcode", 18, dhcp6opts),
+ FieldLenField("optlen", None, fmt="!H",
+ length_of="ifaceid"),
+ StrLenField("ifaceid", b"",
+ length_from = lambda pkt: pkt.optlen) ]
+
+
+#### DHCPv6 Reconfigure Message Option ##############################
+
+# A server includes a Reconfigure Message option in a Reconfigure
+# message to indicate to the client whether the client responds with a
+# renew message or an Informatiion-request message.
+class DHCP6OptReconfMsg(_DHCP6OptGuessPayload): # RFC sect 22.19
+ name = "DHCP6 Reconfigure Message Option"
+ fields_desc = [ ShortEnumField("optcode", 19, dhcp6opts),
+ ShortField("optlen", 1 ),
+ ByteEnumField("msgtype", 11, { 5:"Renew Message",
+ 11:"Information Request"}) ]
+
+
+#### DHCPv6 Reconfigure Accept Option ###############################
+
+# A client uses the Reconfigure Accept option to announce to the
+# server whether the client is willing to accept Recoonfigure
+# messages, and a server uses this option to tell the client whether
+# or not to accept Reconfigure messages. The default behavior in the
+# absence of this option, means unwillingness to accept reconfigure
+# messages, or instruction not to accept Reconfigure messages, for the
+# client and server messages, respectively.
+class DHCP6OptReconfAccept(_DHCP6OptGuessPayload): # RFC sect 22.20
+ name = "DHCP6 Reconfigure Accept Option"
+ fields_desc = [ ShortEnumField("optcode", 20, dhcp6opts),
+ ShortField("optlen", 0)]
+
+# As required in Sect 8. of RFC 3315, Domain Names must be encoded as
+# described in section 3.1 of RFC 1035
+# XXX Label should be at most 63 octets in length : we do not enforce it
+# Total length of domain should be 255 : we do not enforce it either
+class DomainNameListField(StrLenField):
+ islist = 1
+
+ def i2len(self, pkt, x):
+ return len(self.i2m(pkt, x))
+
+ def m2i(self, pkt, x):
+ res = []
+ while x:
+ cur = []
+ #while x and x[0] != b'\x00':
+ while x and x[0] != 0:
+ l = (x[0])
+ cur.append(x[1:l+1])
+ x = x[l+1:]
+ res.append(b".".join(cur))
+ if x and x[0] == 0:
+ x = x[1:]
+ return res
+
+ def i2m(self, pkt, x):
+ def conditionalTrailingDot(z):
+ if z and z[-1] == 0:
+ return z
+ return z+b'\x00'
+ res = b""
+ x = [ i.encode('ascii') for i in x if type(i) is str ]
+ tmp = map(lambda y: map((lambda z: chr(len(z)).encode('ascii')+z), y.split(b'.')), x)
+ return b"".join(map(lambda x: conditionalTrailingDot(b"".join(x)), tmp))
+
+class DHCP6OptSIPDomains(_DHCP6OptGuessPayload): #RFC3319
+ name = "DHCP6 Option - SIP Servers Domain Name List"
+ fields_desc = [ ShortEnumField("optcode", 21, dhcp6opts),
+ FieldLenField("optlen", None, length_of="sipdomains"),
+ DomainNameListField("sipdomains", [],
+ length_from = lambda pkt: pkt.optlen) ]
+
+class DHCP6OptSIPServers(_DHCP6OptGuessPayload): #RFC3319
+ name = "DHCP6 Option - SIP Servers IPv6 Address List"
+ fields_desc = [ ShortEnumField("optcode", 22, dhcp6opts),
+ FieldLenField("optlen", None, length_of="sipservers"),
+ IP6ListField("sipservers", [],
+ length_from = lambda pkt: pkt.optlen) ]
+
+class DHCP6OptDNSServers(_DHCP6OptGuessPayload): #RFC3646
+ name = "DHCP6 Option - DNS Recursive Name Server"
+ fields_desc = [ ShortEnumField("optcode", 23, dhcp6opts),
+ FieldLenField("optlen", None, length_of="dnsservers"),
+ IP6ListField("dnsservers", [],
+ length_from = lambda pkt: pkt.optlen) ]
+
+class DHCP6OptDNSDomains(_DHCP6OptGuessPayload): #RFC3646
+ name = "DHCP6 Option - Domain Search List option"
+ fields_desc = [ ShortEnumField("optcode", 24, dhcp6opts),
+ FieldLenField("optlen", None, length_of="dnsdomains"),
+ DomainNameListField("dnsdomains", [],
+ length_from = lambda pkt: pkt.optlen) ]
+
+# TODO: Implement iaprefopts correctly when provided with more
+# information about it.
+class DHCP6OptIAPrefix(_DHCP6OptGuessPayload): #RFC3633
+ name = "DHCP6 Option - IA_PD Prefix option"
+ fields_desc = [ ShortEnumField("optcode", 26, dhcp6opts),
+ FieldLenField("optlen", None, length_of="iaprefopts",
+ adjust = lambda pkt,x: x+26),
+ IntField("preflft", 0),
+ IntField("validlft", 0),
+ ByteField("plen", 48), # TODO: Challenge that default value
+ IP6Field("prefix", "2001:db8::"), # At least, global and won't hurt
+ StrLenField("iaprefopts", b"",
+ length_from = lambda pkt: pkt.optlen-26) ]
+
+class DHCP6OptIA_PD(_DHCP6OptGuessPayload): #RFC3633
+ name = "DHCP6 Option - Identity Association for Prefix Delegation"
+ fields_desc = [ ShortEnumField("optcode", 25, dhcp6opts),
+ FieldLenField("optlen", None, length_of="iapdopt",
+ adjust = lambda pkt,x: x+12),
+ IntField("iaid", 0),
+ IntField("T1", 0),
+ IntField("T2", 0),
+ PacketListField("iapdopt", [], DHCP6OptIAPrefix,
+ length_from = lambda pkt: pkt.optlen-12) ]
+
+class DHCP6OptNISServers(_DHCP6OptGuessPayload): #RFC3898
+ name = "DHCP6 Option - NIS Servers"
+ fields_desc = [ ShortEnumField("optcode", 27, dhcp6opts),
+ FieldLenField("optlen", None, length_of="nisservers"),
+ IP6ListField("nisservers", [],
+ length_from = lambda pkt: pkt.optlen) ]
+
+class DHCP6OptNISPServers(_DHCP6OptGuessPayload): #RFC3898
+ name = "DHCP6 Option - NIS+ Servers"
+ fields_desc = [ ShortEnumField("optcode", 28, dhcp6opts),
+ FieldLenField("optlen", None, length_of="nispservers"),
+ IP6ListField("nispservers", [],
+ length_from = lambda pkt: pkt.optlen) ]
+
+class DomainNameField(StrLenField):
+ def getfield(self, pkt, s):
+ l = self.length_from(pkt)
+ return s[l:], self.m2i(pkt,s[:l])
+
+ def i2len(self, pkt, x):
+ return len(self.i2m(pkt, x))
+
+ def m2i(self, pkt, x):
+ cur = []
+ while x:
+ l = (x[0])
+ cur.append(x[1:1+l])
+ x = x[l+1:]
+ ret_str = b".".join(cur)
+ return ret_str
+
+ def i2m(self, pkt, x):
+ if not x:
+ return b""
+ tmp = b"".join(map(lambda z: chr(len(z)).encode('ascii')+z, x.split(b'.')))
+ return tmp
+
+class DHCP6OptNISDomain(_DHCP6OptGuessPayload): #RFC3898
+ name = "DHCP6 Option - NIS Domain Name"
+ fields_desc = [ ShortEnumField("optcode", 29, dhcp6opts),
+ FieldLenField("optlen", None, length_of="nisdomain"),
+ DomainNameField("nisdomain", "",
+ length_from = lambda pkt: pkt.optlen) ]
+
+class DHCP6OptNISPDomain(_DHCP6OptGuessPayload): #RFC3898
+ name = "DHCP6 Option - NIS+ Domain Name"
+ fields_desc = [ ShortEnumField("optcode", 30, dhcp6opts),
+ FieldLenField("optlen", None, length_of="nispdomain"),
+ DomainNameField("nispdomain", "",
+ length_from= lambda pkt: pkt.optlen) ]
+
+class DHCP6OptSNTPServers(_DHCP6OptGuessPayload): #RFC4075
+ name = "DHCP6 option - SNTP Servers"
+ fields_desc = [ ShortEnumField("optcode", 31, dhcp6opts),
+ FieldLenField("optlen", None, length_of="sntpservers"),
+ IP6ListField("sntpservers", [],
+ length_from = lambda pkt: pkt.optlen) ]
+
+IRT_DEFAULT=86400
+IRT_MINIMUM=600
+class DHCP6OptInfoRefreshTime(_DHCP6OptGuessPayload): #RFC4242
+ name = "DHCP6 Option - Information Refresh Time"
+ fields_desc = [ ShortEnumField("optcode", 32, dhcp6opts),
+ ShortField("optlen", 4),
+ IntField("reftime", IRT_DEFAULT)] # One day
+
+class DHCP6OptBCMCSDomains(_DHCP6OptGuessPayload): #RFC4280
+ name = "DHCP6 Option - BCMCS Domain Name List"
+ fields_desc = [ ShortEnumField("optcode", 33, dhcp6opts),
+ FieldLenField("optlen", None, length_of="bcmcsdomains"),
+ DomainNameListField("bcmcsdomains", [],
+ length_from = lambda pkt: pkt.optlen) ]
+
+class DHCP6OptBCMCSServers(_DHCP6OptGuessPayload): #RFC4280
+ name = "DHCP6 Option - BCMCS Addresses List"
+ fields_desc = [ ShortEnumField("optcode", 34, dhcp6opts),
+ FieldLenField("optlen", None, length_of="bcmcsservers"),
+ IP6ListField("bcmcsservers", [],
+ length_from= lambda pkt: pkt.optlen) ]
+
+# TODO : Does Nothing at the moment
+class DHCP6OptGeoConf(_DHCP6OptGuessPayload): #RFC-ietf-geopriv-dhcp-civil-09.txt
+ name = ""
+ fields_desc = [ ShortEnumField("optcode", 36, dhcp6opts),
+ FieldLenField("optlen", None, length_of="optdata"),
+ StrLenField("optdata", "",
+ length_from = lambda pkt: pkt.optlen) ]
+
+# TODO: see if we encounter opaque values from vendor devices
+class DHCP6OptRemoteID(_DHCP6OptGuessPayload): #RFC4649
+ name = "DHCP6 Option - Relay Agent Remote-ID"
+ fields_desc = [ ShortEnumField("optcode", 37, dhcp6opts),
+ FieldLenField("optlen", None, length_of="remoteid",
+ adjust = lambda pkt,x: x+4),
+ IntEnumField("enterprisenum", None, iana_enterprise_num),
+ StrLenField("remoteid", b"",
+ length_from = lambda pkt: pkt.optlen-4) ]
+
+# TODO : 'subscriberid' default value should be at least 1 byte long
+class DHCP6OptSubscriberID(_DHCP6OptGuessPayload): #RFC4580
+ name = "DHCP6 Option - Subscriber ID"
+ fields_desc = [ ShortEnumField("optcode", 38, dhcp6opts),
+ FieldLenField("optlen", None, length_of="subscriberid"),
+ StrLenField("subscriberid", b"",
+ length_from = lambda pkt: pkt.optlen) ]
+
+# TODO : "The data in the Domain Name field MUST be encoded
+# as described in Section 8 of [5]"
+class DHCP6OptClientFQDN(_DHCP6OptGuessPayload): #RFC4704
+ name = "DHCP6 Option - Client FQDN"
+ fields_desc = [ ShortEnumField("optcode", 39, dhcp6opts),
+ FieldLenField("optlen", None, length_of="fqdn",
+ adjust = lambda pkt,x: x+1),
+ BitField("res", 0, 5),
+ FlagsField("flags", 0, 3, "SON" ),
+ DomainNameField("fqdn", "",
+ length_from = lambda pkt: pkt.optlen-1) ]
+
+class DHCP6OptRelayAgentERO(_DHCP6OptGuessPayload): # RFC4994
+ name = "DHCP6 Option - RelayRequest Option"
+ fields_desc = [ ShortEnumField("optcode", 43, dhcp6opts),
+ FieldLenField("optlen", None, length_of="reqopts", fmt="!H"),
+ _OptReqListField("reqopts", [23, 24],
+ length_from = lambda pkt: pkt.optlen) ]
+
+#####################################################################
+### DHCPv6 messages ###
+#####################################################################
+
+# Some state parameters of the protocols that should probably be
+# useful to have in the configuration (and keep up-to-date)
+DHCP6RelayAgentUnicastAddr=""
+DHCP6RelayHopCount=""
+DHCP6ServerUnicastAddr=""
+DHCP6ClientUnicastAddr=""
+DHCP6ClientIA_TA=""
+DHCP6ClientIA_NA=""
+DHCP6ClientIAID=""
+T1="" # Voir 2462
+T2="" # Voir 2462
+DHCP6ServerDUID=""
+DHCP6CurrentTransactionID="" # devrait etre utilise pour matcher une
+# reponse et mis a jour en mode client par une valeur aleatoire pour
+# laquelle on attend un retour de la part d'un serveur.
+DHCP6PrefVal="" # la valeur de preference a utiliser dans
+# les options preference
+
+# Emitted by :
+# - server : ADVERTISE, REPLY, RECONFIGURE, RELAY-REPL (vers relay)
+# - client : SOLICIT, REQUEST, CONFIRM, RENEW, REBIND, RELEASE, DECLINE,
+# INFORMATION REQUEST
+# - relay : RELAY-FORW (toward server)
+
+class _DHCP6GuessPayload(Packet):
+ def guess_payload_class(self, payload):
+ if len(payload) > 1 :
+ print((payload[0]))
+ return get_cls(dhcp6opts.get(ord(payload[0]),"DHCP6OptUnknown"), conf.raw_layer)
+ return conf.raw_layer
+
+#####################################################################
+## DHCPv6 messages sent between Clients and Servers (types 1 to 11)
+# Comme specifie en section 15.1 de la RFC 3315, les valeurs de
+# transaction id sont selectionnees de maniere aleatoire par le client
+# a chaque emission et doivent matcher dans les reponses faites par
+# les clients
+class DHCP6(_DHCP6OptGuessPayload):
+ name = "DHCPv6 Generic Message)"
+ fields_desc = [ ByteEnumField("msgtype",None,dhcp6types),
+ X3BytesField("trid",0x000000) ]
+ overload_fields = { UDP: {"sport": 546, "dport": 547} }
+
+ def hashret(self):
+ return struct.pack("!I", self.trid)[1:4]
+
+#####################################################################
+# Solicit Message : sect 17.1.1 RFC3315
+# - sent by client
+# - must include a client identifier option
+# - the client may include IA options for any IAs to which it wants the
+# server to assign address
+# - The client use IA_NA options to request the assignment of
+# non-temporary addresses and uses IA_TA options to request the
+# assignment of temporary addresses
+# - The client should include an Option Request option to indicate the
+# options the client is interested in receiving (eventually
+# including hints)
+# - The client includes a Reconfigure Accept option if is willing to
+# accept Reconfigure messages from the server.
+# Le cas du send and reply est assez particulier car suivant la
+# presence d'une option rapid commit dans le solicit, l'attente
+# s'arrete au premier message de reponse recu ou alors apres un
+# timeout. De la meme maniere, si un message Advertise arrive avec une
+# valeur de preference de 255, il arrete l'attente et envoie une
+# Request.
+# - The client announces its intention to use DHCP authentication by
+# including an Authentication option in its solicit message. The
+# server selects a key for the client based on the client's DUID. The
+# client and server use that key to authenticate all DHCP messages
+# exchanged during the session
+
+class DHCP6_Solicit(DHCP6):
+ name = "DHCPv6 Solicit Message"
+ msgtype = 1
+ overload_fields = { UDP: {"sport": 546, "dport": 547} }
+
+#####################################################################
+# Advertise Message
+# - sent by server
+# - Includes a server identifier option
+# - Includes a client identifier option
+# - the client identifier option must match the client's DUID
+# - transaction ID must match
+
+class DHCP6_Advertise(DHCP6):
+ name = "DHCPv6 Advertise Message"
+ msgtype = 2
+ overload_fields = { UDP: {"sport": 547, "dport": 546} }
+
+ def answers(self, other):
+ return (isinstance(other,DHCP6_Solicit) and
+ other.msgtype == 1 and
+ self.trid == other.trid)
+
+#####################################################################
+# Request Message
+# - sent by clients
+# - includes a server identifier option
+# - the content of Server Identifier option must match server's DUID
+# - includes a client identifier option
+# - must include an ORO Option (even with hints) p40
+# - can includes a reconfigure Accept option indicating whether or
+# not the client is willing to accept Reconfigure messages from
+# the server (p40)
+# - When the server receives a Request message via unicast from a
+# client to which the server has not sent a unicast option, the server
+# discards the Request message and responds with a Reply message
+# containinig Status Code option with the value UseMulticast, a Server
+# Identifier Option containing the server's DUID, the client
+# Identifier option from the client message and no other option.
+
+class DHCP6_Request(DHCP6):
+ name = "DHCPv6 Request Message"
+ msgtype = 3
+
+#####################################################################
+# Confirm Message
+# - sent by clients
+# - must include a clien identifier option
+# - When the server receives a Confirm Message, the server determines
+# whether the addresses in the Confirm message are appropriate for the
+# link to which the client is attached. cf p50
+
+class DHCP6_Confirm(DHCP6):
+ name = "DHCPv6 Confirm Message"
+ msgtype = 4
+
+#####################################################################
+# Renew Message
+# - sent by clients
+# - must include a server identifier option
+# - content of server identifier option must match the server's identifier
+# - must include a client identifier option
+# - the clients includes any IA assigned to the interface that may
+# have moved to a new link, along with the addresses associated with
+# those IAs in its confirm messages
+# - When the server receives a Renew message that contains an IA
+# option from a client, it locates the client's binding and verifies
+# that the information in the IA from the client matches the
+# information for that client. If the server cannot find a client
+# entry for the IA the server returns the IA containing no addresses
+# with a status code option est to NoBinding in the Reply message. cf
+# p51 pour le reste.
+
+class DHCP6_Renew(DHCP6):
+ name = "DHCPv6 Renew Message"
+ msgtype = 5
+
+#####################################################################
+# Rebind Message
+# - sent by clients
+# - must include a client identifier option
+# cf p52
+
+class DHCP6_Rebind(DHCP6):
+ name = "DHCPv6 Rebind Message"
+ msgtype = 6
+
+#####################################################################
+# Reply Message
+# - sent by servers
+# - the message must include a server identifier option
+# - transaction-id field must match the value of original message
+# The server includes a Rapid Commit option in the Reply message to
+# indicate that the reply is in response to a solicit message
+# - if the client receives a reply message with a Status code option
+# with the value UseMulticast, the client records the receipt of the
+# message and sends subsequent messages to the server through the
+# interface on which the message was received using multicast. The
+# client resends the original message using multicast
+# - When the client receives a NotOnLink status from the server in
+# response to a Confirm message, the client performs DHCP server
+# solicitation as described in section 17 and client-initiated
+# configuration as descrribed in section 18 (RFC 3315)
+# - when the client receives a NotOnLink status from the server in
+# response to a Request, the client can either re-issue the Request
+# without specifying any addresses or restart the DHCP server
+# discovery process.
+# - the server must include a server identifier option containing the
+# server's DUID in the Reply message
+
+class DHCP6_Reply(DHCP6):
+ name = "DHCPv6 Reply Message"
+ msgtype = 7
+
+ overload_fields = { UDP: {"sport": 547, "dport": 546} }
+
+ def answers(self, other):
+
+ types = (DHCP6_InfoRequest, DHCP6_Confirm, DHCP6_Rebind, DHCP6_Decline, DHCP6_Request, DHCP6_Release, DHCP6_Renew)
+
+ return (isinstance(other, types) and
+ self.trid == other.trid)
+
+#####################################################################
+# Release Message
+# - sent by clients
+# - must include a server identifier option
+# cf p53
+
+class DHCP6_Release(DHCP6):
+ name = "DHCPv6 Release Message"
+ msgtype = 8
+
+#####################################################################
+# Decline Message
+# - sent by clients
+# - must include a client identifier option
+# - Server identifier option must match server identifier
+# - The addresses to be declined must be included in the IAs. Any
+# addresses for the IAs the client wishes to continue to use should
+# not be in added to the IAs.
+# - cf p54
+
+class DHCP6_Decline(DHCP6):
+ name = "DHCPv6 Decline Message"
+ msgtype = 9
+
+#####################################################################
+# Reconfigure Message
+# - sent by servers
+# - must be unicast to the client
+# - must include a server identifier option
+# - must include a client identifier option that contains the client DUID
+# - must contain a Reconfigure Message Option and the message type
+# must be a valid value
+# - the server sets the transaction-id to 0
+# - The server must use DHCP Authentication in the Reconfigure
+# message. Autant dire que ca va pas etre le type de message qu'on va
+# voir le plus souvent.
+
+class DHCP6_Reconf(DHCP6):
+ name = "DHCPv6 Reconfigure Message"
+ msgtype = 10
+ overload_fields = { UDP: { "sport": 547, "dport": 546 } }
+
+
+#####################################################################
+# Information-Request Message
+# - sent by clients when needs configuration information but no
+# addresses.
+# - client should include a client identifier option to identify
+# itself. If it doesn't the server is not able to return client
+# specific options or the server can choose to not respond to the
+# message at all. The client must include a client identifier option
+# if the message will be authenticated.
+# - client must include an ORO of option she's interested in receiving
+# (can include hints)
+
+class DHCP6_InfoRequest(DHCP6):
+ name = "DHCPv6 Information Request Message"
+ msgtype = 11
+
+#####################################################################
+# sent between Relay Agents and Servers
+#
+# Normalement, doit inclure une option "Relay Message Option"
+# peut en inclure d'autres.
+# voir section 7.1 de la 3315
+
+# Relay-Forward Message
+# - sent by relay agents to servers
+# If the relay agent relays messages to the All_DHCP_Servers multicast
+# address or other multicast addresses, it sets the Hop Limit field to
+# 32.
+
+class DHCP6_RelayForward(_DHCP6GuessPayload,Packet):
+ name = "DHCPv6 Relay Forward Message (Relay Agent/Server Message)"
+ fields_desc = [ ByteEnumField("msgtype", 12, dhcp6types),
+ ByteField("hopcount", None),
+ IP6Field("linkaddr", "::"),
+ IP6Field("peeraddr", "::") ]
+ def hashret(self): # we filter on peer address field
+ return inet_pton(socket.AF_INET6, self.peeraddr)
+
+#####################################################################
+# sent between Relay Agents and Servers
+# Normalement, doit inclure une option "Relay Message Option"
+# peut en inclure d'autres.
+# Les valeurs des champs hop-count, link-addr et peer-addr
+# sont copiees du messsage Forward associe. POur le suivi de session.
+# Pour le moment, comme decrit dans le commentaire, le hashret
+# se limite au contenu du champ peer address.
+# Voir section 7.2 de la 3315.
+
+# Relay-Reply Message
+# - sent by servers to relay agents
+# - if the solicit message was received in a Relay-Forward message,
+# the server constructs a relay-reply message with the Advertise
+# message in the payload of a relay-message. cf page 37/101. Envoie de
+# ce message en unicast au relay-agent. utilisation de l'adresse ip
+# presente en ip source du paquet recu
+
+class DHCP6_RelayReply(DHCP6_RelayForward):
+ name = "DHCPv6 Relay Reply Message (Relay Agent/Server Message)"
+ msgtype = 13
+ def hashret(self): # We filter on peer address field.
+ return inet_pton(socket.AF_INET6, self.peeraddr)
+ def answers(self, other):
+ return (isinstance(other, DHCP6_RelayForward) and
+ self.hopcount == other.hopcount and
+ self.linkaddr == other.linkaddr and
+ self.peeraddr == other.peeraddr )
+
+
+dhcp6_cls_by_type = { 1: "DHCP6_Solicit",
+ 2: "DHCP6_Advertise",
+ 3: "DHCP6_Request",
+ 4: "DHCP6_Confirm",
+ 5: "DHCP6_Renew",
+ 6: "DHCP6_Rebind",
+ 7: "DHCP6_Reply",
+ 8: "DHCP6_Release",
+ 9: "DHCP6_Decline",
+ 10: "DHCP6_Reconf",
+ 11: "DHCP6_InfoRequest",
+ 12: "DHCP6_RelayForward",
+ 13: "DHCP6_RelayReply" }
+
+def _dhcp6_dispatcher(x, *args, **kargs):
+ cls = conf.raw_layer
+ if len(x) >= 2:
+ cls = get_cls(dhcp6_cls_by_type.get((x[0]), "Raw"), conf.raw_layer)
+ return cls(x, *args, **kargs)
+
+bind_bottom_up(UDP, _dhcp6_dispatcher, { "dport": 547 } )
+bind_bottom_up(UDP, _dhcp6_dispatcher, { "dport": 546 } )
+
+
+
+class DHCPv6_am(AnsweringMachine):
+ function_name = "dhcp6d"
+ filter = "udp and port 546 and port 547"
+ send_function = staticmethod(send)
+ def usage(self):
+ msg = """
+dhcp6d( dns="2001:500::1035", domain="localdomain, local", duid=None)
+ iface=conf.iface6, advpref=255, sntpservers=None,
+ sipdomains=None, sipservers=None,
+ nisdomain=None, nisservers=None,
+ nispdomain=None, nispservers=None,
+ bcmcsdomain=None, bcmcsservers=None)
+
+ debug : When set, additional debugging information is printed.
+
+ duid : some DUID class (DUID_LLT, DUID_LL or DUID_EN). If none
+ is provided a DUID_LLT is constructed based on the MAC
+ address of the sending interface and launch time of dhcp6d
+ answering machine.
+
+ iface : the interface to listen/reply on if you do not want to use
+ conf.iface6.
+
+ advpref : Value in [0,255] given to Advertise preference field.
+ By default, 255 is used. Be aware that this specific
+ value makes clients stops waiting for further Advertise
+ messages from other servers.
+
+ dns : list of recursive DNS servers addresses (as a string or list).
+ By default, it is set empty and the associated DHCP6OptDNSServers
+ option is inactive. See RFC 3646 for details.
+ domain : a list of DNS search domain (as a string or list). By default,
+ it is empty and the associated DHCP6OptDomains option is inactive.
+ See RFC 3646 for details.
+
+ sntpservers : a list of SNTP servers IPv6 addresses. By default,
+ it is empty and the associated DHCP6OptSNTPServers option
+ is inactive.
+
+ sipdomains : a list of SIP domains. By default, it is empty and the
+ associated DHCP6OptSIPDomains option is inactive. See RFC 3319
+ for details.
+ sipservers : a list of SIP servers IPv6 addresses. By default, it is
+ empty and the associated DHCP6OptSIPDomains option is inactive.
+ See RFC 3319 for details.
+
+ nisdomain : a list of NIS domains. By default, it is empty and the
+ associated DHCP6OptNISDomains option is inactive. See RFC 3898
+ for details. See RFC 3646 for details.
+ nisservers : a list of NIS servers IPv6 addresses. By default, it is
+ empty and the associated DHCP6OptNISServers option is inactive.
+ See RFC 3646 for details.
+
+ nispdomain : a list of NIS+ domains. By default, it is empty and the
+ associated DHCP6OptNISPDomains option is inactive. See RFC 3898
+ for details.
+ nispservers : a list of NIS+ servers IPv6 addresses. By default, it is
+ empty and the associated DHCP6OptNISServers option is inactive.
+ See RFC 3898 for details.
+
+ bcmcsdomain : a list of BCMCS domains. By default, it is empty and the
+ associated DHCP6OptBCMCSDomains option is inactive. See RFC 4280
+ for details.
+ bcmcsservers : a list of BCMCS servers IPv6 addresses. By default, it is
+ empty and the associated DHCP6OptBCMCSServers option is inactive.
+ See RFC 4280 for details.
+
+ If you have a need for others, just ask ... or provide a patch."""
+ print(msg)
+
+ def parse_options(self, dns="2001:500::1035", domain="localdomain, local",
+ startip="2001:db8::1", endip="2001:db8::20", duid=None,
+ sntpservers=None, sipdomains=None, sipservers=None,
+ nisdomain=None, nisservers=None, nispdomain=None,
+ nispservers=None, bcmcsservers=None, bcmcsdomains=None,
+ iface=None, debug=0, advpref=255):
+ def norm_list(val, param_name):
+ if val is None:
+ return None
+ if type(val) is list:
+ return val
+ elif type(val) is str:
+ l = val.split(',')
+ return map(lambda x: x.strip(), l)
+ else:
+ print("Bad '%s' parameter provided." % param_name)
+ self.usage()
+ return -1
+
+ if iface is None:
+ iface = conf.iface6
+
+ self.debug = debug
+
+ # Dictionary of provided DHCPv6 options, keyed by option type
+ self.dhcpv6_options={}
+
+ for o in [(dns, "dns", 23, lambda x: DHCP6OptDNSServers(dnsservers=x)),
+ (domain, "domain", 24, lambda x: DHCP6OptDNSDomains(dnsdomains=x)),
+ (sntpservers, "sntpservers", 31, lambda x: DHCP6OptSNTPServers(sntpservers=x)),
+ (sipservers, "sipservers", 22, lambda x: DHCP6OptSIPServers(sipservers=x)),
+ (sipdomains, "sipdomains", 21, lambda x: DHCP6OptSIPDomains(sipdomains=x)),
+ (nisservers, "nisservers", 27, lambda x: DHCP6OptNISServers(nisservers=x)),
+ (nisdomain, "nisdomain", 29, lambda x: DHCP6OptNISDomain(nisdomain=(x+[""])[0])),
+ (nispservers, "nispservers", 28, lambda x: DHCP6OptNISPServers(nispservers=x)),
+ (nispdomain, "nispdomain", 30, lambda x: DHCP6OptNISPDomain(nispdomain=(x+[""])[0])),
+ (bcmcsservers, "bcmcsservers", 33, lambda x: DHCP6OptBCMCSServers(bcmcsservers=x)),
+ (bcmcsdomains, "bcmcsdomains", 34, lambda x: DHCP6OptBCMCSDomains(bcmcsdomains=x))]:
+
+ opt = norm_list(o[0], o[1])
+ if opt == -1: # Usage() was triggered
+ return False
+ elif opt is None: # We won't return that option
+ pass
+ else:
+ self.dhcpv6_options[o[2]] = o[3](opt)
+
+ if self.debug:
+ print("\n[+] List of active DHCPv6 options:")
+ opts = self.dhcpv6_options.keys()
+ opts.sort()
+ for i in opts:
+ print(" %d: %s" % (i, repr(self.dhcpv6_options[i])))
+
+ # Preference value used in Advertise.
+ self.advpref = advpref
+
+ # IP Pool
+ self.startip = startip
+ self.endip = endip
+ # XXX TODO Check IPs are in same subnet
+
+ ####
+ # The interface we are listening/replying on
+ self.iface = iface
+
+ ####
+ # Generate a server DUID
+ if duid is not None:
+ self.duid = duid
+ else:
+ # Timeval
+ from time import gmtime, strftime, mktime
+ epoch = (2000, 1, 1, 0, 0, 0, 5, 1, 0)
+ delta = mktime(epoch) - mktime(gmtime(0))
+ timeval = time.time() - delta
+
+ # Mac Address
+ rawmac = get_if_raw_hwaddr(iface)
+ mac = ":".join(map(lambda x: "%.02x" % x, rawmac))
+
+ self.duid = DUID_LLT(timeval = timeval, lladdr = mac)
+
+ if self.debug:
+ print("\n[+] Our server DUID:" )
+ self.duid.show(label_lvl=" "*4)
+
+ ####
+ # Find the source address we will use
+ #l = filter(lambda x: x[2] == iface and in6_islladdr(x[0]), in6_getifaddr())
+ l = [ x for x in in6_getifaddr() if x[2] == iface and in6_islladdr(x[0]) ]
+ if not l:
+ warning("Unable to get a Link-Local address")
+ return
+
+ self.src_addr = l[0][0]
+
+ ####
+ # Our leases
+ self.leases = {}
+
+
+ if self.debug:
+ print("\n[+] Starting DHCPv6 service on %s:" % self.iface )
+
+ def is_request(self, p):
+ if not IPv6 in p:
+ return False
+
+ src = p[IPv6].src
+ dst = p[IPv6].dst
+
+ p = p[IPv6].payload
+ if not isinstance(p, UDP) or p.sport != 546 or p.dport != 547 :
+ return False
+
+ p = p.payload
+ if not isinstance(p, DHCP6):
+ return False
+
+ # Message we considered client messages :
+ # Solicit (1), Request (3), Confirm (4), Renew (5), Rebind (6)
+ # Decline (9), Release (8), Information-request (11),
+ if not (p.msgtype in [1, 3, 4, 5, 6, 8, 9, 11]):
+ return False
+
+ # Message validation following section 15 of RFC 3315
+
+ if ((p.msgtype == 1) or # Solicit
+ (p.msgtype == 6) or # Rebind
+ (p.msgtype == 4)): # Confirm
+ if ((not DHCP6OptClientId in p) or
+ DHCP6OptServerId in p):
+ return False
+
+ if (p.msgtype == 6 or # Rebind
+ p.msgtype == 4): # Confirm
+ # XXX We do not reply to Confirm or Rebind as we
+ # XXX do not support address assignment
+ return False
+
+ elif (p.msgtype == 3 or # Request
+ p.msgtype == 5 or # Renew
+ p.msgtype == 8): # Release
+
+ # Both options must be present
+ if ((not DHCP6OptServerId in p) or
+ (not DHCP6OptClientId in p)):
+ return False
+ # provided server DUID must match ours
+ duid = p[DHCP6OptServerId].duid
+ if (type(duid) != type(self.duid)):
+ return False
+ if bytes(duid) != bytes(self.duid):
+ return False
+
+ if (p.msgtype == 5 or # Renew
+ p.msgtype == 8): # Release
+ # XXX We do not reply to Renew or Release as we
+ # XXX do not support address assignment
+ return False
+
+ elif p.msgtype == 9: # Decline
+ # XXX We should check if we are tracking that client
+ if not self.debug:
+ return False
+
+ bo = Color.bold
+ g = Color.green + bo
+ b = Color.blue + bo
+ n = Color.normal
+ r = Color.red
+
+ vendor = in6_addrtovendor(src)
+ if (vendor and vendor != "UNKNOWN"):
+ vendor = " [" + b + vendor + n + "]"
+ else:
+ vendor = ""
+ src = bo + src + n
+
+ it = p
+ addrs = []
+ while it:
+ l = []
+ if isinstance(it, DHCP6OptIA_NA):
+ l = it.ianaopts
+ elif isinstance(it, DHCP6OptIA_TA):
+ l = it.iataopts
+
+ #opsaddr = filter(lambda x: isinstance(x, DHCP6OptIAAddress),l)
+ opsaddr = [ x for x in l if isinstance(x, DHCP6OptIAAddress) ]
+ a=map(lambda x: x.addr, opsaddr)
+ addrs += a
+ it = it.payload
+
+ addrs = map(lambda x: bo + x + n, addrs)
+ if debug:
+ msg = r + "[DEBUG]" + n + " Received " + g + "Decline" + n
+ msg += " from " + bo + src + vendor + " for "
+ msg += ", ".join(addrs)+ n
+ print(msg)
+
+ # See sect 18.1.7
+
+ # Sent by a client to warn us she has determined
+ # one or more addresses assigned to her is already
+ # used on the link.
+ # We should simply log that fact. No messaged should
+ # be sent in return.
+
+ # - Message must include a Server identifier option
+ # - the content of the Server identifier option must
+ # match the server's identifier
+ # - the message must include a Client Identifier option
+ return False
+
+ elif p.msgtype == 11: # Information-Request
+ if DHCP6OptServerId in p:
+ duid = p[DHCP6OptServerId].duid
+ if (type(duid) != type(self.duid)):
+ return False
+ if bytes(duid) != bytes(self.duid):
+ return False
+ if ((DHCP6OptIA_NA in p) or
+ (DHCP6OptIA_TA in p) or
+ (DHCP6OptIA_PD in p)):
+ return False
+ else:
+ return False
+
+ return True
+
+ def print_reply(self, req, reply):
+ def norm(s):
+ if s.startswith("DHCPv6 "):
+ s = s[7:]
+ if s.endswith(" Message"):
+ s = s[:-8]
+ return s
+
+ if reply is None:
+ return
+
+ bo = Color.bold
+ g = Color.green + bo
+ b = Color.blue + bo
+ n = Color.normal
+ reqtype = g + norm(req.getlayer(UDP).payload.name) + n
+ reqsrc = req.getlayer(IPv6).src
+ vendor = in6_addrtovendor(reqsrc)
+ if (vendor and vendor != "UNKNOWN"):
+ vendor = " [" + b + vendor + n + "]"
+ else:
+ vendor = ""
+ reqsrc = bo + reqsrc + n
+ reptype = g + norm(reply.getlayer(UDP).payload.name) + n
+
+ print("Sent %s answering to %s from %s%s" % (reptype, reqtype, reqsrc, vendor))
+
+ def make_reply(self, req):
+ req_mac_src = req.src
+ req_mac_dst = req.dst
+
+ p = req[IPv6]
+ req_src = p.src
+ req_dst = p.dst
+
+ p = p.payload.payload
+
+ msgtype = p.msgtype
+ trid = p.trid
+
+ if msgtype == 1: # SOLICIT (See Sect 17.1 and 17.2 of RFC 3315)
+
+ # XXX We don't support address or prefix assignment
+ # XXX We also do not support relay function --arno
+
+ client_duid = p[DHCP6OptClientId].duid
+ resp = IPv6(src=self.src_addr, dst=req_src)
+ resp /= UDP(sport=547, dport=546)
+
+ if p.haslayer(DHCP6OptRapidCommit):
+ # construct a Reply packet
+ resp /= DHCP6_Reply(trid=trid)
+ resp /= DHCP6OptRapidCommit() # See 17.1.2
+ resp /= DHCP6OptServerId(duid = self.duid)
+ resp /= DHCP6OptClientId(duid = client_duid)
+
+ else: # No Rapid Commit in the packet. Reply with an Advertise
+
+ if (p.haslayer(DHCP6OptIA_NA) or
+ p.haslayer(DHCP6OptIA_TA)):
+ # XXX We don't assign addresses at the moment
+ msg = "Scapy6 dhcp6d does not support address assignment"
+ resp /= DHCP6_Advertise(trid = trid)
+ resp /= DHCP6OptStatusCode(statuscode=2, statusmsg=msg)
+ resp /= DHCP6OptServerId(duid = self.duid)
+ resp /= DHCP6OptClientId(duid = client_duid)
+
+ elif p.haslayer(DHCP6OptIA_PD):
+ # XXX We don't assign prefixes at the moment
+ msg = "Scapy6 dhcp6d does not support prefix assignment"
+ resp /= DHCP6_Advertise(trid = trid)
+ resp /= DHCP6OptStatusCode(statuscode=6, statusmsg=msg)
+ resp /= DHCP6OptServerId(duid = self.duid)
+ resp /= DHCP6OptClientId(duid = client_duid)
+
+ else: # Usual case, no request for prefixes or addresse
+ resp /= DHCP6_Advertise(trid = trid)
+ resp /= DHCP6OptPref(prefval = self.advpref)
+ resp /= DHCP6OptServerId(duid = self.duid)
+ resp /= DHCP6OptClientId(duid = client_duid)
+ resp /= DHCP6OptReconfAccept()
+
+ # See which options should be included
+ reqopts = []
+ if p.haslayer(DHCP6OptOptReq): # add only asked ones
+ reqopts = p[DHCP6OptOptReq].reqopts
+ for o in self.dhcpv6_options.keys():
+ if o in reqopts:
+ resp /= self.dhcpv6_options[o]
+ else: # advertise everything we have available
+ for o in self.dhcpv6_options.keys():
+ resp /= self.dhcpv6_options[o]
+
+ return resp
+
+ elif msgtype == 3: #REQUEST (INFO-REQUEST is further below)
+ client_duid = p[DHCP6OptClientId].duid
+ resp = IPv6(src=self.src_addr, dst=req_src)
+ resp /= UDP(sport=547, dport=546)
+ resp /= DHCP6_Solicit(trid=trid)
+ resp /= DHCP6OptServerId(duid = self.duid)
+ resp /= DHCP6OptClientId(duid = client_duid)
+
+ # See which options should be included
+ reqopts = []
+ if p.haslayer(DHCP6OptOptReq): # add only asked ones
+ reqopts = p[DHCP6OptOptReq].reqopts
+ for o in self.dhcpv6_options.keys():
+ if o in reqopts:
+ resp /= self.dhcpv6_options[o]
+ else:
+ # advertise everything we have available.
+ # Should not happen has clients MUST include
+ # and ORO in requests (sec 18.1.1) -- arno
+ for o in self.dhcpv6_options.keys():
+ resp /= self.dhcpv6_options[o]
+
+ return resp
+
+ elif msgtype == 4: # CONFIRM
+ # see Sect 18.1.2
+
+ # Client want to check if addresses it was assigned
+ # are still appropriate
+
+ # Server must discard any Confirm messages that
+ # do not include a Client Identifier option OR
+ # THAT DO INCLUDE a Server Identifier Option
+
+ # XXX we must discard the SOLICIT if it is received with
+ # a unicast destination address
+
+ pass
+
+ elif msgtype == 5: # RENEW
+ # see Sect 18.1.3
+
+ # Clients want to extend lifetime of assigned addresses
+ # and update configuration parameters. This message is sent
+ # specifically to the server that provided her the info
+
+ # - Received message must include a Server Identifier
+ # option.
+ # - the content of server identifier option must match
+ # the server's identifier.
+ # - the message must include a Client identifier option
+
+ pass
+
+ elif msgtype == 6: # REBIND
+ # see Sect 18.1.4
+
+ # Same purpose as the Renew message but sent to any
+ # available server after he received no response
+ # to its previous Renew message.
+
+
+ # - Message must include a Client Identifier Option
+ # - Message can't include a Server identifier option
+
+ # XXX we must discard the SOLICIT if it is received with
+ # a unicast destination address
+
+ pass
+
+ elif msgtype == 8: # RELEASE
+ # See section 18.1.6
+
+ # Message is sent to the server to indicate that
+ # she will no longer use the addresses that was assigned
+ # We should parse the message and verify our dictionary
+ # to log that fact.
+
+
+ # - The message must include a server identifier option
+ # - The content of the Server Identifier option must
+ # match the server's identifier
+ # - the message must include a Client Identifier option
+
+ pass
+
+ elif msgtype == 9: # DECLINE
+ # See section 18.1.7
+ pass
+
+ elif msgtype == 11: # INFO-REQUEST
+ client_duid = None
+ if not p.haslayer(DHCP6OptClientId):
+ if self.debug:
+ warning("Received Info Request message without Client Id option")
+ else:
+ client_duid = p[DHCP6OptClientId].duid
+
+ resp = IPv6(src=self.src_addr, dst=req_src)
+ resp /= UDP(sport=547, dport=546)
+ resp /= DHCP6_Reply(trid=trid)
+ resp /= DHCP6OptServerId(duid = self.duid)
+
+ if client_duid:
+ resp /= DHCP6OptClientId(duid = client_duid)
+
+ # Stack requested options if available
+ reqopts = []
+ if p.haslayer(DHCP6OptOptReq):
+ reqopts = p[DHCP6OptOptReq].reqopts
+ for o in self.dhcpv6_options.keys():
+ resp /= self.dhcpv6_options[o]
+
+ return resp
+
+ else:
+ # what else ?
+ pass
+
+ # - We won't support reemission
+ # - We won't support relay role, nor relay forwarded messages
+ # at the beginning
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dns.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dns.py
new file mode 100644
index 00000000..8a01e273
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dns.py
@@ -0,0 +1,712 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+DNS: Domain Name System.
+"""
+
+import socket,struct
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.ansmachine import *
+from scapy.layers.inet import IP, UDP
+from scapy.utils import str2bytes
+
+class DNSStrField(StrField):
+
+ def h2i(self, pkt, x):
+ if type(x) == str:
+ x = x.encode('ascii')
+ if x == b"":
+ return b"."
+ return x
+
+ def i2m(self, pkt, x):
+ if type(x) == str:
+ x = x.encode('ascii')
+ if x == b".":
+ return b"\x00"
+
+ x = [k[:63] for k in x.split(b".")] # Truncate chunks that cannot be encoded (more than 63 bytes..)
+ x = map(lambda y: bytes([len(y)]) + y, x)
+ x = b"".join(x)
+ if x[-1] != 0:
+ x += b"\x00"
+ return x
+
+ def getfield(self, pkt, s):
+ n = b""
+
+ #if ord(s[0]) == 0:
+ if (s[0]) == 0:
+ return s[1:], b"."
+
+ while 1:
+ #l = ord(s[0])
+ l = (s[0])
+ s = s[1:]
+ if not l:
+ break
+ if l & 0xc0:
+ raise Scapy_Exception("DNS message can't be compressed at this point!")
+ else:
+ n += s[:l]+b"."
+ s = s[l:]
+ return s, n
+
+
+class DNSRRCountField(ShortField):
+ holds_packets=1
+ def __init__(self, name, default, rr):
+ ShortField.__init__(self, name, default)
+ self.rr = rr
+ def _countRR(self, pkt):
+ x = getattr(pkt,self.rr)
+ i = 0
+ while isinstance(x, DNSRR) or isinstance(x, DNSQR) or isdnssecRR(x):
+ x = x.payload
+ i += 1
+ return i
+
+ def i2m(self, pkt, x):
+ if x is None:
+ x = self._countRR(pkt)
+ return x
+ def i2h(self, pkt, x):
+ if x is None:
+ x = self._countRR(pkt)
+ return x
+
+
+def DNSgetstr(s,p):
+ name = b""
+ q = 0
+ jpath = [p]
+ while 1:
+ if p >= len(s):
+ warning("DNS RR prematured end (ofs=%i, len=%i)"%(p,len(s)))
+ break
+ #l = ord(s[p])
+ l = s[p]
+ p += 1
+ if l & 0xc0:
+ if not q:
+ q = p+1
+ if p >= len(s):
+ warning("DNS incomplete jump token at (ofs=%i)" % p)
+ break
+ p = ((l & 0x3f) << 8) + s[p] - 12
+ if p in jpath:
+ warning("DNS decompression loop detected")
+ break
+ jpath.append(p)
+ continue
+ elif l > 0:
+ name += s[p:p+l]+b"."
+ p += l
+ continue
+ break
+ if q:
+ p = q
+ return name,p
+
+
+class DNSRRField(StrField):
+ holds_packets=1
+ def __init__(self, name, countfld, passon=1):
+ StrField.__init__(self, name, None)
+ self.countfld = countfld
+ self.passon = passon
+ def i2m(self, pkt, x):
+ if x is None:
+ return b""
+ return bytes(x)
+ def decodeRR(self, name, s, p):
+ ret = s[p:p+10]
+ type,cls,ttl,rdlen = struct.unpack("!HHIH", ret)
+ p += 10
+ rr = DNSRR(b"\x00"+ret+s[p:p+rdlen])
+ if type in [2, 3, 4, 5]:
+ rr.rdata = DNSgetstr(s,p)[0]
+ del(rr.rdlen)
+ elif type in dnsRRdispatcher.keys():
+ rr = dnsRRdispatcher[type](b"\x00"+ret+s[p:p+rdlen])
+ else:
+ del(rr.rdlen)
+
+ p += rdlen
+
+ rr.rrname = name
+ return rr,p
+ def getfield(self, pkt, s):
+ if type(s) is tuple :
+ s,p = s
+ else:
+ p = 0
+ ret = None
+ c = getattr(pkt, self.countfld)
+ if c > len(s):
+ warning("wrong value: DNS.%s=%i" % (self.countfld,c))
+ return s,b""
+ while c:
+ c -= 1
+ name,p = DNSgetstr(s,p)
+ rr,p = self.decodeRR(name, s, p)
+ if ret is None:
+ ret = rr
+ else:
+ ret.add_payload(rr)
+ if self.passon:
+ return (s,p),ret
+ else:
+ return s[p:],ret
+
+
+class DNSQRField(DNSRRField):
+ holds_packets=1
+ def decodeRR(self, name, s, p):
+ ret = s[p:p+4]
+ p += 4
+ rr = DNSQR(b"\x00"+ret)
+ rr.qname = name
+ return rr,p
+
+
+
+class RDataField(StrLenField):
+ def m2i(self, pkt, s):
+ family = None
+ if pkt.type == 1: # A
+ family = socket.AF_INET
+ elif pkt.type == 12: # PTR
+ s = DNSgetstr(s, 0)[0]
+ elif pkt.type == 16: # TXT
+ ret_s = b""
+ tmp_s = s
+ # RDATA contains a list of strings, each are prepended with
+ # a byte containing the size of the following string.
+ while tmp_s:
+ tmp_len = struct.unpack("!B", bytes([tmp_s[0]]))[0] + 1
+ if tmp_len > len(tmp_s):
+ warning("DNS RR TXT prematured end of character-string (size=%i, remaining bytes=%i)" % (tmp_len, len(tmp_s)))
+ ret_s += tmp_s[1:tmp_len]
+ tmp_s = tmp_s[tmp_len:]
+ s = ret_s
+ elif pkt.type == 28: # AAAA
+ family = socket.AF_INET6
+ if family is not None:
+ s = inet_ntop(family, s)
+ return s
+ def i2m(self, pkt, s):
+ if pkt.type == 1: # A
+ if s:
+ if type(s) is bytes:
+ s = s.decode('ascii')
+ s = inet_aton(s)
+ elif pkt.type in [2,3,4,5]: # NS, MD, MF, CNAME
+ s = b"".join(map(lambda x: bytes([len(x)]) + x, s.split(b".")))
+ #if ord(s[-1]):
+ if s[-1]:
+ s += b"\x00"
+ elif pkt.type == 16: # TXT
+ if s:
+ ret_s = b""
+ # The initial string must be splitted into a list of strings
+ # prepended with theirs sizes.
+ while len(s) >= 255:
+ ret_s += b"\xff" + s[:255]
+ s = s[255:]
+ # The remaining string is less than 255 bytes long
+ if len(s):
+ ret_s += struct.pack("!B", len(s)) + s
+ s = ret_s
+ elif pkt.type == 28: # AAAA
+ if s:
+ s = inet_pton(socket.AF_INET6, s)
+ return s
+
+class RDLenField(Field):
+ def __init__(self, name):
+ Field.__init__(self, name, None, "H")
+ def i2m(self, pkt, x):
+ if x is None:
+ rdataf = pkt.get_field("rdata")
+ x = len(rdataf.i2m(pkt, pkt.rdata))
+ return x
+ def i2h(self, pkt, x):
+ if x is None:
+ rdataf = pkt.get_field("rdata")
+ x = len(rdataf.i2m(pkt, pkt.rdata))
+ return x
+
+
+class DNS(Packet):
+ name = "DNS"
+ fields_desc = [ ShortField("id", 0),
+ BitField("qr", 0, 1),
+ BitEnumField("opcode", 0, 4, {0:"QUERY",1:"IQUERY",2:"STATUS"}),
+ BitField("aa", 0, 1),
+ BitField("tc", 0, 1),
+ BitField("rd", 0, 1),
+ BitField("ra", 0, 1),
+ BitField("z", 0, 1),
+ # AD and CD bits are defined in RFC 2535
+ BitField("ad", 0, 1), # Authentic Data
+ BitField("cd", 0, 1), # Checking Disabled
+ BitEnumField("rcode", 0, 4, {0:"ok", 1:"format-error", 2:"server-failure", 3:"name-error", 4:"not-implemented", 5:"refused"}),
+ DNSRRCountField("qdcount", None, "qd"),
+ DNSRRCountField("ancount", None, "an"),
+ DNSRRCountField("nscount", None, "ns"),
+ DNSRRCountField("arcount", None, "ar"),
+ DNSQRField("qd", "qdcount"),
+ DNSRRField("an", "ancount"),
+ DNSRRField("ns", "nscount"),
+ DNSRRField("ar", "arcount",0) ]
+ def answers(self, other):
+ return (isinstance(other, DNS)
+ and self.id == other.id
+ and self.qr == 1
+ and other.qr == 0)
+
+ def mysummary(self):
+ type = ["Qry","Ans"][self.qr]
+ name = ""
+ if self.qr:
+ type = "Ans"
+ if self.ancount > 0 and isinstance(self.an, DNSRR):
+ name = ' "%s"' % self.an.getstrval("rdata")
+ else:
+ type = "Qry"
+ if self.qdcount > 0 and isinstance(self.qd, DNSQR):
+ name = ' "%s"' % self.qd.getstrval("qname")
+ return 'DNS %s%s ' % (type, name)
+
+dnstypes = { 0:"ANY", 255:"ALL",
+ 1:"A", 2:"NS", 3:"MD", 4:"MF", 5:"CNAME", 6:"SOA", 7: "MB", 8:"MG",
+ 9:"MR",10:"NULL",11:"WKS",12:"PTR",13:"HINFO",14:"MINFO",15:"MX",16:"TXT",
+ 17:"RP",18:"AFSDB",28:"AAAA", 33:"SRV",38:"A6",39:"DNAME",
+ 41:"OPT", 43:"DS", 46:"RRSIG", 47:"NSEC", 48:"DNSKEY",
+ 50: "NSEC3", 51: "NSEC3PARAM", 32769:"DLV" }
+
+dnsqtypes = {251:"IXFR",252:"AXFR",253:"MAILB",254:"MAILA",255:"ALL"}
+dnsqtypes.update(dnstypes)
+dnsclasses = {1: 'IN', 2: 'CS', 3: 'CH', 4: 'HS', 255: 'ANY'}
+
+
+class DNSQR(Packet):
+ name = "DNS Question Record"
+ show_indent=0
+ fields_desc = [ DNSStrField("qname",b""),
+ ShortEnumField("qtype", 1, dnsqtypes),
+ ShortEnumField("qclass", 1, dnsclasses) ]
+
+
+
+# RFC 2671 - Extension Mechanisms for DNS (EDNS0)
+
+class EDNS0TLV(Packet):
+ name = "DNS EDNS0 TLV"
+ fields_desc = [ ShortEnumField("optcode", 0, { 0: "Reserved", 1: "LLQ", 2: "UL", 3: "NSID", 4: "Reserved", 5: "PING" }),
+ FieldLenField("optlen", None, "optdata", fmt="H"),
+ StrLenField("optdata", b"", length_from=lambda pkt: pkt.optlen) ]
+
+ def extract_padding(self, p):
+ return b"", p
+
+class DNSRROPT(Packet):
+ name = "DNS OPT Resource Record"
+ fields_desc = [ DNSStrField("rrname",b""),
+ ShortEnumField("type", 41, dnstypes),
+ ShortField("rclass", 4096),
+ ByteField("extrcode", 0),
+ ByteField("version", 0),
+ # version 0 means EDNS0
+ BitEnumField("z", 32768, 16, { 32768: "D0" }),
+ # D0 means DNSSEC OK from RFC 3225
+ FieldLenField("rdlen", None, length_of="rdata", fmt="H"),
+ PacketListField("rdata", [], EDNS0TLV, length_from=lambda pkt: pkt.rdlen) ]
+
+# RFC 4034 - Resource Records for the DNS Security Extensions
+
+# 09/2013 from http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
+dnssecalgotypes = { 0:"Reserved", 1:"RSA/MD5", 2:"Diffie-Hellman", 3:"DSA/SHA-1",
+ 4:"Reserved", 5:"RSA/SHA-1", 6:"DSA-NSEC3-SHA1",
+ 7:"RSASHA1-NSEC3-SHA1", 8:"RSA/SHA-256", 9:"Reserved",
+ 10:"RSA/SHA-512", 11:"Reserved", 12:"GOST R 34.10-2001",
+ 13:"ECDSA Curve P-256 with SHA-256", 14: "ECDSA Curve P-384 with SHA-384",
+ 252:"Reserved for Indirect Keys", 253:"Private algorithms - domain name",
+ 254:"Private algorithms - OID", 255:"Reserved" }
+
+# 09/2013 from http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml
+dnssecdigesttypes = { 0:"Reserved", 1:"SHA-1", 2:"SHA-256", 3:"GOST R 34.11-94", 4:"SHA-384" }
+
+
+class TimeField(IntField):
+
+ def any2i(self, pkt, x):
+ if type(x) == str:
+ import time, calendar
+ t = time.strptime(x, "%Y%m%d%H%M%S")
+ return int(calendar.timegm(t))
+ return x
+
+ def i2repr(self, pkt, x):
+ import time
+ x = self.i2h(pkt, x)
+ t = time.strftime("%Y%m%d%H%M%S", time.gmtime(x))
+ return "%s (%d)" % (t ,x)
+
+
+def bitmap2RRlist(bitmap):
+ """
+ Decode the 'Type Bit Maps' field of the NSEC Resource Record into an
+ integer list.
+ """
+ # RFC 4034, 4.1.2. The Type Bit Maps Field
+
+ RRlist = []
+
+ while bitmap:
+
+ if len(bitmap) < 2:
+ warning("bitmap too short (%i)" % len(bitmap))
+ return
+
+ #window_block = ord(bitmap[0]) # window number
+ window_block = (bitmap[0]) # window number
+ offset = 256*window_block # offset of the Ressource Record
+ #bitmap_len = ord(bitmap[0]) # length of the bitmap in bytes
+ bitmap_len = (bitmap[1]) # length of the bitmap in bytes
+
+ if bitmap_len <= 0 or bitmap_len > 32:
+ warning("bitmap length is no valid (%i)" % bitmap_len)
+ return
+
+ tmp_bitmap = bitmap[2:2+bitmap_len]
+
+ # Let's compare each bit of tmp_bitmap and compute the real RR value
+ for b in range(len(tmp_bitmap)):
+ v = 128
+ for i in range(8):
+ #if ord(tmp_bitmap[b]) & v:
+ if (tmp_bitmap[b]) & v:
+ # each of the RR is encoded as a bit
+ RRlist += [ offset + b*8 + i ]
+ v = v >> 1
+
+# Next block if any
+ bitmap = bitmap[2+bitmap_len:]
+
+ return RRlist
+
+
+def RRlist2bitmap(lst):
+ """
+ Encode a list of integers representing Resource Records to a bitmap field
+ used in the NSEC Resource Record.
+ """
+ # RFC 4034, 4.1.2. The Type Bit Maps Field
+
+ import math
+
+ bitmap = b""
+ lst = list(set(lst))
+ lst.sort()
+
+ #lst = filter(lambda x: x <= 65535, lst)
+ #lst = map(lambda x: abs(x), lst)
+ lst = [ abs(x) for x in lst if x<= 65535 ]
+
+ # number of window blocks
+ max_window_blocks = int(math.ceil(lst[-1] / 256.))
+ min_window_blocks = int(math.floor(lst[0] / 256.))
+ if min_window_blocks == max_window_blocks:
+ max_window_blocks += 1
+
+ for wb in range(min_window_blocks, max_window_blocks+1):
+ # First, filter out RR not encoded in the current window block
+ # i.e. keep everything between 256*wb <= 256*(wb+1)
+ #rrlist = filter(lambda x: 256*wb <= x and x < 256*(wb+1), lst)
+ rrlist = [ x for x in lst if 256*wb <= x and x < 256*(wb+1) ]
+ rrlist.sort()
+ if rrlist == []:
+ continue
+
+ # Compute the number of bytes used to store the bitmap
+ if rrlist[-1] == 0: # only one element in the list
+ bs = 1
+ else:
+ max = rrlist[-1] - 256*wb
+ #bs = int(math.ceil(max / 8)) + 1 # use at least 1 byte
+ bs = int(max // 8) + 1 # use at least 1 byte
+ if bs > 32: # Don't encode more than 256 bits / values
+ bs = 32
+
+ bitmap += struct.pack("B", wb)
+ bitmap += struct.pack("B", bs)
+
+ # Generate the bitmap
+ for tmp in range(bs):
+ v = 0
+ # Remove out of range Ressource Records
+ #tmp_rrlist = filter(lambda x: 256*wb+8*tmp <= x and x < 256*wb+8*tmp+8, rrlist)
+ tmp_rrlist = [ x for x in rrlist if 256*wb+8*tmp <= x and x < 256*wb+8*tmp+8 ]
+ if not tmp_rrlist == []:
+ # 1. rescale to fit into 8 bits
+ tmp_rrlist = map(lambda x: (x-256*wb)-(tmp*8), tmp_rrlist)
+ # 2. x gives the bit position ; compute the corresponding value
+ tmp_rrlist = map(lambda x: 2**(7-x) , tmp_rrlist)
+ # 3. sum everything
+ #v = reduce(lambda x,y: x+y, tmp_rrlist)
+ v = sum(tmp_rrlist)
+ bitmap += struct.pack("B", v)
+
+ return bitmap
+
+
+class RRlistField(StrField):
+ def h2i(self, pkt, x):
+ if type(x) == list:
+ return RRlist2bitmap(x)
+ return x
+
+ def i2repr(self, pkt, x):
+ x = self.i2h(pkt, x)
+ rrlist = bitmap2RRlist(x)
+ return [ dnstypes.get(rr, rr) for rr in rrlist ]
+
+
+class _DNSRRdummy(Packet):
+ name = "Dummy class that implements post_build() for Ressource Records"
+ def post_build(self, pkt, pay):
+ if not self.rdlen == None:
+ return pkt
+
+ lrrname = len(self.fields_desc[0].i2m(b"", self.getfieldval("rrname")))
+ l = len(pkt) - lrrname - 10
+ pkt = pkt[:lrrname+8] + struct.pack("!H", l) + pkt[lrrname+8+2:]
+
+ return pkt
+
+class DNSRRSOA(_DNSRRdummy):
+ name = "DNS SOA Resource Record"
+ fields_desc = [ DNSStrField("rrname",b""),
+ ShortEnumField("type", 6, dnstypes),
+ ShortEnumField("rclass", 1, dnsclasses),
+ IntField("ttl", 0),
+ ShortField("rdlen", None),
+ DNSStrField("mname", b""),
+ DNSStrField("rname", b""),
+ IntField("serial", 0),
+ IntField("refresh", 0),
+ IntField("retry", 0),
+ IntField("expire", 0),
+ IntField("minimum", 0)
+ ]
+
+class DNSRRRSIG(_DNSRRdummy):
+ name = "DNS RRSIG Resource Record"
+ fields_desc = [ DNSStrField("rrname",b""),
+ ShortEnumField("type", 46, dnstypes),
+ ShortEnumField("rclass", 1, dnsclasses),
+ IntField("ttl", 0),
+ ShortField("rdlen", None),
+ ShortEnumField("typecovered", 1, dnstypes),
+ ByteEnumField("algorithm", 5, dnssecalgotypes),
+ ByteField("labels", 0),
+ IntField("originalttl", 0),
+ TimeField("expiration", 0),
+ TimeField("inception", 0),
+ ShortField("keytag", 0),
+ DNSStrField("signersname", b""),
+ StrField("signature", b"")
+ ]
+
+
+class DNSRRNSEC(_DNSRRdummy):
+ name = "DNS NSEC Resource Record"
+ fields_desc = [ DNSStrField("rrname",b""),
+ ShortEnumField("type", 47, dnstypes),
+ ShortEnumField("rclass", 1, dnsclasses),
+ IntField("ttl", 0),
+ ShortField("rdlen", None),
+ DNSStrField("nextname", b""),
+ RRlistField("typebitmaps", b"")
+ ]
+
+
+class DNSRRDNSKEY(_DNSRRdummy):
+ name = "DNS DNSKEY Resource Record"
+ fields_desc = [ DNSStrField("rrname",b""),
+ ShortEnumField("type", 48, dnstypes),
+ ShortEnumField("rclass", 1, dnsclasses),
+ IntField("ttl", 0),
+ ShortField("rdlen", None),
+ FlagsField("flags", 256, 16, "S???????Z???????"),
+ # S: Secure Entry Point
+ # Z: Zone Key
+ ByteField("protocol", 3),
+ ByteEnumField("algorithm", 5, dnssecalgotypes),
+ StrField("publickey", b"")
+ ]
+
+
+class DNSRRDS(_DNSRRdummy):
+ name = "DNS DS Resource Record"
+ fields_desc = [ DNSStrField("rrname",b""),
+ ShortEnumField("type", 43, dnstypes),
+ ShortEnumField("rclass", 1, dnsclasses),
+ IntField("ttl", 0),
+ ShortField("rdlen", None),
+ ShortField("keytag", 0),
+ ByteEnumField("algorithm", 5, dnssecalgotypes),
+ ByteEnumField("digesttype", 5, dnssecdigesttypes),
+ StrField("digest", b"")
+ ]
+
+
+# RFC 5074 - DNSSEC Lookaside Validation (DLV)
+class DNSRRDLV(DNSRRDS):
+ name = "DNS DLV Resource Record"
+ def __init__(self, *args, **kargs):
+ DNSRRDS.__init__(self, *args, **kargs)
+ if not kargs.get('type', 0):
+ self.type = 32769
+
+# RFC 5155 - DNS Security (DNSSEC) Hashed Authenticated Denial of Existence
+class DNSRRNSEC3(_DNSRRdummy):
+ name = "DNS NSEC3 Resource Record"
+ fields_desc = [ DNSStrField("rrname",b""),
+ ShortEnumField("type", 50, dnstypes),
+ ShortEnumField("rclass", 1, dnsclasses),
+ IntField("ttl", 0),
+ ShortField("rdlen", None),
+ ByteField("hashalg", 0),
+ BitEnumField("flags", 0, 8, {1:"Opt-Out"}),
+ ShortField("iterations", 0),
+ FieldLenField("saltlength", 0, fmt="!B", length_of="salt"),
+ StrLenField("salt", b"", length_from=lambda x: x.saltlength),
+ FieldLenField("hashlength", 0, fmt="!B", length_of="nexthashedownername"),
+ StrLenField("nexthashedownername", b"", length_from=lambda x: x.hashlength),
+ RRlistField("typebitmaps", b"")
+ ]
+
+
+class DNSRRNSEC3PARAM(_DNSRRdummy):
+ name = "DNS NSEC3PARAM Resource Record"
+ fields_desc = [ DNSStrField("rrname",b""),
+ ShortEnumField("type", 51, dnstypes),
+ ShortEnumField("rclass", 1, dnsclasses),
+ IntField("ttl", 0),
+ ShortField("rdlen", None),
+ ByteField("hashalg", 0),
+ ByteField("flags", 0),
+ ShortField("iterations", 0),
+ FieldLenField("saltlength", 0, fmt="!B", length_of="salt"),
+ StrLenField("salt", b"", length_from=lambda pkt: pkt.saltlength)
+ ]
+
+
+dnssecclasses = [ DNSRROPT, DNSRRRSIG, DNSRRDLV, DNSRRDNSKEY, DNSRRNSEC, DNSRRDS, DNSRRNSEC3, DNSRRNSEC3PARAM ]
+
+def isdnssecRR(obj):
+ list = [ isinstance (obj, cls) for cls in dnssecclasses ]
+ ret = False
+ for i in list:
+ ret = ret or i
+ return ret
+
+dnsRRdispatcher = { #6: DNSRRSOA,
+ 41: DNSRROPT, # RFC 1671
+ 43: DNSRRDS, # RFC 4034
+ 46: DNSRRRSIG, # RFC 4034
+ 47: DNSRRNSEC, # RFC 4034
+ 48: DNSRRDNSKEY, # RFC 4034
+ 50: DNSRRNSEC3, # RFC 5155
+ 51: DNSRRNSEC3PARAM, # RFC 5155
+ 32769: DNSRRDLV # RFC 4431
+ }
+
+class DNSRR(Packet):
+ name = "DNS Resource Record"
+ show_indent=0
+ fields_desc = [ DNSStrField("rrname",""),
+ ShortEnumField("type", 1, dnstypes),
+ ShortEnumField("rclass", 1, dnsclasses),
+ IntField("ttl", 0),
+ RDLenField("rdlen"),
+ RDataField("rdata", "", length_from=lambda pkt:pkt.rdlen) ]
+
+bind_layers( UDP, DNS, dport=53)
+bind_layers( UDP, DNS, sport=53)
+
+
+@conf.commands.register
+def dyndns_add(nameserver, name, rdata, type="A", ttl=10):
+ """Send a DNS add message to a nameserver for "name" to have a new "rdata"
+dyndns_add(nameserver, name, rdata, type="A", ttl=10) -> result code (0=ok)
+
+example: dyndns_add("ns1.toto.com", "dyn.toto.com", "127.0.0.1")
+RFC2136
+"""
+ zone = name[name.find(".")+1:]
+ r=sr1(IP(dst=nameserver)/UDP()/DNS(opcode=5,
+ qd=[DNSQR(qname=zone, qtype="SOA")],
+ ns=[DNSRR(rrname=name, type="A",
+ ttl=ttl, rdata=rdata)]),
+ verbose=0, timeout=5)
+ if r and r.haslayer(DNS):
+ return r.getlayer(DNS).rcode
+ else:
+ return -1
+
+
+
+
+@conf.commands.register
+def dyndns_del(nameserver, name, type="ALL", ttl=10):
+ """Send a DNS delete message to a nameserver for "name"
+dyndns_del(nameserver, name, type="ANY", ttl=10) -> result code (0=ok)
+
+example: dyndns_del("ns1.toto.com", "dyn.toto.com")
+RFC2136
+"""
+ zone = name[name.find(".")+1:]
+ r=sr1(IP(dst=nameserver)/UDP()/DNS(opcode=5,
+ qd=[DNSQR(qname=zone, qtype="SOA")],
+ ns=[DNSRR(rrname=name, type=type,
+ rclass="ANY", ttl=0, rdata=b"")]),
+ verbose=0, timeout=5)
+ if r and r.haslayer(DNS):
+ return r.getlayer(DNS).rcode
+ else:
+ return -1
+
+
+class DNS_am(AnsweringMachine):
+ function_name="dns_spoof"
+ filter = "udp port 53"
+
+ def parse_options(self, joker="192.168.1.1", match=None):
+ if match is None:
+ self.match = {}
+ else:
+ self.match = match
+ self.joker=joker
+
+ def is_request(self, req):
+ return req.haslayer(DNS) and req.getlayer(DNS).qr == 0
+
+ def make_reply(self, req):
+ ip = req.getlayer(IP)
+ dns = req.getlayer(DNS)
+ resp = IP(dst=ip.src, src=ip.dst)/UDP(dport=ip.sport,sport=ip.dport)
+ rdata = self.match.get(dns.qd.qname, self.joker)
+ resp /= DNS(id=dns.id, qr=1, qd=dns.qd,
+ an=DNSRR(rrname=dns.qd.qname, ttl=10, rdata=rdata))
+ return resp
+
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dot11.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dot11.py
new file mode 100644
index 00000000..417a470e
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/dot11.py
@@ -0,0 +1,560 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+Wireless LAN according to IEEE 802.11.
+"""
+
+import re,struct
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.plist import PacketList
+from scapy.layers.l2 import *
+
+
+try:
+ from Crypto.Cipher import ARC4
+except ImportError:
+ log_loading.info("Can't import python Crypto lib. Won't be able to decrypt WEP.")
+
+
+### Fields
+
+class Dot11AddrMACField(MACField):
+ def is_applicable(self, pkt):
+ return 1
+ def addfield(self, pkt, s, val):
+ if self.is_applicable(pkt):
+ return MACField.addfield(self, pkt, s, val)
+ else:
+ return s
+ def getfield(self, pkt, s):
+ if self.is_applicable(pkt):
+ return MACField.getfield(self, pkt, s)
+ else:
+ return s,None
+
+class Dot11Addr2MACField(Dot11AddrMACField):
+ def is_applicable(self, pkt):
+ if pkt.type == 1:
+ return pkt.subtype in [ 0xb, 0xa, 0xe, 0xf] # RTS, PS-Poll, CF-End, CF-End+CF-Ack
+ return 1
+
+class Dot11Addr3MACField(Dot11AddrMACField):
+ def is_applicable(self, pkt):
+ if pkt.type in [0,2]:
+ return 1
+ return 0
+
+class Dot11Addr4MACField(Dot11AddrMACField):
+ def is_applicable(self, pkt):
+ if pkt.type == 2:
+ if pkt.FCfield & 0x3 == 0x3: # To-DS and From-DS are set
+ return 1
+ return 0
+
+
+### Layers
+
+
+class PrismHeader(Packet):
+ """ iwpriv wlan0 monitor 3 """
+ name = "Prism header"
+ fields_desc = [ LEIntField("msgcode",68),
+ LEIntField("len",144),
+ StrFixedLenField("dev","",16),
+ LEIntField("hosttime_did",0),
+ LEShortField("hosttime_status",0),
+ LEShortField("hosttime_len",0),
+ LEIntField("hosttime",0),
+ LEIntField("mactime_did",0),
+ LEShortField("mactime_status",0),
+ LEShortField("mactime_len",0),
+ LEIntField("mactime",0),
+ LEIntField("channel_did",0),
+ LEShortField("channel_status",0),
+ LEShortField("channel_len",0),
+ LEIntField("channel",0),
+ LEIntField("rssi_did",0),
+ LEShortField("rssi_status",0),
+ LEShortField("rssi_len",0),
+ LEIntField("rssi",0),
+ LEIntField("sq_did",0),
+ LEShortField("sq_status",0),
+ LEShortField("sq_len",0),
+ LEIntField("sq",0),
+ LEIntField("signal_did",0),
+ LEShortField("signal_status",0),
+ LEShortField("signal_len",0),
+ LESignedIntField("signal",0),
+ LEIntField("noise_did",0),
+ LEShortField("noise_status",0),
+ LEShortField("noise_len",0),
+ LEIntField("noise",0),
+ LEIntField("rate_did",0),
+ LEShortField("rate_status",0),
+ LEShortField("rate_len",0),
+ LEIntField("rate",0),
+ LEIntField("istx_did",0),
+ LEShortField("istx_status",0),
+ LEShortField("istx_len",0),
+ LEIntField("istx",0),
+ LEIntField("frmlen_did",0),
+ LEShortField("frmlen_status",0),
+ LEShortField("frmlen_len",0),
+ LEIntField("frmlen",0),
+ ]
+ def answers(self, other):
+ if isinstance(other, PrismHeader):
+ return self.payload.answers(other.payload)
+ else:
+ return self.payload.answers(other)
+
+class RadioTap(Packet):
+ name = "RadioTap dummy"
+ fields_desc = [ ByteField('version', 0),
+ ByteField('pad', 0),
+ FieldLenField('len', None, 'notdecoded', '<H', adjust=lambda pkt,x:x+8),
+ FlagsField('present', None, -32, ['TSFT','Flags','Rate','Channel','FHSS','dBm_AntSignal',
+ 'dBm_AntNoise','Lock_Quality','TX_Attenuation','dB_TX_Attenuation',
+ 'dBm_TX_Power', 'Antenna', 'dB_AntSignal', 'dB_AntNoise',
+ 'b14', 'b15','b16','b17','b18','b19','b20','b21','b22','b23',
+ 'b24','b25','b26','b27','b28','b29','b30','Ext']),
+ StrLenField('notdecoded', "", length_from= lambda pkt:pkt.len-8) ]
+
+class PPI(Packet):
+ name = "Per-Packet Information header (partial)"
+ fields_desc = [ ByteField("version", 0),
+ ByteField("flags", 0),
+ FieldLenField("len", None, fmt="<H", length_of="fields", adjust=lambda pkt,x:x+8),
+ LEIntField("dlt", 0),
+ StrLenField("notdecoded", "", length_from = lambda pkt:pkt.len-8)
+ ]
+
+
+
+class Dot11SCField(LEShortField):
+ def is_applicable(self, pkt):
+ return pkt.type != 1 # control frame
+ def addfield(self, pkt, s, val):
+ if self.is_applicable(pkt):
+ return LEShortField.addfield(self, pkt, s, val)
+ else:
+ return s
+ def getfield(self, pkt, s):
+ if self.is_applicable(pkt):
+ return LEShortField.getfield(self, pkt, s)
+ else:
+ return s,None
+
+class Dot11(Packet):
+ name = "802.11"
+ fields_desc = [
+ BitField("subtype", 0, 4),
+ BitEnumField("type", 0, 2, ["Management", "Control", "Data", "Reserved"]),
+ BitField("proto", 0, 2),
+ FlagsField("FCfield", 0, 8, ["to-DS", "from-DS", "MF", "retry", "pw-mgt", "MD", "wep", "order"]),
+ ShortField("ID",0),
+ MACField("addr1", ETHER_ANY),
+ Dot11Addr2MACField("addr2", ETHER_ANY),
+ Dot11Addr3MACField("addr3", ETHER_ANY),
+ Dot11SCField("SC", 0),
+ Dot11Addr4MACField("addr4", ETHER_ANY)
+ ]
+ def mysummary(self):
+ return self.sprintf("802.11 %Dot11.type% %Dot11.subtype% %Dot11.addr2% > %Dot11.addr1%")
+ def guess_payload_class(self, payload):
+ if self.type == 0x02 and (self.subtype >= 0x08 and self.subtype <=0xF and self.subtype != 0xD):
+ return Dot11QoS
+ elif self.FCfield & 0x40:
+ return Dot11WEP
+ else:
+ return Packet.guess_payload_class(self, payload)
+ def answers(self, other):
+ if isinstance(other,Dot11):
+ if self.type == 0: # management
+ if self.addr1.lower() != other.addr2.lower(): # check resp DA w/ req SA
+ return 0
+ if (other.subtype,self.subtype) in [(0,1),(2,3),(4,5)]:
+ return 1
+ if self.subtype == other.subtype == 11: # auth
+ return self.payload.answers(other.payload)
+ elif self.type == 1: # control
+ return 0
+ elif self.type == 2: # data
+ return self.payload.answers(other.payload)
+ elif self.type == 3: # reserved
+ return 0
+ return 0
+ def unwep(self, key=None, warn=1):
+ if self.FCfield & 0x40 == 0:
+ if warn:
+ warning("No WEP to remove")
+ return
+ if isinstance(self.payload.payload, NoPayload):
+ if key or conf.wepkey:
+ self.payload.decrypt(key)
+ if isinstance(self.payload.payload, NoPayload):
+ if warn:
+ warning("Dot11 can't be decrypted. Check conf.wepkey.")
+ return
+ self.FCfield &= ~0x40
+ self.payload=self.payload.payload
+
+
+class Dot11QoS(Packet):
+ name = "802.11 QoS"
+ fields_desc = [ BitField("TID",None,4),
+ BitField("EOSP",None,1),
+ BitField("Ack Policy",None,2),
+ BitField("Reserved",None,1),
+ ByteField("TXOP",None) ]
+ def guess_payload_class(self, payload):
+ if isinstance(self.underlayer, Dot11):
+ if self.underlayer.FCfield & 0x40:
+ return Dot11WEP
+ return Packet.guess_payload_class(self, payload)
+
+
+capability_list = [ "res8", "res9", "short-slot", "res11",
+ "res12", "DSSS-OFDM", "res14", "res15",
+ "ESS", "IBSS", "CFP", "CFP-req",
+ "privacy", "short-preamble", "PBCC", "agility"]
+
+reason_code = {0:"reserved",1:"unspec", 2:"auth-expired",
+ 3:"deauth-ST-leaving",
+ 4:"inactivity", 5:"AP-full", 6:"class2-from-nonauth",
+ 7:"class3-from-nonass", 8:"disas-ST-leaving",
+ 9:"ST-not-auth"}
+
+status_code = {0:"success", 1:"failure", 10:"cannot-support-all-cap",
+ 11:"inexist-asso", 12:"asso-denied", 13:"algo-unsupported",
+ 14:"bad-seq-num", 15:"challenge-failure",
+ 16:"timeout", 17:"AP-full",18:"rate-unsupported" }
+
+class Dot11Beacon(Packet):
+ name = "802.11 Beacon"
+ fields_desc = [ LELongField("timestamp", 0),
+ LEShortField("beacon_interval", 0x0064),
+ FlagsField("cap", 0, 16, capability_list) ]
+
+
+class Dot11Elt(Packet):
+ name = "802.11 Information Element"
+ fields_desc = [ ByteEnumField("ID", 0, {0:"SSID", 1:"Rates", 2: "FHset", 3:"DSset", 4:"CFset", 5:"TIM", 6:"IBSSset", 16:"challenge",
+ 42:"ERPinfo", 46:"QoS Capability", 47:"ERPinfo", 48:"RSNinfo", 50:"ESRates",221:"vendor",68:"reserved"}),
+ FieldLenField("len", None, "info", "B"),
+ StrLenField("info", "", length_from=lambda x:x.len) ]
+ def mysummary(self):
+ if self.ID == 0:
+ return "SSID=%s"%repr(self.info),[Dot11]
+ else:
+ return ""
+
+class Dot11ATIM(Packet):
+ name = "802.11 ATIM"
+
+class Dot11Disas(Packet):
+ name = "802.11 Disassociation"
+ fields_desc = [ LEShortEnumField("reason", 1, reason_code) ]
+
+class Dot11AssoReq(Packet):
+ name = "802.11 Association Request"
+ fields_desc = [ FlagsField("cap", 0, 16, capability_list),
+ LEShortField("listen_interval", 0x00c8) ]
+
+
+class Dot11AssoResp(Packet):
+ name = "802.11 Association Response"
+ fields_desc = [ FlagsField("cap", 0, 16, capability_list),
+ LEShortField("status", 0),
+ LEShortField("AID", 0) ]
+
+class Dot11ReassoReq(Packet):
+ name = "802.11 Reassociation Request"
+ fields_desc = [ FlagsField("cap", 0, 16, capability_list),
+ LEShortField("listen_interval", 0x00c8),
+ MACField("current_AP", ETHER_ANY) ]
+
+
+class Dot11ReassoResp(Dot11AssoResp):
+ name = "802.11 Reassociation Response"
+
+class Dot11ProbeReq(Packet):
+ name = "802.11 Probe Request"
+
+class Dot11ProbeResp(Packet):
+ name = "802.11 Probe Response"
+ fields_desc = [ LELongField("timestamp", 0),
+ LEShortField("beacon_interval", 0x0064),
+ FlagsField("cap", 0, 16, capability_list) ]
+
+class Dot11Auth(Packet):
+ name = "802.11 Authentication"
+ fields_desc = [ LEShortEnumField("algo", 0, ["open", "sharedkey"]),
+ LEShortField("seqnum", 0),
+ LEShortEnumField("status", 0, status_code) ]
+ def answers(self, other):
+ if self.seqnum == other.seqnum+1:
+ return 1
+ return 0
+
+class Dot11Deauth(Packet):
+ name = "802.11 Deauthentication"
+ fields_desc = [ LEShortEnumField("reason", 1, reason_code) ]
+
+
+
+class Dot11WEP(Packet):
+ name = "802.11 WEP packet"
+ fields_desc = [ StrFixedLenField("iv", b"\0\0\0", 3),
+ ByteField("keyid", 0),
+ StrField("wepdata",None,remain=4),
+ IntField("icv",None) ]
+
+ def post_dissect(self, s):
+# self.icv, = struct.unpack("!I",self.wepdata[-4:])
+# self.wepdata = self.wepdata[:-4]
+ self.decrypt()
+
+ def build_payload(self):
+ if self.wepdata is None:
+ return Packet.build_payload(self)
+ return b""
+
+ def post_build(self, p, pay):
+ if self.wepdata is None:
+ key = conf.wepkey
+ if key:
+ if self.icv is None:
+ pay += struct.pack("<I",crc32(pay))
+ icv = b""
+ else:
+ icv = p[4:8]
+ c = ARC4.new(self.iv+key)
+ p = p[:4]+c.encrypt(pay)+icv
+ else:
+ warning("No WEP key set (conf.wepkey).. strange results expected..")
+ return p
+
+
+ def decrypt(self,key=None):
+ if key is None:
+ key = conf.wepkey
+ if key:
+ c = ARC4.new(self.iv+key)
+ self.add_payload(LLC(c.decrypt(self.wepdata)))
+
+
+bind_layers( PrismHeader, Dot11, )
+bind_layers( RadioTap, Dot11, )
+bind_layers( PPI, Dot11, dlt=105)
+bind_layers( Dot11, LLC, type=2)
+bind_layers( Dot11QoS, LLC, )
+bind_layers( Dot11, Dot11AssoReq, subtype=0, type=0)
+bind_layers( Dot11, Dot11AssoResp, subtype=1, type=0)
+bind_layers( Dot11, Dot11ReassoReq, subtype=2, type=0)
+bind_layers( Dot11, Dot11ReassoResp, subtype=3, type=0)
+bind_layers( Dot11, Dot11ProbeReq, subtype=4, type=0)
+bind_layers( Dot11, Dot11ProbeResp, subtype=5, type=0)
+bind_layers( Dot11, Dot11Beacon, subtype=8, type=0)
+bind_layers( Dot11, Dot11ATIM, subtype=9, type=0)
+bind_layers( Dot11, Dot11Disas, subtype=10, type=0)
+bind_layers( Dot11, Dot11Auth, subtype=11, type=0)
+bind_layers( Dot11, Dot11Deauth, subtype=12, type=0)
+bind_layers( Dot11Beacon, Dot11Elt, )
+bind_layers( Dot11AssoReq, Dot11Elt, )
+bind_layers( Dot11AssoResp, Dot11Elt, )
+bind_layers( Dot11ReassoReq, Dot11Elt, )
+bind_layers( Dot11ReassoResp, Dot11Elt, )
+bind_layers( Dot11ProbeReq, Dot11Elt, )
+bind_layers( Dot11ProbeResp, Dot11Elt, )
+bind_layers( Dot11Auth, Dot11Elt, )
+bind_layers( Dot11Elt, Dot11Elt, )
+
+
+conf.l2types.register(105, Dot11)
+conf.l2types.register_num2layer(801, Dot11)
+conf.l2types.register(119, PrismHeader)
+conf.l2types.register_num2layer(802, PrismHeader)
+conf.l2types.register(127, RadioTap)
+conf.l2types.register(0xc0, PPI)
+conf.l2types.register_num2layer(803, RadioTap)
+
+
+class WiFi_am(AnsweringMachine):
+ """Before using this, initialize "iffrom" and "ifto" interfaces:
+iwconfig iffrom mode monitor
+iwpriv orig_ifto hostapd 1
+ifconfig ifto up
+note: if ifto=wlan0ap then orig_ifto=wlan0
+note: ifto and iffrom must be set on the same channel
+ex:
+ifconfig eth1 up
+iwconfig eth1 mode monitor
+iwconfig eth1 channel 11
+iwpriv wlan0 hostapd 1
+ifconfig wlan0ap up
+iwconfig wlan0 channel 11
+iwconfig wlan0 essid dontexist
+iwconfig wlan0 mode managed
+"""
+ function_name = "airpwn"
+ filter = None
+
+ def parse_options(self, iffrom, ifto, replace, pattern="", ignorepattern=""):
+ self.iffrom = iffrom
+ self.ifto = ifto
+ ptrn = re.compile(pattern)
+ iptrn = re.compile(ignorepattern)
+
+ def is_request(self, pkt):
+ if not isinstance(pkt,Dot11):
+ return 0
+ if not pkt.FCfield & 1:
+ return 0
+ if not pkt.haslayer(TCP):
+ return 0
+ ip = pkt.getlayer(IP)
+ tcp = pkt.getlayer(TCP)
+ pay = str(tcp.payload)
+ if not self.ptrn.match(pay):
+ return 0
+ if self.iptrn.match(pay):
+ return 0
+
+ def make_reply(self, p):
+ ip = p.getlayer(IP)
+ tcp = p.getlayer(TCP)
+ pay = str(tcp.payload)
+ del(p.payload.payload.payload)
+ p.FCfield="from-DS"
+ p.addr1,p.addr2 = p.addr2,p.addr1
+ p /= IP(src=ip.dst,dst=ip.src)
+ p /= TCP(sport=tcp.dport, dport=tcp.sport,
+ seq=tcp.ack, ack=tcp.seq+len(pay),
+ flags="PA")
+ q = p.copy()
+ p /= self.replace
+ q.ID += 1
+ q.getlayer(TCP).flags="RA"
+ q.getlayer(TCP).seq+=len(replace)
+ return [p,q]
+
+ def print_reply(self):
+ print(p.sprintf("Sent %IP.src%:%IP.sport% > %IP.dst%:%TCP.dport%"))
+
+ def send_reply(self, reply):
+ sendp(reply, iface=self.ifto, **self.optsend)
+
+ def sniff(self):
+ sniff(iface=self.iffrom, **self.optsniff)
+
+
+
+plst=[]
+def get_toDS():
+ global plst
+ while 1:
+ p,=sniff(iface="eth1",count=1)
+ if not isinstance(p,Dot11):
+ continue
+ if p.FCfield & 1:
+ plst.append(p)
+ print(".")
+
+
+# if not ifto.endswith("ap"):
+# print("iwpriv %s hostapd 1" % ifto)
+# os.system("iwpriv %s hostapd 1" % ifto)
+# ifto += "ap"
+#
+# os.system("iwconfig %s mode monitor" % iffrom)
+#
+
+def airpwn(iffrom, ifto, replace, pattern="", ignorepattern=""):
+ """Before using this, initialize "iffrom" and "ifto" interfaces:
+iwconfig iffrom mode monitor
+iwpriv orig_ifto hostapd 1
+ifconfig ifto up
+note: if ifto=wlan0ap then orig_ifto=wlan0
+note: ifto and iffrom must be set on the same channel
+ex:
+ifconfig eth1 up
+iwconfig eth1 mode monitor
+iwconfig eth1 channel 11
+iwpriv wlan0 hostapd 1
+ifconfig wlan0ap up
+iwconfig wlan0 channel 11
+iwconfig wlan0 essid dontexist
+iwconfig wlan0 mode managed
+"""
+
+ ptrn = re.compile(pattern)
+ iptrn = re.compile(ignorepattern)
+ def do_airpwn(p, ifto=ifto, replace=replace, ptrn=ptrn, iptrn=iptrn):
+ if not isinstance(p,Dot11):
+ return
+ if not p.FCfield & 1:
+ return
+ if not p.haslayer(TCP):
+ return
+ ip = p.getlayer(IP)
+ tcp = p.getlayer(TCP)
+ pay = str(tcp.payload)
+# print "got tcp"
+ if not ptrn.match(pay):
+ return
+# print "match 1"
+ if iptrn.match(pay):
+ return
+# print "match 2"
+ del(p.payload.payload.payload)
+ p.FCfield="from-DS"
+ p.addr1,p.addr2 = p.addr2,p.addr1
+ q = p.copy()
+ p /= IP(src=ip.dst,dst=ip.src)
+ p /= TCP(sport=tcp.dport, dport=tcp.sport,
+ seq=tcp.ack, ack=tcp.seq+len(pay),
+ flags="PA")
+ q = p.copy()
+ p /= replace
+ q.ID += 1
+ q.getlayer(TCP).flags="RA"
+ q.getlayer(TCP).seq+=len(replace)
+
+ sendp([p,q], iface=ifto, verbose=0)
+# print "send",repr(p)
+# print "send",repr(q)
+ print(p.sprintf("Sent %IP.src%:%IP.sport% > %IP.dst%:%TCP.dport%"))
+
+ sniff(iface=iffrom,prn=do_airpwn)
+
+
+
+conf.stats_dot11_protocols += [Dot11WEP, Dot11Beacon, ]
+
+
+
+
+
+class Dot11PacketList(PacketList):
+ def __init__(self, res=None, name="Dot11List", stats=None):
+ if stats is None:
+ stats = conf.stats_dot11_protocols
+
+ PacketList.__init__(self, res, name, stats)
+ def toEthernet(self):
+ #data = map(lambda x:x.getlayer(Dot11), filter(lambda x : x.haslayer(Dot11) and x.type == 2, self.res))
+ data = [ x.getlayer(Dot11) for x in self.res if x.haslayer(Dot11) and x.type == 2 ]
+ r2 = []
+ for p in data:
+ q = p.copy()
+ q.unwep()
+ r2.append(Ether()/q.payload.payload.payload) #Dot11/LLC/SNAP/IP
+ return PacketList(r2,name="Ether from %s"%self.listname)
+
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/gprs.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/gprs.py
new file mode 100644
index 00000000..31a931fe
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/gprs.py
@@ -0,0 +1,21 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+GPRS (General Packet Radio Service) for mobile data communication.
+"""
+
+from scapy.fields import *
+from scapy.packet import *
+from scapy.layers.inet import IP
+
+class GPRS(Packet):
+ name = "GPRSdummy"
+ fields_desc = [
+ StrStopField("dummy","","\x65\x00\x00",1)
+ ]
+
+
+bind_layers( GPRS, IP, )
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/hsrp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/hsrp.py
new file mode 100644
index 00000000..7193b97e
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/hsrp.py
@@ -0,0 +1,79 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+#############################################################################
+## ##
+## hsrp.py --- HSRP protocol support for Scapy ##
+## ##
+## Copyright (C) 2010 Mathieu RENARD mathieu.renard(at)gmail.com ##
+## ##
+## This program is free software; you can redistribute it and/or modify it ##
+## under the terms of the GNU General Public License version 2 as ##
+## published by the Free Software Foundation; version 2. ##
+## ##
+## This program is distributed in the hope that it will be useful, but ##
+## WITHOUT ANY WARRANTY; without even the implied warranty of ##
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ##
+## General Public License for more details. ##
+## ##
+#############################################################################
+## HSRP Version 1
+## Ref. RFC 2281
+## HSRP Version 2
+## Ref. http://www.smartnetworks.jp/2006/02/hsrp_8_hsrp_version_2.html
+##
+## $Log: hsrp.py,v $
+## Revision 0.2 2011/05/01 15:23:34 mrenard
+## Cleanup code
+
+"""
+HSRP (Hot Standby Router Protocol): proprietary redundancy protocol for Cisco routers.
+"""
+
+from scapy.fields import *
+from scapy.packet import *
+from scapy.layers.inet import UDP
+
+
+class HSRP(Packet):
+ name = "HSRP"
+ fields_desc = [
+ ByteField("version", 0),
+ ByteEnumField("opcode", 0, {0: "Hello", 1: "Coup", 2: "Resign", 3: "Advertise"}),
+ ByteEnumField("state", 16, {0: "Initial", 1: "Learn", 2: "Listen", 4: "Speak", 8: "Standby", 16: "Active"}),
+ ByteField("hellotime", 3),
+ ByteField("holdtime", 10),
+ ByteField("priority", 120),
+ ByteField("group", 1),
+ ByteField("reserved", 0),
+ StrFixedLenField("auth", "cisco" + "\00" * 3, 8),
+ IPField("virtualIP", "192.168.1.1")]
+
+ def guess_payload_class(self, payload):
+ if self.underlayer.len > 28:
+ return HSRPmd5
+ else:
+ return Packet.guess_payload_class(self, payload)
+
+
+class HSRPmd5(Packet):
+ name = "HSRP MD5 Authentication"
+ fields_desc = [
+ ByteEnumField("type", 4, {4: "MD5 authentication"}),
+ ByteField("len", None),
+ ByteEnumField("algo", 0, {1: "MD5"}),
+ ByteField("padding", 0x00),
+ XShortField("flags", 0x00),
+ IPField("sourceip", None),
+ XIntField("keyid", 0x00),
+ StrFixedLenField("authdigest", "\00" * 16, 16)]
+
+ def post_build(self, p, pay):
+ if self.len is None and pay:
+ l = len(pay)
+ p = p[:1] + hex(l)[30:] + p[30:]
+ return p
+
+bind_layers(UDP, HSRP, dport=1985, sport=1985)
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/inet.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/inet.py
new file mode 100644
index 00000000..04b99e89
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/inet.py
@@ -0,0 +1,1569 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+IPv4 (Internet Protocol v4).
+"""
+
+import os,time,struct,re,socket,types
+from select import select
+from collections import defaultdict
+from scapy.utils import checksum
+from scapy.layers.l2 import *
+from scapy.config import conf
+from scapy.fields import *
+from scapy.packet import *
+from scapy.volatile import *
+from scapy.sendrecv import sr,sr1,srp1
+from scapy.plist import PacketList,SndRcvList
+from scapy.automaton import Automaton,ATMT
+
+import scapy.as_resolvers
+
+
+####################
+## IP Tools class ##
+####################
+
+class IPTools:
+ """Add more powers to a class that have a "src" attribute."""
+ def whois(self):
+ os.system("whois %s" % self.src)
+ def ottl(self):
+ t = [32,64,128,255]+[self.ttl]
+ t.sort()
+ return t[t.index(self.ttl)+1]
+ def hops(self):
+ return self.ottl()-self.ttl-1
+
+
+_ip_options_names = { 0: "end_of_list",
+ 1: "nop",
+ 2: "security",
+ 3: "loose_source_route",
+ 4: "timestamp",
+ 5: "extended_security",
+ 6: "commercial_security",
+ 7: "record_route",
+ 8: "stream_id",
+ 9: "strict_source_route",
+ 10: "experimental_measurement",
+ 11: "mtu_probe",
+ 12: "mtu_reply",
+ 13: "flow_control",
+ 14: "access_control",
+ 15: "encode",
+ 16: "imi_traffic_descriptor",
+ 17: "extended_IP",
+ 18: "traceroute",
+ 19: "address_extension",
+ 20: "router_alert",
+ 21: "selective_directed_broadcast_mode",
+ 23: "dynamic_packet_state",
+ 24: "upstream_multicast_packet",
+ 25: "quick_start",
+ 30: "rfc4727_experiment",
+ }
+
+
+class _IPOption_HDR(Packet):
+ fields_desc = [ BitField("copy_flag",0, 1),
+ BitEnumField("optclass",0,2,{0:"control",2:"debug"}),
+ BitEnumField("option",0,5, _ip_options_names) ]
+
+class IPOption(Packet):
+ name = "IP Option"
+ fields_desc = [ _IPOption_HDR,
+ FieldLenField("length", None, fmt="B", # Only option 0 and 1 have no length and value
+ length_of="value", adjust=lambda pkt,l:l+2),
+ StrLenField("value", "",length_from=lambda pkt:pkt.length-2) ]
+
+ def extract_padding(self, p):
+ return b"",p
+
+ registered_ip_options = {}
+ @classmethod
+ def register_variant(cls):
+ cls.registered_ip_options[cls.option.default] = cls
+ @classmethod
+ def dispatch_hook(cls, pkt=None, *args, **kargs):
+ if pkt:
+ opt = pkt[0]&0x1f
+ if opt in cls.registered_ip_options:
+ return cls.registered_ip_options[opt]
+ return cls
+
+class IPOption_EOL(IPOption):
+ name = "IP Option End of Options List"
+ option = 0
+ fields_desc = [ _IPOption_HDR ]
+
+
+class IPOption_NOP(IPOption):
+ name = "IP Option No Operation"
+ option=1
+ fields_desc = [ _IPOption_HDR ]
+
+class IPOption_Security(IPOption):
+ name = "IP Option Security"
+ copy_flag = 1
+ option = 2
+ fields_desc = [ _IPOption_HDR,
+ ByteField("length", 11),
+ ShortField("security",0),
+ ShortField("compartment",0),
+ ShortField("handling_restrictions",0),
+ StrFixedLenField("transmission_control_code","xxx",3),
+ ]
+
+class IPOption_LSRR(IPOption):
+ name = "IP Option Loose Source and Record Route"
+ copy_flag = 1
+ option = 3
+ fields_desc = [ _IPOption_HDR,
+ FieldLenField("length", None, fmt="B",
+ length_of="routers", adjust=lambda pkt,l:l+3),
+ ByteField("pointer",4), # 4 is first IP
+ FieldListField("routers",[],IPField("","0.0.0.0"),
+ length_from=lambda pkt:pkt.length-3)
+ ]
+ def get_current_router(self):
+ return self.routers[self.pointer//4-1]
+
+class IPOption_RR(IPOption_LSRR):
+ name = "IP Option Record Route"
+ option = 7
+
+class IPOption_SSRR(IPOption_LSRR):
+ name = "IP Option Strict Source and Record Route"
+ option = 9
+
+class IPOption_Stream_Id(IPOption):
+ name = "IP Option Stream ID"
+ option = 8
+ fields_desc = [ _IPOption_HDR,
+ ByteField("length", 4),
+ ShortField("security",0), ]
+
+class IPOption_MTU_Probe(IPOption):
+ name = "IP Option MTU Probe"
+ option = 11
+ fields_desc = [ _IPOption_HDR,
+ ByteField("length", 4),
+ ShortField("mtu",0), ]
+
+class IPOption_MTU_Reply(IPOption_MTU_Probe):
+ name = "IP Option MTU Reply"
+ option = 12
+
+class IPOption_Traceroute(IPOption):
+ name = "IP Option Traceroute"
+ copy_flag = 1
+ option = 18
+ fields_desc = [ _IPOption_HDR,
+ ByteField("length", 12),
+ ShortField("id",0),
+ ShortField("outbound_hops",0),
+ ShortField("return_hops",0),
+ IPField("originator_ip","0.0.0.0") ]
+
+class IPOption_Address_Extension(IPOption):
+ name = "IP Option Address Extension"
+ copy_flag = 1
+ option = 19
+ fields_desc = [ _IPOption_HDR,
+ ByteField("length", 10),
+ IPField("src_ext","0.0.0.0"),
+ IPField("dst_ext","0.0.0.0") ]
+
+class IPOption_Router_Alert(IPOption):
+ name = "IP Option Router Alert"
+ copy_flag = 1
+ option = 20
+ fields_desc = [ _IPOption_HDR,
+ ByteField("length", 4),
+ ShortEnumField("alert",0, {0:"router_shall_examine_packet"}), ]
+
+
+class IPOption_SDBM(IPOption):
+ name = "IP Option Selective Directed Broadcast Mode"
+ copy_flag = 1
+ option = 21
+ fields_desc = [ _IPOption_HDR,
+ FieldLenField("length", None, fmt="B",
+ length_of="addresses", adjust=lambda pkt,l:l+2),
+ FieldListField("addresses",[],IPField("","0.0.0.0"),
+ length_from=lambda pkt:pkt.length-2)
+ ]
+
+
+
+TCPOptions = (
+ { 0 : ("EOL",None),
+ 1 : ("NOP",None),
+ 2 : ("MSS","!H"),
+ 3 : ("WScale","!B"),
+ 4 : ("SAckOK",None),
+ 5 : ("SAck","!"),
+ 8 : ("Timestamp","!II"),
+ 14 : ("AltChkSum","!BH"),
+ 15 : ("AltChkSumOpt",None),
+ 25 : ("Mood","!p")
+ },
+ { "EOL":0,
+ "NOP":1,
+ "MSS":2,
+ "WScale":3,
+ "SAckOK":4,
+ "SAck":5,
+ "Timestamp":8,
+ "AltChkSum":14,
+ "AltChkSumOpt":15,
+ "Mood":25
+ } )
+
+class TCPOptionsField(StrField):
+ islist=1
+ def getfield(self, pkt, s):
+ opsz = (pkt.dataofs-5)*4
+ if opsz < 0:
+ warning("bad dataofs (%i). Assuming dataofs=5"%pkt.dataofs)
+ opsz = 0
+ return s[opsz:],self.m2i(pkt,s[:opsz])
+ def m2i(self, pkt, x):
+ opt = []
+ while x:
+ onum = x[0]
+ if onum == 0:
+ opt.append(("EOL",None))
+ x=x[1:]
+ break
+ if onum == 1:
+ opt.append(("NOP",None))
+ x=x[1:]
+ continue
+ olen = x[1]
+ if olen < 2:
+ warning("Malformed TCP option (announced length is %i)" % olen)
+ olen = 2
+ oval = x[2:olen]
+ if onum in TCPOptions[0]:
+ oname, ofmt = TCPOptions[0][onum]
+ if onum == 5: #SAck
+ ofmt += "%iI" % (len(oval)//4)
+ if ofmt and struct.calcsize(ofmt) == len(oval):
+ oval = struct.unpack(ofmt, oval)
+ if len(oval) == 1:
+ oval = oval[0]
+ opt.append((oname, oval))
+ else:
+ opt.append((onum, oval))
+ x = x[olen:]
+ return opt
+
+ def i2m(self, pkt, x):
+ opt = b""
+ for oname,oval in x:
+ if type(oname) is str:
+ if oname == "NOP":
+ opt += b"\x01"
+ continue
+ elif oname == "EOL":
+ opt += b"\x00"
+ continue
+ elif oname in TCPOptions[1]:
+ onum = TCPOptions[1][oname]
+ ofmt = TCPOptions[0][onum][1]
+ if onum == 5: #SAck
+ ofmt += b"%iI" % len(oval)
+ if ofmt is not None and (type(oval) is not str or "s" in ofmt):
+ if type(oval) is not tuple:
+ oval = (oval,)
+ oval = struct.pack(ofmt, *oval)
+ else:
+ warning("option [%s] unknown. Skipped."%oname)
+ continue
+ else:
+ onum = oname
+ if type(oval) is not str:
+ warning("option [%i] is not string."%onum)
+ continue
+ opt += bytes([(onum), (2+len(oval))]) + oval
+ return opt+b"\x00"*(3-((len(opt)+3)%4))
+ def randval(self):
+ return [] # XXX
+
+
+class ICMPTimeStampField(IntField):
+ re_hmsm = re.compile("([0-2]?[0-9])[Hh:](([0-5]?[0-9])([Mm:]([0-5]?[0-9])([sS:.]([0-9]{0,3}))?)?)?$")
+ def i2repr(self, pkt, val):
+ if val is None:
+ return "--"
+ else:
+ sec, milli = divmod(val, 1000)
+ min, sec = divmod(sec, 60)
+ hour, min = divmod(min, 60)
+ return "%d:%d:%d.%d" %(hour, min, sec, int(milli))
+ def any2i(self, pkt, val):
+ if type(val) is str:
+ hmsms = self.re_hmsm.match(val)
+ if hmsms:
+ h,_,m,_,s,_,ms = hmsms = hmsms.groups()
+ ms = int(((ms or "")+"000")[:3])
+ val = ((int(h)*60+int(m or 0))*60+int(s or 0))*1000+ms
+ else:
+ val = 0
+ elif val is None:
+ val = int((time.time()%(24*60*60))*1000)
+ return val
+
+
+class IP(Packet, IPTools):
+ name = "IP"
+ fields_desc = [ BitField("version" , 4 , 4),
+ BitField("ihl", None, 4),
+ XByteField("tos", 0),
+ ShortField("len", None),
+ ShortField("id", 1),
+ FlagsField("flags", 0, 3, ["MF","DF","evil"]),
+ BitField("frag", 0, 13),
+ ByteField("ttl", 64),
+ ByteEnumField("proto", 0, IP_PROTOS),
+ XShortField("chksum", None),
+ #IPField("src", "127.0.0.1"),
+ #Emph(SourceIPField("src","dst")),
+ #Emph(IPField("dst", "127.0.0.1")),
+
+ Emph(IPField("src", "16.0.0.1")),
+ Emph(IPField("dst", "48.0.0.1")),
+ PacketListField("options", [], IPOption, length_from=lambda p:p.ihl*4-20) ]
+ def post_build(self, p, pay):
+ ihl = self.ihl
+ p += b"\0"*((-len(p))%4) # pad IP options if needed
+ if ihl is None:
+ ihl = len(p)//4
+ p = bytes([((self.version&0xf)<<4) | ihl&0x0f])+p[1:]
+ if self.len is None:
+ l = len(p)+len(pay)
+ p = p[:2]+struct.pack("!H", l)+p[4:]
+ if self.chksum is None:
+ ck = checksum(p)
+ p = p[:10]+bytes([ck>>8])+bytes([ck&0xff])+p[12:]
+ return p+pay
+
+ def extract_padding(self, s):
+ l = self.len - (self.ihl << 2)
+ return s[:l],s[l:]
+
+ def send(self, s, slp=0):
+ for p in self:
+ try:
+ s.sendto(bytes(p), (p.dst,0))
+ except socket.error as msg:
+ log_runtime.error(msg)
+ if slp:
+ time.sleep(slp)
+ def route(self):
+ dst = self.dst
+ if isinstance(dst,Gen):
+ dst = next(iter(dst))
+ return conf.route.route(dst)
+ def hashret(self):
+ if ( (self.proto == socket.IPPROTO_ICMP)
+ and (isinstance(self.payload, ICMP))
+ and (self.payload.type in [3,4,5,11,12]) ):
+ return self.payload.payload.hashret()
+ else:
+ if conf.checkIPsrc and conf.checkIPaddr:
+ return strxor(inet_aton(self.src),inet_aton(self.dst))+struct.pack("B",self.proto)+self.payload.hashret()
+ else:
+ return struct.pack("B", self.proto)+self.payload.hashret()
+ def answers(self, other):
+ if not isinstance(other,IP):
+ return 0
+ if conf.checkIPaddr and (self.dst != other.src):
+ return 0
+ if ( (self.proto == socket.IPPROTO_ICMP) and
+ (isinstance(self.payload, ICMP)) and
+ (self.payload.type in [3,4,5,11,12]) ):
+ # ICMP error message
+ return self.payload.payload.answers(other)
+
+ else:
+ if ( (conf.checkIPaddr and (self.src != other.dst)) or
+ (self.proto != other.proto) ):
+ return 0
+ return self.payload.answers(other.payload)
+ def mysummary(self):
+ s = self.sprintf("%IP.src% > %IP.dst% %IP.proto%")
+ if self.frag:
+ s += " frag:%i" % self.frag
+ return s
+
+ def fragment(self, fragsize=1480):
+ """Fragment IP datagrams"""
+ fragsize = (fragsize+7)//8*8
+ lst = []
+ fnb = 0
+ fl = self
+ while fl.underlayer is not None:
+ fnb += 1
+ fl = fl.underlayer
+
+ for p in fl:
+ s = bytes(p[fnb].payload)
+ nb = (len(s)+fragsize-1)//fragsize
+ for i in range(nb):
+ q = p.copy()
+ del(q[fnb].payload)
+ del(q[fnb].chksum)
+ del(q[fnb].len)
+ if i == nb-1:
+ q[IP].flags &= ~1
+ else:
+ q[IP].flags |= 1
+ q[IP].frag = i*fragsize//8
+ r = conf.raw_layer(load=s[i*fragsize:(i+1)*fragsize])
+ r.overload_fields = p[IP].payload.overload_fields.copy()
+ q.add_payload(r)
+ lst.append(q)
+ return lst
+
+
+class TCP(Packet):
+ name = "TCP"
+ fields_desc = [ ShortEnumField("sport", 20, TCP_SERVICES),
+ ShortEnumField("dport", 80, TCP_SERVICES),
+ IntField("seq", 0),
+ IntField("ack", 0),
+ BitField("dataofs", None, 4),
+ BitField("reserved", 0, 4),
+ FlagsField("flags", 0x2, 8, "FSRPAUEC"),
+ ShortField("window", 8192),
+ XShortField("chksum", None),
+ ShortField("urgptr", 0),
+ TCPOptionsField("options", {}) ]
+ def post_build(self, p, pay):
+ p += pay
+ dataofs = self.dataofs
+ if dataofs is None:
+ dataofs = 5+((len(self.get_field("options").i2m(self,self.options))+3)//4)
+ p = p[:12]+bytes([(dataofs << 4) | (p[12])&0x0f])+p[13:]
+ if self.chksum is None:
+ if isinstance(self.underlayer, IP):
+ if self.underlayer.len is not None:
+ ln = self.underlayer.len-20
+ else:
+ ln = len(p)
+ psdhdr = struct.pack("!4s4sHH",
+ inet_aton(self.underlayer.src),
+ inet_aton(self.underlayer.dst),
+ self.underlayer.proto,
+ ln)
+ ck=checksum(psdhdr+p)
+ p = p[:16]+struct.pack("!H", ck)+p[18:]
+ elif conf.ipv6_enabled and isinstance(self.underlayer, scapy.layers.inet6.IPv6) or isinstance(self.underlayer, scapy.layers.inet6._IPv6ExtHdr):
+ ck = scapy.layers.inet6.in6_chksum(socket.IPPROTO_TCP, self.underlayer, p)
+ p = p[:16]+struct.pack("!H", ck)+p[18:]
+ else:
+ warning("No IP underlayer to compute checksum. Leaving null.")
+ return p
+ def hashret(self):
+ if conf.checkIPsrc:
+ return struct.pack("H",self.sport ^ self.dport)+self.payload.hashret()
+ else:
+ return self.payload.hashret()
+ def answers(self, other):
+ if not isinstance(other, TCP):
+ return 0
+ if conf.checkIPsrc:
+ if not ((self.sport == other.dport) and
+ (self.dport == other.sport)):
+ return 0
+ if (abs(other.seq-self.ack) > 2+len(other.payload)):
+ return 0
+ return 1
+ def mysummary(self):
+ if isinstance(self.underlayer, IP):
+ return self.underlayer.sprintf("TCP %IP.src%:%TCP.sport% > %IP.dst%:%TCP.dport% %TCP.flags%")
+ elif conf.ipv6_enabled and isinstance(self.underlayer, scapy.layers.inet6.IPv6):
+ return self.underlayer.sprintf("TCP %IPv6.src%:%TCP.sport% > %IPv6.dst%:%TCP.dport% %TCP.flags%")
+ else:
+ return self.sprintf("TCP %TCP.sport% > %TCP.dport% %TCP.flags%")
+
+class UDP(Packet):
+ name = "UDP"
+ fields_desc = [ ShortEnumField("sport", 53, UDP_SERVICES),
+ ShortEnumField("dport", 53, UDP_SERVICES),
+ ShortField("len", None),
+ XShortField("chksum", None), ]
+ def post_build(self, p, pay):
+ p += pay
+ l = self.len
+ if l is None:
+ l = len(p)
+ p = p[:4]+struct.pack("!H",l)+p[6:]
+ if self.chksum is None:
+ if isinstance(self.underlayer, IP):
+ if self.underlayer.len is not None:
+ ln = self.underlayer.len-20
+ else:
+ ln = len(p)
+ psdhdr = struct.pack("!4s4sHH",
+ inet_aton(self.underlayer.src),
+ inet_aton(self.underlayer.dst),
+ self.underlayer.proto,
+ ln)
+ ck=checksum(psdhdr+p)
+ p = p[:6]+struct.pack("!H", ck)+p[8:]
+ elif isinstance(self.underlayer, scapy.layers.inet6.IPv6) or isinstance(self.underlayer, scapy.layers.inet6._IPv6ExtHdr):
+ ck = scapy.layers.inet6.in6_chksum(socket.IPPROTO_UDP, self.underlayer, p)
+ p = p[:6]+struct.pack("!H", ck)+p[8:]
+ else:
+ warning("No IP underlayer to compute checksum. Leaving null.")
+ return p
+ def extract_padding(self, s):
+ l = self.len - 8
+ return s[:l],s[l:]
+ def hashret(self):
+ return self.payload.hashret()
+ def answers(self, other):
+ if not isinstance(other, UDP):
+ return 0
+ if conf.checkIPsrc:
+ if self.dport != other.sport:
+ return 0
+ return self.payload.answers(other.payload)
+ def mysummary(self):
+ if isinstance(self.underlayer, IP):
+ return self.underlayer.sprintf("UDP %IP.src%:%UDP.sport% > %IP.dst%:%UDP.dport%")
+ elif isinstance(self.underlayer, scapy.layers.inet6.IPv6):
+ return self.underlayer.sprintf("UDP %IPv6.src%:%UDP.sport% > %IPv6.dst%:%UDP.dport%")
+ else:
+ return self.sprintf("UDP %UDP.sport% > %UDP.dport%")
+
+icmptypes = { 0 : "echo-reply",
+ 3 : "dest-unreach",
+ 4 : "source-quench",
+ 5 : "redirect",
+ 8 : "echo-request",
+ 9 : "router-advertisement",
+ 10 : "router-solicitation",
+ 11 : "time-exceeded",
+ 12 : "parameter-problem",
+ 13 : "timestamp-request",
+ 14 : "timestamp-reply",
+ 15 : "information-request",
+ 16 : "information-response",
+ 17 : "address-mask-request",
+ 18 : "address-mask-reply" }
+
+icmpcodes = { 3 : { 0 : "network-unreachable",
+ 1 : "host-unreachable",
+ 2 : "protocol-unreachable",
+ 3 : "port-unreachable",
+ 4 : "fragmentation-needed",
+ 5 : "source-route-failed",
+ 6 : "network-unknown",
+ 7 : "host-unknown",
+ 9 : "network-prohibited",
+ 10 : "host-prohibited",
+ 11 : "TOS-network-unreachable",
+ 12 : "TOS-host-unreachable",
+ 13 : "communication-prohibited",
+ 14 : "host-precedence-violation",
+ 15 : "precedence-cutoff", },
+ 5 : { 0 : "network-redirect",
+ 1 : "host-redirect",
+ 2 : "TOS-network-redirect",
+ 3 : "TOS-host-redirect", },
+ 11 : { 0 : "ttl-zero-during-transit",
+ 1 : "ttl-zero-during-reassembly", },
+ 12 : { 0 : "ip-header-bad",
+ 1 : "required-option-missing", }, }
+
+
+
+
+class ICMP(Packet):
+ name = "ICMP"
+ fields_desc = [ ByteEnumField("type",8, icmptypes),
+ MultiEnumField("code",0, icmpcodes, depends_on=lambda pkt:pkt.type,fmt="B"),
+ XShortField("chksum", None),
+ ConditionalField(XShortField("id",0), lambda pkt:pkt.type in [0,8,13,14,15,16,17,18]),
+ ConditionalField(XShortField("seq",0), lambda pkt:pkt.type in [0,8,13,14,15,16,17,18]),
+ ConditionalField(ICMPTimeStampField("ts_ori", None), lambda pkt:pkt.type in [13,14]),
+ ConditionalField(ICMPTimeStampField("ts_rx", None), lambda pkt:pkt.type in [13,14]),
+ ConditionalField(ICMPTimeStampField("ts_tx", None), lambda pkt:pkt.type in [13,14]),
+ ConditionalField(IPField("gw","0.0.0.0"), lambda pkt:pkt.type==5),
+ ConditionalField(ByteField("ptr",0), lambda pkt:pkt.type==12),
+ ConditionalField(X3BytesField("reserved",0), lambda pkt:pkt.type==12),
+ ConditionalField(IPField("addr_mask","0.0.0.0"), lambda pkt:pkt.type in [17,18]),
+ ConditionalField(IntField("unused",0), lambda pkt:pkt.type not in [0,5,8,12,13,14,15,16,17,18]),
+
+ ]
+ def post_build(self, p, pay):
+ p += pay
+ if self.chksum is None:
+ ck = checksum(p)
+ p = p[:2]+bytes([ck>>8, ck&0xff])+p[4:]
+ return p
+
+ def hashret(self):
+ if self.type in [0,8,13,14,15,16,17,18]:
+ return struct.pack("HH",self.id,self.seq)+self.payload.hashret()
+ return self.payload.hashret()
+ def answers(self, other):
+ if not isinstance(other,ICMP):
+ return 0
+ if ( (other.type,self.type) in [(8,0),(13,14),(15,16),(17,18)] and
+ self.id == other.id and
+ self.seq == other.seq ):
+ return 1
+ return 0
+
+ def guess_payload_class(self, payload):
+ if self.type in [3,4,5,11,12]:
+ return IPerror
+ else:
+ return None
+ def mysummary(self):
+ if isinstance(self.underlayer, IP):
+ return self.underlayer.sprintf("ICMP %IP.src% > %IP.dst% %ICMP.type% %ICMP.code%")
+ else:
+ return self.sprintf("ICMP %ICMP.type% %ICMP.code%")
+
+
+
+
+
+class IPerror(IP):
+ name = "IP in ICMP"
+ def answers(self, other):
+ if not isinstance(other, IP):
+ return 0
+ if not ( ((conf.checkIPsrc == 0) or (self.dst == other.dst)) and
+ (self.src == other.src) and
+ ( ((conf.checkIPID == 0)
+ or (self.id == other.id)
+ or (conf.checkIPID == 1 and self.id == socket.htons(other.id)))) and
+ (self.proto == other.proto) ):
+ return 0
+ return self.payload.answers(other.payload)
+ def mysummary(self):
+ return Packet.mysummary(self)
+
+
+class TCPerror(TCP):
+ fields_desc = [ ShortEnumField("sport", 20, TCP_SERVICES),
+ ShortEnumField("dport", 80, TCP_SERVICES),
+ IntField("seq", 0) ]
+ name = "TCP in ICMP"
+ def post_build(self, p, pay):
+ p += pay
+ return p
+ def answers(self, other):
+ if not isinstance(other, TCP):
+ return 0
+ if conf.checkIPsrc:
+ if not ((self.sport == other.sport) and
+ (self.dport == other.dport)):
+ return 0
+ if conf.check_TCPerror_seqack:
+ if self.seq is not None:
+ if self.seq != other.seq:
+ return 0
+ if self.ack is not None:
+ if self.ack != other.ack:
+ return 0
+ return 1
+ def mysummary(self):
+ return Packet.mysummary(self)
+
+
+class UDPerror(UDP):
+ name = "UDP in ICMP"
+ def answers(self, other):
+ if not isinstance(other, UDP):
+ return 0
+ if conf.checkIPsrc:
+ if not ((self.sport == other.sport) and
+ (self.dport == other.dport)):
+ return 0
+ return 1
+ def mysummary(self):
+ return Packet.mysummary(self)
+
+
+
+class ICMPerror(ICMP):
+ name = "ICMP in ICMP"
+ def answers(self, other):
+ if not isinstance(other,ICMP):
+ return 0
+ if not ((self.type == other.type) and
+ (self.code == other.code)):
+ return 0
+ if self.code in [0,8,13,14,17,18]:
+ if (self.id == other.id and
+ self.seq == other.seq):
+ return 1
+ else:
+ return 0
+ else:
+ return 1
+ def mysummary(self):
+ return Packet.mysummary(self)
+
+bind_layers( Ether, IP, type=2048)
+bind_layers( CookedLinux, IP, proto=2048)
+bind_layers( GRE, IP, proto=2048)
+bind_layers( SNAP, IP, code=2048)
+bind_layers( IPerror, IPerror, frag=0, proto=4)
+bind_layers( IPerror, ICMPerror, frag=0, proto=1)
+bind_layers( IPerror, TCPerror, frag=0, proto=6)
+bind_layers( IPerror, UDPerror, frag=0, proto=17)
+bind_layers( IP, IP, frag=0, proto=4)
+bind_layers( IP, ICMP, frag=0, proto=1)
+bind_layers( IP, TCP, frag=0, proto=6)
+bind_layers( IP, UDP, frag=0, proto=17)
+bind_layers( IP, GRE, frag=0, proto=47)
+
+conf.l2types.register(101, IP)
+conf.l2types.register_num2layer(12, IP)
+
+conf.l3types.register(ETH_P_IP, IP)
+conf.l3types.register_num2layer(ETH_P_ALL, IP)
+
+
+conf.neighbor.register_l3(Ether, IP, lambda l2,l3: getmacbyip(l3.dst))
+conf.neighbor.register_l3(Dot3, IP, lambda l2,l3: getmacbyip(l3.dst))
+
+
+###################
+## Fragmentation ##
+###################
+
+@conf.commands.register
+def fragment(pkt, fragsize=1480):
+ """Fragment a big IP datagram"""
+ fragsize = (fragsize+7)//8*8
+ lst = []
+ for p in pkt:
+ s = bytes(p[IP].payload)
+ nb = (len(s)+fragsize-1)//fragsize
+ for i in range(nb):
+ q = p.copy()
+ del(q[IP].payload)
+ del(q[IP].chksum)
+ del(q[IP].len)
+ if i == nb-1:
+ q[IP].flags &= ~1
+ else:
+ q[IP].flags |= 1
+ q[IP].frag = i*fragsize//8
+ r = conf.raw_layer(load=s[i*fragsize:(i+1)*fragsize])
+ r.overload_fields = p[IP].payload.overload_fields.copy()
+ q.add_payload(r)
+ lst.append(q)
+ return lst
+
+def overlap_frag(p, overlap, fragsize=8, overlap_fragsize=None):
+ if overlap_fragsize is None:
+ overlap_fragsize = fragsize
+ q = p.copy()
+ del(q[IP].payload)
+ q[IP].add_payload(overlap)
+
+ qfrag = fragment(q, overlap_fragsize)
+ qfrag[-1][IP].flags |= 1
+ return qfrag+fragment(p, fragsize)
+
+@conf.commands.register
+def defrag(plist):
+ """defrag(plist) -> ([not fragmented], [defragmented],
+ [ [bad fragments], [bad fragments], ... ])"""
+ frags = defaultdict(PacketList)
+ nofrag = PacketList()
+ for p in plist:
+ ip = p[IP]
+ if IP not in p:
+ nofrag.append(p)
+ continue
+ if ip.frag == 0 and ip.flags & 1 == 0:
+ nofrag.append(p)
+ continue
+ uniq = (ip.id,ip.src,ip.dst,ip.proto)
+ frags[uniq].append(p)
+ defrag = []
+ missfrag = []
+ for lst in frags.values():
+ lst.sort(key=lambda x: x.frag)
+ p = lst[0]
+ lastp = lst[-1]
+ if p.frag > 0 or lastp.flags & 1 != 0: # first or last fragment missing
+ missfrag.append(lst)
+ continue
+ p = p.copy()
+ if conf.padding_layer in p:
+ del(p[conf.padding_layer].underlayer.payload)
+ ip = p[IP]
+ if ip.len is None or ip.ihl is None:
+ clen = len(ip.payload)
+ else:
+ clen = ip.len - (ip.ihl<<2)
+ txt = conf.raw_layer()
+ for q in lst[1:]:
+ if clen != q.frag<<3: # Wrong fragmentation offset
+ if clen > q.frag<<3:
+ warning("Fragment overlap (%i > %i) %r || %r || %r" % (clen, q.frag<<3, p,txt,q))
+ missfrag.append(lst)
+ break
+ if q[IP].len is None or q[IP].ihl is None:
+ clen += len(q[IP].payload)
+ else:
+ clen += q[IP].len - (q[IP].ihl<<2)
+ if conf.padding_layer in q:
+ del(q[conf.padding_layer].underlayer.payload)
+ txt.add_payload(q[IP].payload.copy())
+ else:
+ ip.flags &= ~1 # !MF
+ del(ip.chksum)
+ del(ip.len)
+ p = p/txt
+ defrag.append(p)
+ defrag2=PacketList()
+ for p in defrag:
+ defrag2.append(p.__class__(bytes(p)))
+ return nofrag,defrag2,missfrag
+
+@conf.commands.register
+def defragment(plist):
+ """defragment(plist) -> plist defragmented as much as possible """
+ frags = defaultdict(lambda:[])
+ final = []
+
+ pos = 0
+ for p in plist:
+ p._defrag_pos = pos
+ pos += 1
+ if IP in p:
+ ip = p[IP]
+ if ip.frag != 0 or ip.flags & 1:
+ ip = p[IP]
+ uniq = (ip.id,ip.src,ip.dst,ip.proto)
+ frags[uniq].append(p)
+ continue
+ final.append(p)
+
+ defrag = []
+ missfrag = []
+ for lst in frags.values():
+ lst.sort(key=lambda x: x.frag)
+ p = lst[0]
+ lastp = lst[-1]
+ if p.frag > 0 or lastp.flags & 1 != 0: # first or last fragment missing
+ missfrag += lst
+ continue
+ p = p.copy()
+ if conf.padding_layer in p:
+ del(p[conf.padding_layer].underlayer.payload)
+ ip = p[IP]
+ if ip.len is None or ip.ihl is None:
+ clen = len(ip.payload)
+ else:
+ clen = ip.len - (ip.ihl<<2)
+ txt = conf.raw_layer()
+ for q in lst[1:]:
+ if clen != q.frag<<3: # Wrong fragmentation offset
+ if clen > q.frag<<3:
+ warning("Fragment overlap (%i > %i) %r || %r || %r" % (clen, q.frag<<3, p,txt,q))
+ missfrag += lst
+ break
+ if q[IP].len is None or q[IP].ihl is None:
+ clen += len(q[IP].payload)
+ else:
+ clen += q[IP].len - (q[IP].ihl<<2)
+ if conf.padding_layer in q:
+ del(q[conf.padding_layer].underlayer.payload)
+ txt.add_payload(q[IP].payload.copy())
+ else:
+ ip.flags &= ~1 # !MF
+ del(ip.chksum)
+ del(ip.len)
+ p = p/txt
+ p._defrag_pos = max(x._defrag_pos for x in lst)
+ defrag.append(p)
+ defrag2=[]
+ for p in defrag:
+ q = p.__class__(bytes(p))
+ q._defrag_pos = p._defrag_pos
+ defrag2.append(q)
+ final += defrag2
+ final += missfrag
+ final.sort(key=lambda x: x._defrag_pos)
+ for p in final:
+ del(p._defrag_pos)
+
+ if hasattr(plist, "listname"):
+ name = "Defragmented %s" % plist.listname
+ else:
+ name = "Defragmented"
+
+ return PacketList(final, name=name)
+
+
+
+### Add timeskew_graph() method to PacketList
+def _packetlist_timeskew_graph(self, ip, **kargs):
+ """Tries to graph the timeskew between the timestamps and real time for a given ip"""
+ res = map(lambda x: self._elt2pkt(x), self.res)
+ b = filter(lambda x:x.haslayer(IP) and x.getlayer(IP).src == ip and x.haslayer(TCP), res)
+ c = []
+ for p in b:
+ opts = p.getlayer(TCP).options
+ for o in opts:
+ if o[0] == "Timestamp":
+ c.append((p.time,o[1][0]))
+ if not c:
+ warning("No timestamps found in packet list")
+ return
+ #d = map(lambda (x,y): (x%2000,((x-c[0][0])-((y-c[0][1])/1000.0))),c)
+ d = map(lambda a: (a[0]%2000,((a[0]-c[0][0])-((a[1]-c[0][1])/1000.0))),c)
+ return plt.plot(d, **kargs)
+
+#PacketList.timeskew_graph = types.MethodType(_packetlist_timeskew_graph, None)
+
+
+### Create a new packet list
+class TracerouteResult(SndRcvList):
+ def __init__(self, res=None, name="Traceroute", stats=None):
+ PacketList.__init__(self, res, name, stats, vector_index = 1)
+ self.graphdef = None
+ self.graphASres = 0
+ self.padding = 0
+ self.hloc = None
+ self.nloc = None
+
+ def show(self):
+ #return self.make_table(lambda (s,r): (s.sprintf("%IP.dst%:{TCP:tcp%ir,TCP.dport%}{UDP:udp%ir,UDP.dport%}{ICMP:ICMP}"),
+ return self.make_table(lambda s,r: (s.sprintf("%IP.dst%:{TCP:tcp%ir,TCP.dport%}{UDP:udp%ir,UDP.dport%}{ICMP:ICMP}"),
+ s.ttl,
+ r.sprintf("%-15s,IP.src% {TCP:%TCP.flags%}{ICMP:%ir,ICMP.type%}")))
+
+
+ def get_trace(self):
+ raw_trace = {}
+ for s,r in self.res:
+ if IP not in s:
+ continue
+ d = s[IP].dst
+ if d not in raw_trace:
+ raw_trace[d] = {}
+ raw_trace[d][s[IP].ttl] = r[IP].src, ICMP not in r
+
+ trace = {}
+ for k in raw_trace.keys():
+ m = [ x for x in raw_trace[k].keys() if raw_trace[k][x][1] ]
+ if not m:
+ trace[k] = raw_trace[k]
+ else:
+ m = min(m)
+ trace[k] = {i: raw_trace[k][i] for i in raw_trace[k].keys() if not raw_trace[k][i][1] or i<=m}
+
+ return trace
+
+ def trace3D(self):
+ """Give a 3D representation of the traceroute.
+ right button: rotate the scene
+ middle button: zoom
+ left button: move the scene
+ left button on a ball: toggle IP displaying
+ ctrl-left button on a ball: scan ports 21,22,23,25,80 and 443 and display the result"""
+ trace = self.get_trace()
+ import visual
+
+ class IPsphere(visual.sphere):
+ def __init__(self, ip, **kargs):
+ visual.sphere.__init__(self, **kargs)
+ self.ip=ip
+ self.label=None
+ self.setlabel(self.ip)
+ def setlabel(self, txt,visible=None):
+ if self.label is not None:
+ if visible is None:
+ visible = self.label.visible
+ self.label.visible = 0
+ elif visible is None:
+ visible=0
+ self.label=visual.label(text=txt, pos=self.pos, space=self.radius, xoffset=10, yoffset=20, visible=visible)
+ def action(self):
+ self.label.visible ^= 1
+
+ visual.scene = visual.display()
+ visual.scene.exit = True
+ start = visual.box()
+ rings={}
+ tr3d = {}
+ for i in trace:
+ tr = trace[i]
+ tr3d[i] = []
+ ttl = tr.keys()
+ for t in range(1,max(ttl)+1):
+ if t not in rings:
+ rings[t] = []
+ if t in tr:
+ if tr[t] not in rings[t]:
+ rings[t].append(tr[t])
+ tr3d[i].append(rings[t].index(tr[t]))
+ else:
+ rings[t].append(("unk",-1))
+ tr3d[i].append(len(rings[t])-1)
+ for t in rings:
+ r = rings[t]
+ l = len(r)
+ for i in range(l):
+ if r[i][1] == -1:
+ col = (0.75,0.75,0.75)
+ elif r[i][1]:
+ col = visual.color.green
+ else:
+ col = visual.color.blue
+
+ s = IPsphere(pos=((l-1)*visual.cos(2*i*visual.pi/l),(l-1)*visual.sin(2*i*visual.pi/l),2*t),
+ ip = r[i][0],
+ color = col)
+ for trlst in tr3d.values():
+ if t <= len(trlst):
+ if trlst[t-1] == i:
+ trlst[t-1] = s
+ forecol = colgen(0.625, 0.4375, 0.25, 0.125)
+ for trlst in tr3d.values():
+ col = next(forecol)
+ start = (0,0,0)
+ for ip in trlst:
+ visual.cylinder(pos=start,axis=ip.pos-start,color=col,radius=0.2)
+ start = ip.pos
+
+ movcenter=None
+ while 1:
+ visual.rate(50)
+ if visual.scene.kb.keys:
+ k = visual.scene.kb.getkey()
+ if k == "esc" or k == "q":
+ break
+ if visual.scene.mouse.events:
+ ev = visual.scene.mouse.getevent()
+ if ev.press == "left":
+ o = ev.pick
+ if o:
+ if ev.ctrl:
+ if o.ip == "unk":
+ continue
+ savcolor = o.color
+ o.color = (1,0,0)
+ a,b=sr(IP(dst=o.ip)/TCP(dport=[21,22,23,25,80,443]),timeout=2)
+ o.color = savcolor
+ if len(a) == 0:
+ txt = "%s:\nno results" % o.ip
+ else:
+ txt = "%s:\n" % o.ip
+ for s,r in a:
+ txt += r.sprintf("{TCP:%IP.src%:%TCP.sport% %TCP.flags%}{TCPerror:%IPerror.dst%:%TCPerror.dport% %IP.src% %ir,ICMP.type%}\n")
+ o.setlabel(txt, visible=1)
+ else:
+ if hasattr(o, "action"):
+ o.action()
+ elif ev.drag == "left":
+ movcenter = ev.pos
+ elif ev.drop == "left":
+ movcenter = None
+ if movcenter:
+ visual.scene.center -= visual.scene.mouse.pos-movcenter
+ movcenter = visual.scene.mouse.pos
+
+## world_trace needs to be reimplemented as gnuplot dependency is removed
+# def world_trace(self):
+# from modules.geo import locate_ip
+# ips = {}
+# rt = {}
+# ports_done = {}
+# for s,r in self.res:
+# ips[r.src] = None
+# if s.haslayer(TCP) or s.haslayer(UDP):
+# trace_id = (s.src,s.dst,s.proto,s.dport)
+# elif s.haslayer(ICMP):
+# trace_id = (s.src,s.dst,s.proto,s.type)
+# else:
+# trace_id = (s.src,s.dst,s.proto,0)
+# trace = rt.get(trace_id,{})
+# if not r.haslayer(ICMP) or r.type != 11:
+# if trace_id in ports_done:
+# continue
+# ports_done[trace_id] = None
+# trace[s.ttl] = r.src
+# rt[trace_id] = trace
+#
+# trt = {}
+# for trace_id in rt:
+# trace = rt[trace_id]
+# loctrace = []
+# for i in range(max(trace.keys())):
+# ip = trace.get(i,None)
+# if ip is None:
+# continue
+# loc = locate_ip(ip)
+# if loc is None:
+# continue
+## loctrace.append((ip,loc)) # no labels yet
+# loctrace.append(loc)
+# if loctrace:
+# trt[trace_id] = loctrace
+#
+# tr = map(lambda x: Gnuplot.Data(x,with_="lines"), trt.values())
+# g = Gnuplot.Gnuplot()
+# world = Gnuplot.File(conf.gnuplot_world,with_="lines")
+# g.plot(world,*tr)
+# return g
+
+ def make_graph(self,ASres=None,padding=0):
+ if ASres is None:
+ ASres = conf.AS_resolver
+ self.graphASres = ASres
+ self.graphpadding = padding
+ ips = {}
+ rt = {}
+ ports = {}
+ ports_done = {}
+ for s,r in self.res:
+ r = r.getlayer(IP) or (conf.ipv6_enabled and r[scapy.layers.inet6.IPv6]) or r
+ s = s.getlayer(IP) or (conf.ipv6_enabled and s[scapy.layers.inet6.IPv6]) or s
+ ips[r.src] = None
+ if TCP in s:
+ trace_id = (s.src,s.dst,6,s.dport)
+ elif UDP in s:
+ trace_id = (s.src,s.dst,17,s.dport)
+ elif ICMP in s:
+ trace_id = (s.src,s.dst,1,s.type)
+ else:
+ trace_id = (s.src,s.dst,s.proto,0)
+ trace = rt.get(trace_id,{})
+ ttl = conf.ipv6_enabled and scapy.layers.inet6.IPv6 in s and s.hlim or s.ttl
+ if not (ICMP in r and r[ICMP].type == 11) and not (conf.ipv6_enabled and scapy.layers.inet6.IPv6 in r and scapy.layers.inet6.ICMPv6TimeExceeded in r):
+ if trace_id in ports_done:
+ continue
+ ports_done[trace_id] = None
+ p = ports.get(r.src,[])
+ if TCP in r:
+ p.append(r.sprintf("<T%ir,TCP.sport%> %TCP.sport% %TCP.flags%"))
+ trace[ttl] = r.sprintf('"%r,src%":T%ir,TCP.sport%')
+ elif UDP in r:
+ p.append(r.sprintf("<U%ir,UDP.sport%> %UDP.sport%"))
+ trace[ttl] = r.sprintf('"%r,src%":U%ir,UDP.sport%')
+ elif ICMP in r:
+ p.append(r.sprintf("<I%ir,ICMP.type%> ICMP %ICMP.type%"))
+ trace[ttl] = r.sprintf('"%r,src%":I%ir,ICMP.type%')
+ else:
+ p.append(r.sprintf("{IP:<P%ir,proto%> IP %proto%}{IPv6:<P%ir,nh%> IPv6 %nh%}"))
+ trace[ttl] = r.sprintf('"%r,src%":{IP:P%ir,proto%}{IPv6:P%ir,nh%}')
+ ports[r.src] = p
+ else:
+ trace[ttl] = r.sprintf('"%r,src%"')
+ rt[trace_id] = trace
+
+ # Fill holes with unk%i nodes
+ unknown_label = incremental_label("unk%i")
+ blackholes = []
+ bhip = {}
+ for rtk in rt:
+ trace = rt[rtk]
+ k = trace.keys()
+ for n in range(min(k), max(k)):
+ if not n in trace:
+ trace[n] = next(unknown_label)
+ if not rtk in ports_done:
+ if rtk[2] == 1: #ICMP
+ bh = "%s %i/icmp" % (rtk[1],rtk[3])
+ elif rtk[2] == 6: #TCP
+ bh = "%s %i/tcp" % (rtk[1],rtk[3])
+ elif rtk[2] == 17: #UDP
+ bh = '%s %i/udp' % (rtk[1],rtk[3])
+ else:
+ bh = '%s %i/proto' % (rtk[1],rtk[2])
+ ips[bh] = None
+ bhip[rtk[1]] = bh
+ bh = '"%s"' % bh
+ trace[max(k)+1] = bh
+ blackholes.append(bh)
+
+ # Find AS numbers
+ ASN_query_list = dict.fromkeys(map(lambda x:x.rsplit(" ",1)[0],ips)).keys()
+ if ASres is None:
+ ASNlist = []
+ else:
+ ASNlist = ASres.resolve(*ASN_query_list)
+
+ ASNs = {}
+ ASDs = {}
+ for ip,asn,desc, in ASNlist:
+ if asn is None:
+ continue
+ iplist = ASNs.get(asn,[])
+ if ip in bhip:
+ if ip in ports:
+ iplist.append(ip)
+ iplist.append(bhip[ip])
+ else:
+ iplist.append(ip)
+ ASNs[asn] = iplist
+ ASDs[asn] = desc
+
+
+ backcolorlist=colgen("60","86","ba","ff")
+ forecolorlist=colgen("a0","70","40","20")
+
+ s = "digraph trace {\n"
+
+ s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n"
+
+ s += "\n#ASN clustering\n"
+ for asn in ASNs:
+ s += '\tsubgraph cluster_%s {\n' % asn
+ col = next(backcolorlist)
+ s += '\t\tcolor="#%s%s%s";' % col
+ s += '\t\tnode [fillcolor="#%s%s%s",style=filled];' % col
+ s += '\t\tfontsize = 10;'
+ s += '\t\tlabel = "%s\\n[%s]"\n' % (asn,ASDs[asn])
+ for ip in ASNs[asn]:
+
+ s += '\t\t"%s";\n'%ip
+ s += "\t}\n"
+
+
+
+
+ s += "#endpoints\n"
+ for p in ports:
+ s += '\t"%s" [shape=record,color=black,fillcolor=green,style=filled,label="%s|%s"];\n' % (p,p,"|".join(ports[p]))
+
+ s += "\n#Blackholes\n"
+ for bh in blackholes:
+ s += '\t%s [shape=octagon,color=black,fillcolor=red,style=filled];\n' % bh
+
+ if padding:
+ s += "\n#Padding\n"
+ pad={}
+ for snd,rcv in self.res:
+ if rcv.src not in ports and rcv.haslayer(conf.padding_layer):
+ p = rcv.getlayer(conf.padding_layer).load
+ if p != "\x00"*len(p):
+ pad[rcv.src]=None
+ for rcv in pad:
+ s += '\t"%s" [shape=triangle,color=black,fillcolor=red,style=filled];\n' % rcv
+
+
+
+ s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n"
+
+
+ for rtk in rt:
+ s += "#---[%s\n" % repr(rtk)
+ s += '\t\tedge [color="#%s%s%s"];\n' % next(forecolorlist)
+ trace = rt[rtk]
+ k = trace.keys()
+ for n in range(min(k), max(k)):
+ s += '\t%s ->\n' % trace[n]
+ s += '\t%s;\n' % trace[max(k)]
+
+ s += "}\n";
+ self.graphdef = s
+
+ def graph(self, ASres=None, padding=0, **kargs):
+ """x.graph(ASres=conf.AS_resolver, other args):
+ ASres=None : no AS resolver => no clustering
+ ASres=AS_resolver() : default whois AS resolver (riswhois.ripe.net)
+ ASres=AS_resolver_cymru(): use whois.cymru.com whois database
+ ASres=AS_resolver(server="whois.ra.net")
+ format: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option
+ figsize: w,h tuple in inches. See matplotlib documentation
+ target: filename. If None uses matplotlib to display
+ prog: which graphviz program to use"""
+ if ASres is None:
+ ASres = conf.AS_resolver
+ if (self.graphdef is None or
+ self.graphASres != ASres or
+ self.graphpadding != padding):
+ self.make_graph(ASres,padding)
+
+ return do_graph(self.graphdef, **kargs)
+
+
+
+@conf.commands.register
+def traceroute(target, dport=80, minttl=1, maxttl=30, sport=RandShort(), l4 = None, filter=None, timeout=2, verbose=None, **kargs):
+ """Instant TCP traceroute
+traceroute(target, [maxttl=30,] [dport=80,] [sport=80,] [verbose=conf.verb]) -> None
+"""
+ if verbose is None:
+ verbose = conf.verb
+ if filter is None:
+ # we only consider ICMP error packets and TCP packets with at
+ # least the ACK flag set *and* either the SYN or the RST flag
+ # set
+ filter="(icmp and (icmp[0]=3 or icmp[0]=4 or icmp[0]=5 or icmp[0]=11 or icmp[0]=12)) or (tcp and (tcp[13] & 0x16 > 0x10))"
+ if l4 is None:
+ a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/TCP(seq=RandInt(),sport=sport, dport=dport),
+ timeout=timeout, filter=filter, verbose=verbose, **kargs)
+ else:
+ # this should always work
+ filter="ip"
+ a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/l4,
+ timeout=timeout, filter=filter, verbose=verbose, **kargs)
+
+ a = TracerouteResult(a.res)
+
+ if verbose:
+ a.show()
+ return a,b
+
+
+
+#############################
+## Simple TCP client stack ##
+#############################
+
+class TCP_client(Automaton):
+
+ def parse_args(self, ip, port, *args, **kargs):
+ self.dst = next(iter(Net(ip)))
+ self.dport = port
+ self.sport = random.randrange(0,2**16)
+ self.l4 = IP(dst=ip)/TCP(sport=self.sport, dport=self.dport, flags=0,
+ seq=random.randrange(0,2**32))
+ self.src = self.l4.src
+ self.swin=self.l4[TCP].window
+ self.dwin=1
+ self.rcvbuf=""
+ bpf = "host %s and host %s and port %i and port %i" % (self.src,
+ self.dst,
+ self.sport,
+ self.dport)
+
+# bpf=None
+ Automaton.parse_args(self, filter=bpf, **kargs)
+
+
+ def master_filter(self, pkt):
+ return (IP in pkt and
+ pkt[IP].src == self.dst and
+ pkt[IP].dst == self.src and
+ TCP in pkt and
+ pkt[TCP].sport == self.dport and
+ pkt[TCP].dport == self.sport and
+ self.l4[TCP].seq >= pkt[TCP].ack and # XXX: seq/ack 2^32 wrap up
+ ((self.l4[TCP].ack == 0) or (self.l4[TCP].ack <= pkt[TCP].seq <= self.l4[TCP].ack+self.swin)) )
+
+
+ @ATMT.state(initial=1)
+ def START(self):
+ pass
+
+ @ATMT.state()
+ def SYN_SENT(self):
+ pass
+
+ @ATMT.state()
+ def ESTABLISHED(self):
+ pass
+
+ @ATMT.state()
+ def LAST_ACK(self):
+ pass
+
+ @ATMT.state(final=1)
+ def CLOSED(self):
+ pass
+
+
+ @ATMT.condition(START)
+ def connect(self):
+ raise self.SYN_SENT()
+ @ATMT.action(connect)
+ def send_syn(self):
+ self.l4[TCP].flags = "S"
+ self.send(self.l4)
+ self.l4[TCP].seq += 1
+
+
+ @ATMT.receive_condition(SYN_SENT)
+ def synack_received(self, pkt):
+ if pkt[TCP].flags & 0x3f == 0x12:
+ raise self.ESTABLISHED().action_parameters(pkt)
+ @ATMT.action(synack_received)
+ def send_ack_of_synack(self, pkt):
+ self.l4[TCP].ack = pkt[TCP].seq+1
+ self.l4[TCP].flags = "A"
+ self.send(self.l4)
+
+ @ATMT.receive_condition(ESTABLISHED)
+ def incoming_data_received(self, pkt):
+ if not isinstance(pkt[TCP].payload, NoPayload) and not isinstance(pkt[TCP].payload, conf.padding_layer):
+ raise self.ESTABLISHED().action_parameters(pkt)
+ @ATMT.action(incoming_data_received)
+ def receive_data(self,pkt):
+ data = (bytes(pkt[TCP].payload))
+ if data and self.l4[TCP].ack == pkt[TCP].seq:
+ self.l4[TCP].ack += len(data)
+ self.l4[TCP].flags = "A"
+ self.send(self.l4)
+ self.rcvbuf += data
+ if pkt[TCP].flags & 8 != 0: #PUSH
+ self.oi.tcp.send(self.rcvbuf)
+ self.rcvbuf = ""
+
+ @ATMT.ioevent(ESTABLISHED,name="tcp", as_supersocket="tcplink")
+ def outgoing_data_received(self, fd):
+ raise self.ESTABLISHED().action_parameters(fd.recv())
+ @ATMT.action(outgoing_data_received)
+ def send_data(self, d):
+ self.l4[TCP].flags = "PA"
+ self.send(self.l4/d)
+ self.l4[TCP].seq += len(d)
+
+
+ @ATMT.receive_condition(ESTABLISHED)
+ def reset_received(self, pkt):
+ if pkt[TCP].flags & 4 != 0:
+ raise self.CLOSED()
+
+ @ATMT.receive_condition(ESTABLISHED)
+ def fin_received(self, pkt):
+ if pkt[TCP].flags & 0x1 == 1:
+ raise self.LAST_ACK().action_parameters(pkt)
+ @ATMT.action(fin_received)
+ def send_finack(self, pkt):
+ self.l4[TCP].flags = "FA"
+ self.l4[TCP].ack = pkt[TCP].seq+1
+ self.send(self.l4)
+ self.l4[TCP].seq += 1
+
+ @ATMT.receive_condition(LAST_ACK)
+ def ack_of_fin_received(self, pkt):
+ if pkt[TCP].flags & 0x3f == 0x10:
+ raise self.CLOSED()
+
+
+
+
+#####################
+## Reporting stuff ##
+#####################
+
+def report_ports(target, ports):
+ """portscan a target and output a LaTeX table
+report_ports(target, ports) -> string"""
+ ans,unans = sr(IP(dst=target)/TCP(dport=ports),timeout=5)
+ rep = "\\begin{tabular}{|r|l|l|}\n\\hline\n"
+ for s,r in ans:
+ if not r.haslayer(ICMP):
+ if r.payload.flags == 0x12:
+ rep += r.sprintf("%TCP.sport% & open & SA \\\\\n")
+ rep += "\\hline\n"
+ for s,r in ans:
+ if r.haslayer(ICMP):
+ rep += r.sprintf("%TCPerror.dport% & closed & ICMP type %ICMP.type%/%ICMP.code% from %IP.src% \\\\\n")
+ elif r.payload.flags != 0x12:
+ rep += r.sprintf("%TCP.sport% & closed & TCP %TCP.flags% \\\\\n")
+ rep += "\\hline\n"
+ for i in unans:
+ rep += i.sprintf("%TCP.dport% & ? & unanswered \\\\\n")
+ rep += "\\hline\n\\end{tabular}\n"
+ return rep
+
+
+
+def IPID_count(lst, funcID=lambda x:x[1].id, funcpres=lambda x:x[1].summary()):
+ idlst = map(funcID, lst)
+ idlst.sort()
+ #classes = [idlst[0]]+map(lambda x:x[1],filter(lambda (x,y): abs(x-y)>50, map(lambda x,y: (x,y),idlst[:-1], idlst[1:])))
+ classes = [idlst[0]]+list(map(lambda x:x[1],filter(lambda a: abs(a[0]-a[1])>50, map(lambda x,y: (x,y),idlst[:-1], idlst[1:]))))
+ lst = map(lambda x:(funcID(x), funcpres(x)), lst)
+ lst.sort()
+ print("Probably %i classes:" % len(classes), classes)
+ for id,pr in lst:
+ print("%5i" % id, pr)
+
+
+def fragleak(target,sport=123, dport=123, timeout=0.2, onlyasc=0):
+ load = "XXXXYYYYYYYYYY"
+# getmacbyip(target)
+# pkt = IP(dst=target, id=RandShort(), options="\x22"*40)/UDP()/load
+ pkt = IP(dst=target, id=RandShort(), options="\x00"*40, flags=1)/UDP(sport=sport, dport=sport)/load
+ s=conf.L3socket()
+ intr=0
+ found={}
+ try:
+ while 1:
+ try:
+ if not intr:
+ s.send(pkt)
+ sin,sout,serr = select([s],[],[],timeout)
+ if not sin:
+ continue
+ ans=s.recv(1600)
+ if not isinstance(ans, IP): #TODO: IPv6
+ continue
+ if not isinstance(ans.payload, ICMP):
+ continue
+ if not isinstance(ans.payload.payload, IPerror):
+ continue
+ if ans.payload.payload.dst != target:
+ continue
+ if ans.src != target:
+ print("leak from", ans.src,end=" ")
+
+
+# print repr(ans)
+ if not ans.haslayer(conf.padding_layer):
+ continue
+
+
+# print repr(ans.payload.payload.payload.payload)
+
+# if not isinstance(ans.payload.payload.payload.payload, conf.raw_layer):
+# continue
+# leak = ans.payload.payload.payload.payload.load[len(load):]
+ leak = ans.getlayer(conf.padding_layer).load
+ if leak not in found:
+ found[leak]=None
+ linehexdump(leak, onlyasc=onlyasc)
+ except KeyboardInterrupt:
+ if intr:
+ raise
+ intr=1
+ except KeyboardInterrupt:
+ pass
+
+def fragleak2(target, timeout=0.4, onlyasc=0):
+ found={}
+ try:
+ while 1:
+ p = sr1(IP(dst=target, options="\x00"*40, proto=200)/"XXXXYYYYYYYYYYYY",timeout=timeout,verbose=0)
+ if not p:
+ continue
+ if conf.padding_layer in p:
+ leak = p[conf.padding_layer].load
+ if leak not in found:
+ found[leak]=None
+ linehexdump(leak,onlyasc=onlyasc)
+ except:
+ pass
+
+
+conf.stats_classic_protocols += [TCP,UDP,ICMP]
+conf.stats_dot11_protocols += [TCP,UDP,ICMP]
+
+if conf.ipv6_enabled:
+ import scapy.layers.inet6
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/inet6.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/inet6.py
new file mode 100644
index 00000000..c2e4a037
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/inet6.py
@@ -0,0 +1,3047 @@
+#! /usr/bin/env python
+#############################################################################
+## ##
+## inet6.py --- IPv6 support for Scapy ##
+## see http://natisbad.org/IPv6/ ##
+## for more informations ##
+## ##
+## Copyright (C) 2005 Guillaume Valadon <guedou@hongo.wide.ad.jp> ##
+## Arnaud Ebalard <arnaud.ebalard@eads.net> ##
+## ##
+## This program is free software; you can redistribute it and/or modify it ##
+## under the terms of the GNU General Public License version 2 as ##
+## published by the Free Software Foundation. ##
+## ##
+## This program is distributed in the hope that it will be useful, but ##
+## WITHOUT ANY WARRANTY; without even the implied warranty of ##
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ##
+## General Public License for more details. ##
+## ##
+#############################################################################
+
+"""
+IPv6 (Internet Protocol v6).
+"""
+
+
+import socket
+if not socket.has_ipv6:
+ raise socket.error("can't use AF_INET6, IPv6 is disabled")
+if not hasattr(socket, "IPPROTO_IPV6"):
+ # Workaround for http://bugs.python.org/issue6926
+ socket.IPPROTO_IPV6 = 41
+
+if not hasattr(socket, "IPPROTO_IPIP"):
+ socket.IPPROTO_IPIP = 4
+
+if not ('IPPROTO_IPIP ' in globals()):
+ IPPROTO_IPIP=4
+
+
+
+from scapy.config import conf
+from scapy.layers.l2 import *
+from scapy.layers.inet import *
+from scapy.fields import *
+from scapy.packet import *
+from scapy.volatile import *
+from scapy.sendrecv import sr,sr1,srp1
+from scapy.as_resolvers import AS_resolver_riswhois
+from scapy.supersocket import SuperSocket,L3RawSocket
+from scapy.arch import *
+from scapy.utils6 import *
+
+
+#############################################################################
+# Helpers ##
+#############################################################################
+
+def get_cls(name, fallback_cls):
+ return globals().get(name, fallback_cls)
+
+
+##########################
+## Neighbor cache stuff ##
+##########################
+
+conf.netcache.new_cache("in6_neighbor", 120)
+
+def neighsol(addr, src, iface, timeout=1, chainCC=0):
+ """
+ Sends an ICMPv6 Neighbor Solicitation message to get the MAC address
+ of the neighbor with specified IPv6 address addr. 'src' address is
+ used as source of the message. Message is sent on iface. By default,
+ timeout waiting for an answer is 1 second.
+
+ If no answer is gathered, None is returned. Else, the answer is
+ returned (ethernet frame).
+ """
+
+ nsma = in6_getnsma(inet_pton(socket.AF_INET6, addr))
+ d = inet_ntop(socket.AF_INET6, nsma)
+ dm = in6_getnsmac(nsma)
+ p = Ether(dst=dm)/IPv6(dst=d, src=src, hlim=255)
+ p /= ICMPv6ND_NS(tgt=addr)
+ p /= ICMPv6NDOptSrcLLAddr(lladdr=get_if_hwaddr(iface))
+ res = srp1(p,type=ETH_P_IPV6, iface=iface, timeout=1, verbose=0,
+ chainCC=chainCC)
+
+ return res
+
+def getmacbyip6(ip6, chainCC=0):
+ """
+ Returns the mac address to be used for provided 'ip6' peer.
+ neighborCache.get() method is used on instantiated neighbor cache.
+ Resolution mechanism is described in associated doc string.
+
+ (chainCC parameter value ends up being passed to sending function
+ used to perform the resolution, if needed)
+ """
+
+ if in6_ismaddr(ip6): # Multicast
+ mac = in6_getnsmac(inet_pton(socket.AF_INET6, ip6))
+ return mac
+
+ iff,a,nh = conf.route6.route(ip6, dev=conf.iface6)
+
+ if iff == LOOPBACK_NAME:
+ return "ff:ff:ff:ff:ff:ff"
+
+ if nh != '::':
+ ip6 = nh # Found next hop
+
+ mac = conf.netcache.in6_neighbor.get(ip6)
+ if mac:
+ return mac
+
+ res = neighsol(ip6, a, iff, chainCC=chainCC)
+
+ if res is not None:
+ if ICMPv6NDOptDstLLAddr in res:
+ mac = res[ICMPv6NDOptDstLLAddr].lladdr
+ else:
+ mac = res.src
+ conf.netcache.in6_neighbor[ip6] = mac
+ return mac
+
+ return None
+
+
+#############################################################################
+#############################################################################
+### IPv6 addresses manipulation routines ###
+#############################################################################
+#############################################################################
+
+class Net6(Gen): # syntax ex. fec0::/126
+ """Generate a list of IPv6s from a network address or a name"""
+ name = "ipv6"
+ ipaddress = re.compile(r"^([a-fA-F0-9:]+)(/[1]?[0-3]?[0-9])?$")
+
+ def __init__(self, net):
+ self.repr = net
+
+ tmp = net.split('/')+["128"]
+ if not self.ipaddress.match(net):
+ tmp[0]=socket.getaddrinfo(tmp[0], None, socket.AF_INET6)[0][-1][0]
+
+ netmask = int(tmp[1])
+ self.net = inet_pton(socket.AF_INET6, tmp[0])
+ self.mask = in6_cidr2mask(netmask)
+ self.plen = netmask
+
+ def __iter__(self):
+ def m8(i):
+ if i % 8 == 0:
+ return i
+ #tuple = filter(lambda x: m8(x), range(8, 129))
+ tuple = [ x for x in range(8, 129) if m8(x) ]
+
+ a = in6_and(self.net, self.mask)
+ tmp = map(lambda x: x, struct.unpack('16B', a))
+
+ def parse_digit(a, netmask):
+ netmask = min(8,max(netmask,0))
+ a = (int(a) & (0xff<<netmask),(int(a) | (0xff>>(8-netmask)))+1)
+ return a
+ self.parsed = map(lambda x,y: parse_digit(x,y), tmp, map(lambda x,nm=self.plen: x-nm, tuple))
+
+ def rec(n, l):
+ if n and n % 2 == 0:
+ sep = ':'
+ else:
+ sep = ''
+ if n == 16:
+ return l
+ else:
+ ll = []
+ for i in range(*self.parsed[n]):
+ for y in l:
+ ll += [y+sep+'%.2x'%i]
+ return rec(n+1, ll)
+
+ return iter(rec(0, ['']))
+
+ def __repr__(self):
+ return "<Net6 %s>" % self.repr
+
+
+
+
+
+
+#############################################################################
+#############################################################################
+### IPv6 Class ###
+#############################################################################
+#############################################################################
+
+class IP6Field(Field):
+ def __init__(self, name, default):
+ Field.__init__(self, name, default, "16s")
+ def h2i(self, pkt, x):
+ if type(x) is str:
+ try:
+ x = in6_ptop(x)
+ except socket.error:
+ x = Net6(x)
+ elif type(x) is list:
+ x = map(Net6, x)
+ return x
+ def i2m(self, pkt, x):
+ return inet_pton(socket.AF_INET6, x)
+ def m2i(self, pkt, x):
+ return inet_ntop(socket.AF_INET6, x)
+ def any2i(self, pkt, x):
+ return self.h2i(pkt,x)
+ def i2repr(self, pkt, x):
+ if x is None:
+ return self.i2h(pkt,x)
+ elif not isinstance(x, Net6) and not type(x) is list:
+ if in6_isaddrTeredo(x): # print Teredo info
+ server, flag, maddr, mport = teredoAddrExtractInfo(x)
+ return "%s [Teredo srv: %s cli: %s:%s]" % (self.i2h(pkt, x), server, maddr,mport)
+ elif in6_isaddr6to4(x): # print encapsulated address
+ vaddr = in6_6to4ExtractAddr(x)
+ return "%s [6to4 GW: %s]" % (self.i2h(pkt, x), vaddr)
+ return self.i2h(pkt, x) # No specific information to return
+ def randval(self):
+ return RandIP6()
+
+class SourceIP6Field(IP6Field):
+ def __init__(self, name, dstname):
+ IP6Field.__init__(self, name, None)
+ self.dstname = dstname
+ def i2m(self, pkt, x):
+ if x is None:
+ dst=getattr(pkt,self.dstname)
+ iff,x,nh = conf.route6.route(dst)
+ return IP6Field.i2m(self, pkt, x)
+ def i2h(self, pkt, x):
+ if x is None:
+ dst=getattr(pkt,self.dstname)
+ if isinstance(dst,Gen):
+ r = map(conf.route6.route, dst)
+ r.sort()
+ if r[0] == r[-1]:
+ x=r[0][1]
+ else:
+ warning("More than one possible route for %s"%repr(dst))
+ return None
+ else:
+ iff,x,nh = conf.route6.route(dst)
+ return IP6Field.i2h(self, pkt, x)
+
+ipv6nh = { 0:"Hop-by-Hop Option Header",
+ 4:"IP",
+ 6:"TCP",
+ 17:"UDP",
+ 41:"IPv6",
+ 43:"Routing Header",
+ 44:"Fragment Header",
+ 47:"GRE",
+ 50:"ESP Header",
+ 51:"AH Header",
+ 58:"ICMPv6",
+ 59:"No Next Header",
+ 60:"Destination Option Header",
+ 135:"Mobility Header"}
+
+ipv6nhcls = { 0: "IPv6ExtHdrHopByHop",
+ 4: "IP",
+ 6: "TCP",
+ 17: "UDP",
+ 43: "IPv6ExtHdrRouting",
+ 44: "IPv6ExtHdrFragment",
+ #50: "IPv6ExtHrESP",
+ #51: "IPv6ExtHdrAH",
+ 58: "ICMPv6Unknown",
+ 59: "Raw",
+ 60: "IPv6ExtHdrDestOpt" }
+
+class IP6ListField(StrField):
+ islist = 1
+ def __init__(self, name, default, count_from=None, length_from=None):
+ if default is None:
+ default = []
+ StrField.__init__(self, name, default)
+ self.count_from = count_from
+ self.length_from = length_from
+
+ def i2len(self, pkt, i):
+ return 16*len(i)
+
+ def i2count(self, pkt, i):
+ if type(i) is list:
+ return len(i)
+ return 0
+
+ def getfield(self, pkt, s):
+ c = l = None
+ if self.length_from is not None:
+ l = self.length_from(pkt)
+ elif self.count_from is not None:
+ c = self.count_from(pkt)
+
+ lst = []
+ ret = b""
+ remain = s
+ if l is not None:
+ remain,ret = s[:l],s[l:]
+ while remain:
+ if c is not None:
+ if c <= 0:
+ break
+ c -= 1
+ addr = inet_ntop(socket.AF_INET6, remain[:16])
+ lst.append(addr)
+ remain = remain[16:]
+ return remain+ret,lst
+
+ def i2m(self, pkt, x):
+ s = b''
+ for y in x:
+ try:
+ y = inet_pton(socket.AF_INET6, y)
+ except:
+ y = socket.getaddrinfo(y, None, socket.AF_INET6)[0][-1][0]
+ y = inet_pton(socket.AF_INET6, y)
+ s += y
+ return s
+
+ def i2repr(self,pkt,x):
+ s = []
+ if x == None:
+ return "[]"
+ for y in x:
+ s.append('%s' % y)
+ return "[ %s ]" % (", ".join(s))
+
+class _IPv6GuessPayload:
+ name = "Dummy class that implements guess_payload_class() for IPv6"
+ def default_payload_class(self,p):
+ if self.nh == 58: # ICMPv6
+ #t = ord(p[0])
+ t = p[0]
+ if len(p) > 2 and t == 139 or t == 140: # Node Info Query
+ return _niquery_guesser(p)
+ if len(p) >= icmp6typesminhdrlen.get(t, sys.maxsize): # Other ICMPv6 messages
+ return get_cls(icmp6typescls.get(t,"Raw"), "Raw")
+ return Raw
+ elif self.nh == 135 and len(p) > 3: # Mobile IPv6
+ #return _mip6_mhtype2cls.get(ord(p[2]), MIP6MH_Generic)
+ return _mip6_mhtype2cls.get(p[2], MIP6MH_Generic)
+ else:
+ return get_cls(ipv6nhcls.get(self.nh,"Raw"), "Raw")
+
+class IPv6(_IPv6GuessPayload, Packet, IPTools):
+ name = "IPv6"
+ fields_desc = [ BitField("version" , 6 , 4),
+ BitField("tc", 0, 8), #TODO: IPv6, ByteField ?
+ BitField("fl", 0, 20),
+ ShortField("plen", None),
+ ByteEnumField("nh", 59, ipv6nh),
+ ByteField("hlim", 64),
+ IP6Field("src", "::2"),
+ #SourceIP6Field("src", "dst"), # dst is for src @ selection
+ IP6Field("dst", "::1") ]
+
+ def route(self):
+ dst = self.dst
+ if isinstance(dst,Gen):
+ dst = next(iter(dst))
+ return conf.route6.route(dst)
+
+ def mysummary(self):
+ return "%s > %s (%i)" % (self.src,self.dst, self.nh)
+
+ def post_build(self, p, pay):
+ p += pay
+ if self.plen is None:
+ l = len(p) - 40
+ p = p[:4]+struct.pack("!H", l)+p[6:]
+ return p
+
+ def extract_padding(self, s):
+ l = self.plen
+ return s[:l], s[l:]
+
+ def hashret(self):
+ if self.nh == 58 and isinstance(self.payload, _ICMPv6):
+ if self.payload.type < 128:
+ return self.payload.payload.hashret()
+ elif (self.payload.type in [133,134,135,136,144,145]):
+ return struct.pack("B", self.nh)+self.payload.hashret()
+
+ nh = self.nh
+ sd = self.dst
+ ss = self.src
+ if self.nh == 43 and isinstance(self.payload, IPv6ExtHdrRouting):
+ # With routing header, the destination is the last
+ # address of the IPv6 list if segleft > 0
+ nh = self.payload.nh
+ try:
+ sd = self.addresses[-1]
+ except IndexError:
+ sd = '::1'
+ # TODO: big bug with ICMPv6 error messages as the destination of IPerror6
+ # could be anything from the original list ...
+ if 1:
+ sd = inet_pton(socket.AF_INET6, sd)
+ for a in self.addresses:
+ a = inet_pton(socket.AF_INET6, a)
+ sd = strxor(sd, a)
+ sd = inet_ntop(socket.AF_INET6, sd)
+
+ if self.nh == 44 and isinstance(self.payload, IPv6ExtHdrFragment):
+ nh = self.payload.nh
+
+ if self.nh == 0 and isinstance(self.payload, IPv6ExtHdrHopByHop):
+ nh = self.payload.nh
+
+ if self.nh == 60 and isinstance(self.payload, IPv6ExtHdrDestOpt):
+ foundhao = None
+ for o in self.payload.options:
+ if isinstance(o, HAO):
+ foundhao = o
+ if foundhao:
+ nh = self.payload.nh # XXX what if another extension follows ?
+ ss = foundhao.hoa
+
+ if conf.checkIPsrc and conf.checkIPaddr:
+ sd = inet_pton(socket.AF_INET6, sd)
+ ss = inet_pton(socket.AF_INET6, self.src)
+ return struct.pack("B",nh)+self.payload.hashret()
+ else:
+ return struct.pack("B", nh)+self.payload.hashret()
+
+ def answers(self, other):
+ if not isinstance(other, IPv6): # self is reply, other is request
+ return False
+ if conf.checkIPaddr:
+ ss = inet_pton(socket.AF_INET6, self.src)
+ sd = inet_pton(socket.AF_INET6, self.dst)
+ os = inet_pton(socket.AF_INET6, other.src)
+ od = inet_pton(socket.AF_INET6, other.dst)
+ # request was sent to a multicast address (other.dst)
+ # Check reply destination addr matches request source addr (i.e
+ # sd == os) except when reply is multicasted too
+ # XXX test mcast scope matching ?
+ if in6_ismaddr(other.dst):
+ if in6_ismaddr(self.dst):
+ if ((od == sd) or
+ (in6_isaddrllallnodes(self.dst) and in6_isaddrllallservers(other.dst))):
+ return self.payload.answers(other.payload)
+ return False
+ if (os == sd):
+ return self.payload.answers(other.payload)
+ return False
+ elif (sd != os): # or ss != od): <- removed for ICMP errors
+ return False
+ if self.nh == 58 and isinstance(self.payload, _ICMPv6) and self.payload.type < 128:
+ # ICMPv6 Error message -> generated by IPv6 packet
+ # Note : at the moment, we jump the ICMPv6 specific class
+ # to call answers() method of erroneous packet (over
+ # initial packet). There can be cases where an ICMPv6 error
+ # class could implement a specific answers method that perform
+ # a specific task. Currently, don't see any use ...
+ return self.payload.payload.answers(other)
+ elif other.nh == 0 and isinstance(other.payload, IPv6ExtHdrHopByHop):
+ return self.payload.answers(other.payload.payload)
+ elif other.nh == 44 and isinstance(other.payload, IPv6ExtHdrFragment):
+ return self.payload.answers(other.payload.payload)
+ elif other.nh == 43 and isinstance(other.payload, IPv6ExtHdrRouting):
+ return self.payload.answers(other.payload.payload) # Buggy if self.payload is a IPv6ExtHdrRouting
+ elif other.nh == 60 and isinstance(other.payload, IPv6ExtHdrDestOpt):
+ return self.payload.payload.answers(other.payload.payload)
+ elif self.nh == 60 and isinstance(self.payload, IPv6ExtHdrDestOpt): # BU in reply to BRR, for instance
+ return self.payload.payload.answers(other.payload)
+ else:
+ if (self.nh != other.nh):
+ return False
+ return self.payload.answers(other.payload)
+
+
+conf.neighbor.register_l3(Ether, IPv6, lambda l2,l3: getmacbyip6(l3.dst))
+
+
+class IPerror6(IPv6):
+ name = "IPv6 in ICMPv6"
+ def answers(self, other):
+ if not isinstance(other, IPv6):
+ return False
+ sd = inet_pton(socket.AF_INET6, self.dst)
+ ss = inet_pton(socket.AF_INET6, self.src)
+ od = inet_pton(socket.AF_INET6, other.dst)
+ os = inet_pton(socket.AF_INET6, other.src)
+
+ # Make sure that the ICMPv6 error is related to the packet scapy sent
+ if isinstance(self.underlayer, _ICMPv6) and self.underlayer.type < 128:
+
+ # find upper layer for self (possible citation)
+ selfup = self.payload
+ while selfup is not None and isinstance(selfup, _IPv6ExtHdr):
+ selfup = selfup.payload
+
+ # find upper layer for other (initial packet). Also look for RH
+ otherup = other.payload
+ request_has_rh = False
+ while otherup is not None and isinstance(otherup, _IPv6ExtHdr):
+ if isinstance(otherup, IPv6ExtHdrRouting):
+ request_has_rh = True
+ otherup = otherup.payload
+
+ if ((ss == os and sd == od) or # <- Basic case
+ (ss == os and request_has_rh)): # <- Request has a RH :
+ # don't check dst address
+
+ # Let's deal with possible MSS Clamping
+ if (isinstance(selfup, TCP) and
+ isinstance(otherup, TCP) and
+ selfup.options != otherup.options): # seems clamped
+
+ # Save fields modified by MSS clamping
+ old_otherup_opts = otherup.options
+ old_otherup_cksum = otherup.chksum
+ old_otherup_dataofs = otherup.dataofs
+ old_selfup_opts = selfup.options
+ old_selfup_cksum = selfup.chksum
+ old_selfup_dataofs = selfup.dataofs
+
+ # Nullify them
+ otherup.options = []
+ otherup.chksum = 0
+ otherup.dataofs = 0
+ selfup.options = []
+ selfup.chksum = 0
+ selfup.dataofs = 0
+
+ # Test it and save result
+ s1 = bytes(selfup)
+ s2 = bytes(otherup)
+ l = min(len(s1), len(s2))
+ res = s1[:l] == s2[:l]
+
+ # recall saved values
+ otherup.options = old_otherup_opts
+ otherup.chksum = old_otherup_cksum
+ otherup.dataofs = old_otherup_dataofs
+ selfup.options = old_selfup_opts
+ selfup.chksum = old_selfup_cksum
+ selfup.dataofs = old_selfup_dataofs
+
+ return res
+
+ s1 = bytes(selfup)
+ s2 = bytes(otherup)
+ l = min(len(s1), len(s2))
+ return s1[:l] == s2[:l]
+
+ return False
+
+ def mysummary(self):
+ return Packet.mysummary(self)
+
+
+#############################################################################
+#############################################################################
+### Upper Layer Checksum computation ###
+#############################################################################
+#############################################################################
+
+class PseudoIPv6(Packet): # IPv6 Pseudo-header for checksum computation
+ name = "Pseudo IPv6 Header"
+ fields_desc = [ IP6Field("src", "::"),
+ IP6Field("dst", "::"),
+ ShortField("uplen", None),
+ BitField("zero", 0, 24),
+ ByteField("nh", 0) ]
+
+def in6_chksum(nh, u, p):
+ """
+ Performs IPv6 Upper Layer checksum computation. Provided parameters are:
+
+ - 'nh' : value of upper layer protocol
+ - 'u' : upper layer instance (TCP, UDP, ICMPv6*, ). Instance must be
+ provided with all under layers (IPv6 and all extension headers,
+ for example)
+ - 'p' : the payload of the upper layer provided as a string
+
+ Functions operate by filling a pseudo header class instance (PseudoIPv6)
+ with
+ - Next Header value
+ - the address of _final_ destination (if some Routing Header with non
+ segleft field is present in underlayer classes, last address is used.)
+ - the address of _real_ source (basically the source address of an
+ IPv6 class instance available in the underlayer or the source address
+ in HAO option if some Destination Option header found in underlayer
+ includes this option).
+ - the length is the length of provided payload string ('p')
+ """
+
+ ph6 = PseudoIPv6()
+ ph6.nh = nh
+ rthdr = 0
+ hahdr = 0
+ final_dest_addr_found = 0
+ while u != None and not isinstance(u, IPv6):
+ if (isinstance(u, IPv6ExtHdrRouting) and
+ u.segleft != 0 and len(u.addresses) != 0 and
+ final_dest_addr_found == 0):
+ rthdr = u.addresses[-1]
+ final_dest_addr_found = 1
+ elif (isinstance(u, IPv6ExtHdrDestOpt) and (len(u.options) == 1) and
+ isinstance(u.options[0], HAO)):
+ hahdr = u.options[0].hoa
+ u = u.underlayer
+ if u is None:
+ warning("No IPv6 underlayer to compute checksum. Leaving null.")
+ return 0
+ if hahdr:
+ ph6.src = hahdr
+ else:
+ ph6.src = u.src
+ if rthdr:
+ ph6.dst = rthdr
+ else:
+ ph6.dst = u.dst
+ ph6.uplen = len(p)
+ ph6s = bytes(ph6)
+ return checksum(ph6s+p)
+
+
+#############################################################################
+#############################################################################
+### Extension Headers ###
+#############################################################################
+#############################################################################
+
+
+# Inherited by all extension header classes
+class _IPv6ExtHdr(_IPv6GuessPayload, Packet):
+ name = 'Abstract IPV6 Option Header'
+ aliastypes = [IPv6, IPerror6] # TODO ...
+
+
+#################### IPv6 options for Extension Headers #####################
+
+_hbhopts = { 0x00: "Pad1",
+ 0x01: "PadN",
+ 0x04: "Tunnel Encapsulation Limit",
+ 0x05: "Router Alert",
+ 0x06: "Quick-Start",
+ 0xc2: "Jumbo Payload",
+ 0xc9: "Home Address Option" }
+
+class _OTypeField(ByteEnumField):
+ """
+ Modified BytEnumField that displays information regarding the IPv6 option
+ based on its option type value (What should be done by nodes that process
+ the option if they do not understand it ...)
+
+ It is used by Jumbo, Pad1, PadN, RouterAlert, HAO options
+ """
+ pol = {0x00: "00: skip",
+ 0x40: "01: discard",
+ 0x80: "10: discard+ICMP",
+ 0xC0: "11: discard+ICMP not mcast"}
+
+ enroutechange = {0x00: "0: Don't change en-route",
+ 0x20: "1: May change en-route" }
+
+ def i2repr(self, pkt, x):
+ s = self.i2s.get(x, repr(x))
+ polstr = self.pol[(x & 0xC0)]
+ enroutechangestr = self.enroutechange[(x & 0x20)]
+ return "%s [%s, %s]" % (s, polstr, enroutechangestr)
+
+class HBHOptUnknown(Packet): # IPv6 Hop-By-Hop Option
+ name = "Scapy6 Unknown Option"
+ fields_desc = [_OTypeField("otype", 0x01, _hbhopts),
+ FieldLenField("optlen", None, length_of="optdata", fmt="B"),
+ StrLenField("optdata", "",
+ length_from = lambda pkt: pkt.optlen) ]
+ def alignment_delta(self, curpos): # By default, no alignment requirement
+ """
+ As specified in section 4.2 of RFC 2460, every options has
+ an alignment requirement ususally expressed xn+y, meaning
+ the Option Type must appear at an integer multiple of x octest
+ from the start of the header, plus y octet.
+
+ That function is provided the current position from the
+ start of the header and returns required padding length.
+ """
+ return 0
+
+class Pad1(Packet): # IPv6 Hop-By-Hop Option
+ name = "Pad1"
+ fields_desc = [ _OTypeField("otype", 0x00, _hbhopts) ]
+ def alignment_delta(self, curpos): # No alignment requirement
+ return 0
+
+class PadN(Packet): # IPv6 Hop-By-Hop Option
+ name = "PadN"
+ fields_desc = [_OTypeField("otype", 0x01, _hbhopts),
+ FieldLenField("optlen", None, length_of="optdata", fmt="B"),
+ StrLenField("optdata", "",
+ length_from = lambda pkt: pkt.optlen)]
+ def alignment_delta(self, curpos): # No alignment requirement
+ return 0
+
+class RouterAlert(Packet): # RFC 2711 - IPv6 Hop-By-Hop Option
+ name = "Router Alert"
+ fields_desc = [_OTypeField("otype", 0x05, _hbhopts),
+ ByteField("optlen", 2),
+ ShortEnumField("value", None,
+ { 0: "Datagram contains a MLD message",
+ 1: "Datagram contains RSVP message",
+ 2: "Datagram contains an Active Network message" }) ]
+ # TODO : Check IANA has not defined new values for value field of RouterAlertOption
+ # TODO : now that we have that option, we should do something in MLD class that need it
+ def alignment_delta(self, curpos): # alignment requirement : 2n+0
+ x = 2 ; y = 0
+ delta = x*((curpos - y + x - 1)//x) + y - curpos
+ return delta
+
+class Jumbo(Packet): # IPv6 Hop-By-Hop Option
+ name = "Jumbo Payload"
+ fields_desc = [_OTypeField("otype", 0xC2, _hbhopts),
+ ByteField("optlen", 4),
+ IntField("jumboplen", None) ]
+ def alignment_delta(self, curpos): # alignment requirement : 4n+2
+ x = 4 ; y = 2
+ delta = x*((curpos - y + x - 1)//x) + y - curpos
+ return delta
+
+class HAO(Packet): # IPv6 Destination Options Header Option
+ name = "Home Address Option"
+ fields_desc = [_OTypeField("otype", 0xC9, _hbhopts),
+ ByteField("optlen", 16),
+ IP6Field("hoa", "::") ]
+ def alignment_delta(self, curpos): # alignment requirement : 8n+6
+ x = 8 ; y = 6
+ delta = x*((curpos - y + x - 1)//x) + y - curpos
+ return delta
+
+_hbhoptcls = { 0x00: Pad1,
+ 0x01: PadN,
+ 0x05: RouterAlert,
+ 0xC2: Jumbo,
+ 0xC9: HAO }
+
+
+######################## Hop-by-Hop Extension Header ########################
+
+class _HopByHopOptionsField(PacketListField):
+ islist = 1
+ holds_packet = 1
+ def __init__(self, name, default, cls, curpos, count_from=None, length_from=None):
+ self.curpos = curpos
+ PacketListField.__init__(self, name, default, cls, count_from=count_from, length_from=length_from)
+
+ def i2len(self, pkt, i):
+ l = len(self.i2m(pkt, i))
+ return l
+
+ def i2count(self, pkt, i):
+ if type(i) is list:
+ return len(i)
+ return 0
+
+ def getfield(self, pkt, s):
+ c = l = None
+ if self.length_from is not None:
+ l = self.length_from(pkt)
+ elif self.count_from is not None:
+ c = self.count_from(pkt)
+
+ opt = []
+ ret = b""
+ x = s
+ if l is not None:
+ x,ret = s[:l],s[l:]
+ while x:
+ if c is not None:
+ if c <= 0:
+ break
+ c -= 1
+ #o = ord(x[0]) # Option type
+ o = x[0] # Option type
+ cls = self.cls
+ if o in _hbhoptcls:
+ cls = _hbhoptcls[o]
+ try:
+ op = cls(x)
+ except:
+ op = self.cls(x)
+ opt.append(op)
+ if isinstance(op.payload, conf.raw_layer):
+ x = op.payload.load
+ del(op.payload)
+ else:
+ x = b""
+ return x+ret,opt
+
+ def i2m(self, pkt, x):
+ autopad = None
+ try:
+ autopad = getattr(pkt, "autopad") # Hack : 'autopad' phantom field
+ except:
+ autopad = 1
+
+ if not autopad:
+ return b"".join(map(bytes, x))
+
+ curpos = self.curpos
+ s = b""
+ for p in x:
+ d = p.alignment_delta(curpos)
+ curpos += d
+ if d == 1:
+ s += bytes(Pad1())
+ elif d != 0:
+ s += bytes(PadN(optdata=b'\x00'*(d-2)))
+ pstr = bytes(p)
+ curpos += len(pstr)
+ s += pstr
+
+ # Let's make the class including our option field
+ # a multiple of 8 octets long
+ d = curpos % 8
+ if d == 0:
+ return s
+ d = 8 - d
+ if d == 1:
+ s += bytes(Pad1())
+ elif d != 0:
+ s += bytes(PadN(optdata=b'\x00'*(d-2)))
+
+ return s
+
+ def addfield(self, pkt, s, val):
+ return s+self.i2m(pkt, val)
+
+class _PhantomAutoPadField(ByteField):
+ def addfield(self, pkt, s, val):
+ return s
+
+ def getfield(self, pkt, s):
+ return s, 1
+
+ def i2repr(self, pkt, x):
+ if x:
+ return "On"
+ return "Off"
+
+
+class IPv6ExtHdrHopByHop(_IPv6ExtHdr):
+ name = "IPv6 Extension Header - Hop-by-Hop Options Header"
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+ FieldLenField("len", None, length_of="options", fmt="B",
+ adjust = lambda pkt,x: (x+2+7)//8 - 1),
+ _PhantomAutoPadField("autopad", 1), # autopad activated by default
+ _HopByHopOptionsField("options", [], HBHOptUnknown, 2,
+ length_from = lambda pkt: (8*(pkt.len+1))-2) ]
+ overload_fields = {IPv6: { "nh": 0 }}
+
+
+######################## Destination Option Header ##########################
+
+class IPv6ExtHdrDestOpt(_IPv6ExtHdr):
+ name = "IPv6 Extension Header - Destination Options Header"
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+ FieldLenField("len", None, length_of="options", fmt="B",
+ adjust = lambda pkt,x: (x+2+7)//8 - 1),
+ _PhantomAutoPadField("autopad", 1), # autopad activated by default
+ _HopByHopOptionsField("options", [], HBHOptUnknown, 2,
+ length_from = lambda pkt: (8*(pkt.len+1))-2) ]
+ overload_fields = {IPv6: { "nh": 60 }}
+
+
+############################# Routing Header ################################
+
+class IPv6ExtHdrRouting(_IPv6ExtHdr):
+ name = "IPv6 Option Header Routing"
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+ FieldLenField("len", None, count_of="addresses", fmt="B",
+ adjust = lambda pkt,x:2*x), # in 8 bytes blocks
+ ByteField("type", 0),
+ ByteField("segleft", None),
+ BitField("reserved", 0, 32), # There is meaning in this field ...
+ IP6ListField("addresses", [],
+ length_from = lambda pkt: 8*pkt.len)]
+ overload_fields = {IPv6: { "nh": 43 }}
+
+ def post_build(self, pkt, pay):
+ if self.segleft is None:
+ pkt = pkt[:3]+struct.pack("B", len(self.addresses))+pkt[4:]
+ return _IPv6ExtHdr.post_build(self, pkt, pay)
+
+########################### Fragmentation Header ############################
+
+class IPv6ExtHdrFragment(_IPv6ExtHdr):
+ name = "IPv6 Extension Header - Fragmentation header"
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+ BitField("res1", 0, 8),
+ BitField("offset", 0, 13),
+ BitField("res2", 0, 2),
+ BitField("m", 0, 1),
+ IntField("id", None) ]
+ overload_fields = {IPv6: { "nh": 44 }}
+
+
+def defragment6(pktlist):
+ """
+ Performs defragmentation of a list of IPv6 packets. Packets are reordered.
+ Crap is dropped. What lacks is completed by 'X' characters.
+ """
+
+ l = [ x for x in pktlist if IPv6ExtHdrFragment in x ] # remove non fragments
+ if not l:
+ return []
+
+ id = l[0][IPv6ExtHdrFragment].id
+
+ llen = len(l)
+ l = [ x for x in l if x[IPv6ExtHdrFragment].id == id ]
+ if len(l) != llen:
+ warning("defragment6: some fragmented packets have been removed from list")
+ llen = len(l)
+
+ # reorder fragments
+ i = 0
+ res = []
+ while l:
+ min_pos = 0
+ min_offset = l[0][IPv6ExtHdrFragment].offset
+ for p in l:
+ cur_offset = p[IPv6ExtHdrFragment].offset
+ if cur_offset < min_offset:
+ min_pos = 0
+ min_offset = cur_offset
+ res.append(l[min_pos])
+ del(l[min_pos])
+
+ # regenerate the fragmentable part
+ fragmentable = b""
+ for p in res:
+ q=p[IPv6ExtHdrFragment]
+ offset = 8*q.offset
+ if offset != len(fragmentable):
+ warning("Expected an offset of %d. Found %d. Padding with XXXX" % (len(fragmentable), offset))
+ fragmentable += b"X"*(offset - len(fragmentable))
+ fragmentable += bytes(q.payload)
+
+ # Regenerate the unfragmentable part.
+ q = res[0]
+ nh = q[IPv6ExtHdrFragment].nh
+ q[IPv6ExtHdrFragment].underlayer.nh = nh
+ q[IPv6ExtHdrFragment].underlayer.payload = None
+ q /= conf.raw_layer(load=fragmentable)
+
+ return IPv6(bytes(q))
+
+
+def fragment6(pkt, fragSize):
+ """
+ Performs fragmentation of an IPv6 packet. Provided packet ('pkt') must already
+ contain an IPv6ExtHdrFragment() class. 'fragSize' argument is the expected
+ maximum size of fragments (MTU). The list of packets is returned.
+
+ If packet does not contain an IPv6ExtHdrFragment class, it is returned in
+ result list.
+ """
+
+ pkt = pkt.copy()
+
+ if not IPv6ExtHdrFragment in pkt:
+ # TODO : automatically add a fragment before upper Layer
+ # at the moment, we do nothing and return initial packet
+ # as single element of a list
+ return [pkt]
+
+ # If the payload is bigger than 65535, a Jumbo payload must be used, as
+ # an IPv6 packet can't be bigger than 65535 bytes.
+ if len(bytes(pkt[IPv6ExtHdrFragment])) > 65535:
+ warning("An IPv6 packet can'be bigger than 65535, please use a Jumbo payload.")
+ return []
+
+ s = bytes(pkt) # for instantiation to get upper layer checksum right
+
+ if len(s) <= fragSize:
+ return [pkt]
+
+ # Fragmentable part : fake IPv6 for Fragmentable part length computation
+ fragPart = pkt[IPv6ExtHdrFragment].payload
+ tmp = bytes(IPv6(src="::1", dst="::1")/fragPart)
+ fragPartLen = len(tmp) - 40 # basic IPv6 header length
+ fragPartStr = s[-fragPartLen:]
+
+ # Grab Next Header for use in Fragment Header
+ nh = IPv6(tmp[:40]).nh
+
+ # Keep fragment header
+ fragHeader = pkt[IPv6ExtHdrFragment]
+ fragHeader.payload = None # detach payload
+
+ # Unfragmentable Part
+ unfragPartLen = len(s) - fragPartLen - 8
+ unfragPart = pkt
+ pkt[IPv6ExtHdrFragment].underlayer.payload = None # detach payload
+
+ # Cut the fragmentable part to fit fragSize. Inner fragments have
+ # a length that is an integer multiple of 8 octets. last Frag MTU
+ # can be anything below MTU
+ lastFragSize = fragSize - unfragPartLen - 8
+ innerFragSize = lastFragSize - (lastFragSize % 8)
+
+ if lastFragSize <= 0 or innerFragSize == 0:
+ warning("Provided fragment size value is too low. " +
+ "Should be more than %d" % (unfragPartLen + 8))
+ return [unfragPart/fragHeader/fragPart]
+
+ remain = fragPartStr
+ res = []
+ fragOffset = 0 # offset, incremeted during creation
+ fragId = random.randint(0,0xffffffff) # random id ...
+ if fragHeader.id is not None: # ... except id provided by user
+ fragId = fragHeader.id
+ fragHeader.m = 1
+ fragHeader.id = fragId
+ fragHeader.nh = nh
+
+ # Main loop : cut, fit to FRAGSIZEs, fragOffset, Id ...
+ while True:
+ if (len(remain) > lastFragSize):
+ tmp = remain[:innerFragSize]
+ remain = remain[innerFragSize:]
+ fragHeader.offset = fragOffset # update offset
+ fragOffset += (innerFragSize // 8) # compute new one
+ if IPv6 in unfragPart:
+ unfragPart[IPv6].plen = None
+ tempo = unfragPart/fragHeader/conf.raw_layer(load=tmp)
+ res.append(tempo)
+ else:
+ fragHeader.offset = fragOffset # update offSet
+ fragHeader.m = 0
+ if IPv6 in unfragPart:
+ unfragPart[IPv6].plen = None
+ tempo = unfragPart/fragHeader/conf.raw_layer(load=remain)
+ res.append(tempo)
+ break
+ return res
+
+
+############################### AH Header ###################################
+
+# class _AHFieldLenField(FieldLenField):
+# def getfield(self, pkt, s):
+# l = getattr(pkt, self.fld)
+# l = (l*8)-self.shift
+# i = self.m2i(pkt, s[:l])
+# return s[l:],i
+
+# class _AHICVStrLenField(StrLenField):
+# def i2len(self, pkt, x):
+
+
+
+# class IPv6ExtHdrAH(_IPv6ExtHdr):
+# name = "IPv6 Extension Header - AH"
+# fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+# _AHFieldLenField("len", None, "icv"),
+# ShortField("res", 0),
+# IntField("spi", 0),
+# IntField("sn", 0),
+# _AHICVStrLenField("icv", None, "len", shift=2) ]
+# overload_fields = {IPv6: { "nh": 51 }}
+
+# def post_build(self, pkt, pay):
+# if self.len is None:
+# pkt = pkt[0]+struct.pack("!B", 2*len(self.addresses))+pkt[2:]
+# if self.segleft is None:
+# pkt = pkt[:3]+struct.pack("!B", len(self.addresses))+pkt[4:]
+# return _IPv6ExtHdr.post_build(self, pkt, pay)
+
+
+############################### ESP Header ##################################
+
+# class IPv6ExtHdrESP(_IPv6extHdr):
+# name = "IPv6 Extension Header - ESP"
+# fields_desc = [ IntField("spi", 0),
+# IntField("sn", 0),
+# # there is things to extract from IKE work
+# ]
+# overloads_fields = {IPv6: { "nh": 50 }}
+
+
+
+#############################################################################
+#############################################################################
+### ICMPv6* Classes ###
+#############################################################################
+#############################################################################
+
+icmp6typescls = { 1: "ICMPv6DestUnreach",
+ 2: "ICMPv6PacketTooBig",
+ 3: "ICMPv6TimeExceeded",
+ 4: "ICMPv6ParamProblem",
+ 128: "ICMPv6EchoRequest",
+ 129: "ICMPv6EchoReply",
+ 130: "ICMPv6MLQuery",
+ 131: "ICMPv6MLReport",
+ 132: "ICMPv6MLDone",
+ 133: "ICMPv6ND_RS",
+ 134: "ICMPv6ND_RA",
+ 135: "ICMPv6ND_NS",
+ 136: "ICMPv6ND_NA",
+ 137: "ICMPv6ND_Redirect",
+ #138: Do Me - RFC 2894 - Seems painful
+ 139: "ICMPv6NIQuery",
+ 140: "ICMPv6NIReply",
+ 141: "ICMPv6ND_INDSol",
+ 142: "ICMPv6ND_INDAdv",
+ #143: Do Me - RFC 3810
+ 144: "ICMPv6HAADRequest",
+ 145: "ICMPv6HAADReply",
+ 146: "ICMPv6MPSol",
+ 147: "ICMPv6MPAdv",
+ #148: Do Me - SEND related - RFC 3971
+ #149: Do Me - SEND related - RFC 3971
+ 151: "ICMPv6MRD_Advertisement",
+ 152: "ICMPv6MRD_Solicitation",
+ 153: "ICMPv6MRD_Termination",
+ }
+
+icmp6typesminhdrlen = { 1: 8,
+ 2: 8,
+ 3: 8,
+ 4: 8,
+ 128: 8,
+ 129: 8,
+ 130: 24,
+ 131: 24,
+ 132: 24,
+ 133: 8,
+ 134: 16,
+ 135: 24,
+ 136: 24,
+ 137: 40,
+ #139:
+ #140
+ 141: 8,
+ 142: 8,
+ 144: 8,
+ 145: 8,
+ 146: 8,
+ 147: 8,
+ 151: 8,
+ 152: 4,
+ 153: 4
+ }
+
+icmp6types = { 1 : "Destination unreachable",
+ 2 : "Packet too big",
+ 3 : "Time exceeded",
+ 4 : "Parameter problem",
+ 100 : "Private Experimentation",
+ 101 : "Private Experimentation",
+ 128 : "Echo Request",
+ 129 : "Echo Reply",
+ 130 : "MLD Query",
+ 131 : "MLD Report",
+ 132 : "MLD Done",
+ 133 : "Router Solicitation",
+ 134 : "Router Advertisement",
+ 135 : "Neighbor Solicitation",
+ 136 : "Neighbor Advertisement",
+ 137 : "Redirect Message",
+ 138 : "Router Renumbering",
+ 139 : "ICMP Node Information Query",
+ 140 : "ICMP Node Information Response",
+ 141 : "Inverse Neighbor Discovery Solicitation Message",
+ 142 : "Inverse Neighbor Discovery Advertisement Message",
+ 143 : "Version 2 Multicast Listener Report",
+ 144 : "Home Agent Address Discovery Request Message",
+ 145 : "Home Agent Address Discovery Reply Message",
+ 146 : "Mobile Prefix Solicitation",
+ 147 : "Mobile Prefix Advertisement",
+ 148 : "Certification Path Solicitation",
+ 149 : "Certification Path Advertisement",
+ 151 : "Multicast Router Advertisement",
+ 152 : "Multicast Router Solicitation",
+ 153 : "Multicast Router Termination",
+ 200 : "Private Experimentation",
+ 201 : "Private Experimentation" }
+
+
+class _ICMPv6(Packet):
+ name = "ICMPv6 dummy class"
+ overload_fields = {IPv6: {"nh": 58}}
+ def post_build(self, p, pay):
+ p += pay
+ if self.cksum == None:
+ chksum = in6_chksum(58, self.underlayer, p)
+ p = p[:2]+struct.pack("!H", chksum)+p[4:]
+ return p
+
+ def hashret(self):
+ return self.payload.hashret()
+
+ def answers(self, other):
+ # isinstance(self.underlayer, _IPv6ExtHdr) may introduce a bug ...
+ if (isinstance(self.underlayer, IPerror6) or
+ isinstance(self.underlayer, _IPv6ExtHdr) and
+ isinstance(other, _ICMPv6)):
+ if not ((self.type == other.type) and
+ (self.code == other.code)):
+ return 0
+ return 1
+ return 0
+
+
+class _ICMPv6Error(_ICMPv6):
+ name = "ICMPv6 errors dummy class"
+ def guess_payload_class(self,p):
+ return IPerror6
+
+class ICMPv6Unknown(_ICMPv6):
+ name = "Scapy6 ICMPv6 fallback class"
+ fields_desc = [ ByteEnumField("type",1, icmp6types),
+ ByteField("code",0),
+ XShortField("cksum", None),
+ StrField("msgbody", "")]
+
+
+################################## RFC 2460 #################################
+
+class ICMPv6DestUnreach(_ICMPv6Error):
+ name = "ICMPv6 Destination Unreachable"
+ fields_desc = [ ByteEnumField("type",1, icmp6types),
+ ByteEnumField("code",0, { 0: "No route to destination",
+ 1: "Communication with destination administratively prohibited",
+ 2: "Beyond scope of source address",
+ 3: "Address unreachable",
+ 4: "Port unreachable" }),
+ XShortField("cksum", None),
+ XIntField("unused",0x00000000)]
+
+class ICMPv6PacketTooBig(_ICMPv6Error):
+ name = "ICMPv6 Packet Too Big"
+ fields_desc = [ ByteEnumField("type",2, icmp6types),
+ ByteField("code",0),
+ XShortField("cksum", None),
+ IntField("mtu",1280)]
+
+class ICMPv6TimeExceeded(_ICMPv6Error):
+ name = "ICMPv6 Time Exceeded"
+ fields_desc = [ ByteEnumField("type",3, icmp6types),
+ ByteEnumField("code",0, { 0: "hop limit exceeded in transit",
+ 1: "fragment reassembly time exceeded"}),
+ XShortField("cksum", None),
+ XIntField("unused",0x00000000)]
+
+# The default pointer value is set to the next header field of
+# the encapsulated IPv6 packet
+class ICMPv6ParamProblem(_ICMPv6Error):
+ name = "ICMPv6 Parameter Problem"
+ fields_desc = [ ByteEnumField("type",4, icmp6types),
+ ByteEnumField("code",0, {0: "erroneous header field encountered",
+ 1: "unrecognized Next Header type encountered",
+ 2: "unrecognized IPv6 option encountered"}),
+ XShortField("cksum", None),
+ IntField("ptr",6)]
+
+class ICMPv6EchoRequest(_ICMPv6):
+ name = "ICMPv6 Echo Request"
+ fields_desc = [ ByteEnumField("type", 128, icmp6types),
+ ByteField("code", 0),
+ XShortField("cksum", None),
+ XShortField("id",0),
+ XShortField("seq",0),
+ StrField("data", "")]
+ def mysummary(self):
+ return self.sprintf("%name% (id: %id% seq: %seq%)")
+ def hashret(self):
+ return struct.pack("HH",self.id,self.seq)+self.payload.hashret()
+
+
+class ICMPv6EchoReply(ICMPv6EchoRequest):
+ name = "ICMPv6 Echo Reply"
+ type = 129
+ def answers(self, other):
+ # We could match data content between request and reply.
+ return (isinstance(other, ICMPv6EchoRequest) and
+ self.id == other.id and self.seq == other.seq and
+ self.data == other.data)
+
+
+############ ICMPv6 Multicast Listener Discovery (RFC3810) ##################
+
+# tous les messages MLD sont emis avec une adresse source lien-locale
+# -> Y veiller dans le post_build si aucune n'est specifiee
+# La valeur de Hop-Limit doit etre de 1
+# "and an IPv6 Router Alert option in a Hop-by-Hop Options
+# header. (The router alert option is necessary to cause routers to
+# examine MLD messages sent to multicast addresses in which the router
+# itself has no interest"
+class _ICMPv6ML(_ICMPv6):
+ fields_desc = [ ByteEnumField("type", 130, icmp6types),
+ ByteField("code", 0),
+ XShortField("cksum", None),
+ ShortField("mrd", 0),
+ ShortField("reserved", 0),
+ IP6Field("mladdr","::")]
+
+# general queries are sent to the link-scope all-nodes multicast
+# address ff02::1, with a multicast address field of 0 and a MRD of
+# [Query Response Interval]
+# Default value for mladdr is set to 0 for a General Query, and
+# overloaded by the user for a Multicast Address specific query
+# TODO : See what we can do to automatically include a Router Alert
+# Option in a Destination Option Header.
+class ICMPv6MLQuery(_ICMPv6ML): # RFC 2710
+ name = "MLD - Multicast Listener Query"
+ type = 130
+ mrd = 10000
+ mladdr = "::" # 10s for mrd
+ overload_fields = {IPv6: { "dst": "ff02::1", "hlim": 1, "nh": 58 }}
+ def hashret(self):
+ if self.mladdr != "::":
+ return struct.pack("HH",self.mladdr)+self.payload.hashret()
+ else:
+ return self.payload.hashret()
+
+
+# TODO : See what we can do to automatically include a Router Alert
+# Option in a Destination Option Header.
+class ICMPv6MLReport(_ICMPv6ML): # RFC 2710
+ name = "MLD - Multicast Listener Report"
+ type = 131
+ overload_fields = {IPv6: {"hlim": 1, "nh": 58}}
+ # implementer le hashret et le answers
+
+# When a node ceases to listen to a multicast address on an interface,
+# it SHOULD send a single Done message to the link-scope all-routers
+# multicast address (FF02::2), carrying in its multicast address field
+# the address to which it is ceasing to listen
+# TODO : See what we can do to automatically include a Router Alert
+# Option in a Destination Option Header.
+class ICMPv6MLDone(_ICMPv6ML): # RFC 2710
+ name = "MLD - Multicast Listener Done"
+ type = 132
+ overload_fields = {IPv6: { "dst": "ff02::2", "hlim": 1, "nh": 58}}
+
+
+########## ICMPv6 MRD - Multicast Router Discovery (RFC 4286) ###############
+
+# TODO:
+# - 04/09/06 troglocan : find a way to automatically add a router alert
+# option for all MRD packets. This could be done in a specific
+# way when IPv6 is the under layer with some specific keyword
+# like 'exthdr'. This would allow to keep compatibility with
+# providing IPv6 fields to be overloaded in fields_desc.
+#
+# At the moment, if user inserts an IPv6 Router alert option
+# none of the IPv6 default values of IPv6 layer will be set.
+
+class ICMPv6MRD_Advertisement(_ICMPv6):
+ name = "ICMPv6 Multicast Router Discovery Advertisement"
+ fields_desc = [ByteEnumField("type", 151, icmp6types),
+ ByteField("advinter", 20),
+ XShortField("cksum", None),
+ ShortField("queryint", 0),
+ ShortField("robustness", 0)]
+ overload_fields = {IPv6: { "nh": 58, "hlim": 1, "dst": "ff02::2"}}
+ # IPv6 Router Alert requires manual inclusion
+ def extract_padding(self, s):
+ return s[:8], s[8:]
+
+class ICMPv6MRD_Solicitation(_ICMPv6):
+ name = "ICMPv6 Multicast Router Discovery Solicitation"
+ fields_desc = [ByteEnumField("type", 152, icmp6types),
+ ByteField("res", 0),
+ XShortField("cksum", None) ]
+ overload_fields = {IPv6: { "nh": 58, "hlim": 1, "dst": "ff02::2"}}
+ # IPv6 Router Alert requires manual inclusion
+ def extract_padding(self, s):
+ return s[:4], s[4:]
+
+class ICMPv6MRD_Termination(_ICMPv6):
+ name = "ICMPv6 Multicast Router Discovery Termination"
+ fields_desc = [ByteEnumField("type", 153, icmp6types),
+ ByteField("res", 0),
+ XShortField("cksum", None) ]
+ overload_fields = {IPv6: { "nh": 58, "hlim": 1, "dst": "ff02::6A"}}
+ # IPv6 Router Alert requires manual inclusion
+ def extract_padding(self, s):
+ return s[:4], s[4:]
+
+
+################### ICMPv6 Neighbor Discovery (RFC 2461) ####################
+
+icmp6ndopts = { 1: "Source Link-Layer Address",
+ 2: "Target Link-Layer Address",
+ 3: "Prefix Information",
+ 4: "Redirected Header",
+ 5: "MTU",
+ 6: "NBMA Shortcut Limit Option", # RFC2491
+ 7: "Advertisement Interval Option",
+ 8: "Home Agent Information Option",
+ 9: "Source Address List",
+ 10: "Target Address List",
+ 11: "CGA Option", # RFC 3971
+ 12: "RSA Signature Option", # RFC 3971
+ 13: "Timestamp Option", # RFC 3971
+ 14: "Nonce option", # RFC 3971
+ 15: "Trust Anchor Option", # RFC 3971
+ 16: "Certificate Option", # RFC 3971
+ 17: "IP Address Option", # RFC 4068
+ 18: "New Router Prefix Information Option", # RFC 4068
+ 19: "Link-layer Address Option", # RFC 4068
+ 20: "Neighbor Advertisement Acknowledgement Option",
+ 21: "CARD Request Option", # RFC 4065/4066/4067
+ 22: "CARD Reply Option", # RFC 4065/4066/4067
+ 23: "MAP Option", # RFC 4140
+ 24: "Route Information Option", # RFC 4191
+ 25: "Recusive DNS Server Option",
+ 26: "IPv6 Router Advertisement Flags Option"
+ }
+
+icmp6ndoptscls = { 1: "ICMPv6NDOptSrcLLAddr",
+ 2: "ICMPv6NDOptDstLLAddr",
+ 3: "ICMPv6NDOptPrefixInfo",
+ 4: "ICMPv6NDOptRedirectedHdr",
+ 5: "ICMPv6NDOptMTU",
+ 6: "ICMPv6NDOptShortcutLimit",
+ 7: "ICMPv6NDOptAdvInterval",
+ 8: "ICMPv6NDOptHAInfo",
+ 9: "ICMPv6NDOptSrcAddrList",
+ 10: "ICMPv6NDOptTgtAddrList",
+ #11: Do Me,
+ #12: Do Me,
+ #13: Do Me,
+ #14: Do Me,
+ #15: Do Me,
+ #16: Do Me,
+ 17: "ICMPv6NDOptIPAddr",
+ 18: "ICMPv6NDOptNewRtrPrefix",
+ 19: "ICMPv6NDOptLLA",
+ #18: Do Me,
+ #19: Do Me,
+ #20: Do Me,
+ #21: Do Me,
+ #22: Do Me,
+ 23: "ICMPv6NDOptMAP",
+ 24: "ICMPv6NDOptRouteInfo",
+ 25: "ICMPv6NDOptRDNSS",
+ 26: "ICMPv6NDOptEFA"
+ }
+
+class _ICMPv6NDGuessPayload:
+ name = "Dummy ND class that implements guess_payload_class()"
+ def guess_payload_class(self,p):
+ if len(p) > 1:
+ #return get_cls(icmp6ndoptscls.get(ord(p[0]),"Raw"), "Raw") # s/Raw/ICMPv6NDOptUnknown/g ?
+ return get_cls(icmp6ndoptscls.get(p[0],"Raw"), "Raw") # s/Raw/ICMPv6NDOptUnknown/g ?
+
+
+# Beginning of ICMPv6 Neighbor Discovery Options.
+
+class ICMPv6NDOptUnknown(_ICMPv6NDGuessPayload, Packet):
+ name = "ICMPv6 Neighbor Discovery Option - Scapy Unimplemented"
+ fields_desc = [ ByteField("type",None),
+ FieldLenField("len",None,length_of="data",fmt="B",
+ adjust = lambda pkt,x: x+2),
+ StrLenField("data","",
+ length_from = lambda pkt: pkt.len-2) ]
+
+# NOTE: len includes type and len field. Expressed in unit of 8 bytes
+# TODO: Revoir le coup du ETHER_ANY
+class ICMPv6NDOptSrcLLAddr(_ICMPv6NDGuessPayload, Packet):
+ name = "ICMPv6 Neighbor Discovery Option - Source Link-Layer Address"
+ fields_desc = [ ByteField("type", 1),
+ ByteField("len", 1),
+ MACField("lladdr", ETHER_ANY) ]
+ def mysummary(self):
+ return self.sprintf("%name% %lladdr%")
+
+class ICMPv6NDOptDstLLAddr(ICMPv6NDOptSrcLLAddr):
+ name = "ICMPv6 Neighbor Discovery Option - Destination Link-Layer Address"
+ type = 2
+
+class ICMPv6NDOptPrefixInfo(_ICMPv6NDGuessPayload, Packet):
+ name = "ICMPv6 Neighbor Discovery Option - Prefix Information"
+ fields_desc = [ ByteField("type",3),
+ ByteField("len",4),
+ ByteField("prefixlen",None),
+ BitField("L",1,1),
+ BitField("A",1,1),
+ BitField("R",0,1),
+ BitField("res1",0,5),
+ XIntField("validlifetime",0xffffffff),
+ XIntField("preferredlifetime",0xffffffff),
+ XIntField("res2",0x00000000),
+ IP6Field("prefix","::") ]
+ def mysummary(self):
+ return self.sprintf("%name% %prefix%")
+
+# TODO: We should also limit the size of included packet to something
+# like (initiallen - 40 - 2)
+class TruncPktLenField(PacketLenField):
+
+ def __init__(self, name, default, cls, cur_shift, length_from=None, shift=0):
+ PacketLenField.__init__(self, name, default, cls, length_from=length_from)
+ self.cur_shift = cur_shift
+
+ def getfield(self, pkt, s):
+ l = self.length_from(pkt)
+ i = self.m2i(pkt, s[:l])
+ return s[l:],i
+
+ def m2i(self, pkt, m):
+ s = None
+ try: # It can happen we have sth shorter than 40 bytes
+ s = self.cls(m)
+ except:
+ return conf.raw_layer(m)
+ return s
+
+ def i2m(self, pkt, x):
+ s = bytes(x)
+ l = len(s)
+ r = (l + self.cur_shift) % 8
+ l = l - r
+ return s[:l]
+
+ def i2len(self, pkt, i):
+ return len(self.i2m(pkt, i))
+
+
+# Faire un post_build pour le recalcul de la taille (en multiple de 8 octets)
+class ICMPv6NDOptRedirectedHdr(_ICMPv6NDGuessPayload, Packet):
+ name = "ICMPv6 Neighbor Discovery Option - Redirected Header"
+ fields_desc = [ ByteField("type",4),
+ FieldLenField("len", None, length_of="pkt", fmt="B",
+ adjust = lambda pkt,x:(x+8)//8),
+ StrFixedLenField("res", b"\x00"*6, 6),
+ TruncPktLenField("pkt", b"", IPv6, 8,
+ length_from = lambda pkt: 8*pkt.len-8) ]
+
+# See which value should be used for default MTU instead of 1280
+class ICMPv6NDOptMTU(_ICMPv6NDGuessPayload, Packet):
+ name = "ICMPv6 Neighbor Discovery Option - MTU"
+ fields_desc = [ ByteField("type",5),
+ ByteField("len",1),
+ XShortField("res",0),
+ IntField("mtu",1280)]
+
+class ICMPv6NDOptShortcutLimit(_ICMPv6NDGuessPayload, Packet): # RFC 2491
+ name = "ICMPv6 Neighbor Discovery Option - NBMA Shortcut Limit"
+ fields_desc = [ ByteField("type", 6),
+ ByteField("len", 1),
+ ByteField("shortcutlim", 40), # XXX
+ ByteField("res1", 0),
+ IntField("res2", 0) ]
+
+class ICMPv6NDOptAdvInterval(_ICMPv6NDGuessPayload, Packet):
+ name = "ICMPv6 Neighbor Discovery - Interval Advertisement"
+ fields_desc = [ ByteField("type",7),
+ ByteField("len",1),
+ ShortField("res", 0),
+ IntField("advint", 0) ]
+ def mysummary(self):
+ return self.sprintf("%name% %advint% milliseconds")
+
+class ICMPv6NDOptHAInfo(_ICMPv6NDGuessPayload, Packet):
+ name = "ICMPv6 Neighbor Discovery - Home Agent Information"
+ fields_desc = [ ByteField("type",8),
+ ByteField("len",1),
+ ShortField("res", 0),
+ ShortField("pref", 0),
+ ShortField("lifetime", 1)]
+ def mysummary(self):
+ return self.sprintf("%name% %pref% %lifetime% seconds")
+
+# type 9 : See ICMPv6NDOptSrcAddrList class below in IND (RFC 3122) support
+
+# type 10 : See ICMPv6NDOptTgtAddrList class below in IND (RFC 3122) support
+
+class ICMPv6NDOptIPAddr(_ICMPv6NDGuessPayload, Packet): # RFC 4068
+ name = "ICMPv6 Neighbor Discovery - IP Address Option (FH for MIPv6)"
+ fields_desc = [ ByteField("type",17),
+ ByteField("len", 3),
+ ByteEnumField("optcode", 1, {1: "Old Care-Of Address",
+ 2: "New Care-Of Address",
+ 3: "NAR's IP address" }),
+ ByteField("plen", 64),
+ IntField("res", 0),
+ IP6Field("addr", "::") ]
+
+class ICMPv6NDOptNewRtrPrefix(_ICMPv6NDGuessPayload, Packet): # RFC 4068
+ name = "ICMPv6 Neighbor Discovery - New Router Prefix Information Option (FH for MIPv6)"
+ fields_desc = [ ByteField("type",18),
+ ByteField("len", 3),
+ ByteField("optcode", 0),
+ ByteField("plen", 64),
+ IntField("res", 0),
+ IP6Field("prefix", "::") ]
+
+_rfc4068_lla_optcode = {0: "Wildcard requesting resolution for all nearby AP",
+ 1: "LLA for the new AP",
+ 2: "LLA of the MN",
+ 3: "LLA of the NAR",
+ 4: "LLA of the src of TrSolPr or PrRtAdv msg",
+ 5: "AP identified by LLA belongs to current iface of router",
+ 6: "No preifx info available for AP identified by the LLA",
+ 7: "No fast handovers support for AP identified by the LLA" }
+
+class ICMPv6NDOptLLA(_ICMPv6NDGuessPayload, Packet): # RFC 4068
+ name = "ICMPv6 Neighbor Discovery - Link-Layer Address (LLA) Option (FH for MIPv6)"
+ fields_desc = [ ByteField("type", 19),
+ ByteField("len", 1),
+ ByteEnumField("optcode", 0, _rfc4068_lla_optcode),
+ MACField("lla", ETHER_ANY) ] # We only support ethernet
+
+class ICMPv6NDOptMAP(_ICMPv6NDGuessPayload, Packet): # RFC 4140
+ name = "ICMPv6 Neighbor Discovery - MAP Option"
+ fields_desc = [ ByteField("type", 23),
+ ByteField("len", 3),
+ BitField("dist", 1, 4),
+ BitField("pref", 15, 4), # highest availability
+ BitField("R", 1, 1),
+ BitField("res", 0, 7),
+ IntField("validlifetime", 0xffffffff),
+ IP6Field("addr", "::") ]
+
+
+class IP6PrefixField(IP6Field):
+ def __init__(self, name, default):
+ IP6Field.__init__(self, name, default)
+ self.length_from = lambda pkt: 8*(pkt.len - 1)
+
+ def addfield(self, pkt, s, val):
+ return s + self.i2m(pkt, val)
+
+ def getfield(self, pkt, s):
+ l = self.length_from(pkt)
+ p = s[:l]
+ if l < 16:
+ p += b'\x00'*(16-l)
+ return s[l:], self.m2i(pkt,p)
+
+ def i2len(self, pkt, x):
+ return len(self.i2m(pkt, x))
+
+ def i2m(self, pkt, x):
+ l = pkt.len
+
+ if x is None:
+ x = "::"
+ if l is None:
+ l = 1
+ x = inet_pton(socket.AF_INET6, x)
+
+ if l is None:
+ return x
+ if l in [0, 1]:
+ return b""
+ if l in [2, 3]:
+ return x[:8*(l-1)]
+
+ return x + b'\x00'*8*(l-3)
+
+class ICMPv6NDOptRouteInfo(_ICMPv6NDGuessPayload, Packet): # RFC 4191
+ name = "ICMPv6 Neighbor Discovery Option - Route Information Option"
+ fields_desc = [ ByteField("type",24),
+ FieldLenField("len", None, length_of="prefix", fmt="B",
+ adjust = lambda pkt,x: x//8 + 1),
+ ByteField("plen", None),
+ BitField("res1",0,3),
+ BitField("prf",0,2),
+ BitField("res2",0,3),
+ IntField("rtlifetime", 0xffffffff),
+ IP6PrefixField("prefix", None) ]
+
+class ICMPv6NDOptRDNSS(_ICMPv6NDGuessPayload, Packet): # RFC 5006
+ name = "ICMPv6 Neighbor Discovery Option - Recursive DNS Server Option"
+ fields_desc = [ ByteField("type", 25),
+ FieldLenField("len", None, count_of="dns", fmt="B",
+ adjust = lambda pkt,x: 2*x+1),
+ ShortField("res", None),
+ IntField("lifetime", 0xffffffff),
+ IP6ListField("dns", [],
+ length_from = lambda pkt: 8*(pkt.len-1)) ]
+
+class ICMPv6NDOptEFA(_ICMPv6NDGuessPayload, Packet): # RFC 5175 (prev. 5075)
+ name = "ICMPv6 Neighbor Discovery Option - Expanded Flags Option"
+ fields_desc = [ ByteField("type", 26),
+ ByteField("len", 1),
+ BitField("res", 0, 48) ]
+
+# End of ICMPv6 Neighbor Discovery Options.
+
+class ICMPv6ND_RS(_ICMPv6NDGuessPayload, _ICMPv6):
+ name = "ICMPv6 Neighbor Discovery - Router Solicitation"
+ fields_desc = [ ByteEnumField("type", 133, icmp6types),
+ ByteField("code",0),
+ XShortField("cksum", None),
+ IntField("res",0) ]
+ overload_fields = {IPv6: { "nh": 58, "dst": "ff02::2", "hlim": 255 }}
+
+class ICMPv6ND_RA(_ICMPv6NDGuessPayload, _ICMPv6):
+ name = "ICMPv6 Neighbor Discovery - Router Advertisement"
+ fields_desc = [ ByteEnumField("type", 134, icmp6types),
+ ByteField("code",0),
+ XShortField("cksum", None),
+ ByteField("chlim",0),
+ BitField("M",0,1),
+ BitField("O",0,1),
+ BitField("H",0,1),
+ BitEnumField("prf",1,2, { 0: "Medium (default)",
+ 1: "High",
+ 2: "Reserved",
+ 3: "Low" } ), # RFC 4191
+ BitField("P",0,1),
+ BitField("res",0,2),
+ ShortField("routerlifetime",1800),
+ IntField("reachabletime",0),
+ IntField("retranstimer",0) ]
+ overload_fields = {IPv6: { "nh": 58, "dst": "ff02::1", "hlim": 255 }}
+
+ def answers(self, other):
+ return isinstance(other, ICMPv6ND_RS)
+
+class ICMPv6ND_NS(_ICMPv6NDGuessPayload, _ICMPv6, Packet):
+ name = "ICMPv6 Neighbor Discovery - Neighbor Solicitation"
+ fields_desc = [ ByteEnumField("type",135, icmp6types),
+ ByteField("code",0),
+ XShortField("cksum", None),
+ IntField("res", 0),
+ IP6Field("tgt","::") ]
+ overload_fields = {IPv6: { "nh": 58, "dst": "ff02::1", "hlim": 255 }}
+
+ def mysummary(self):
+ return self.sprintf("%name% (tgt: %tgt%)")
+
+ def hashret(self):
+ return self.getbyteval("tgt")+self.payload.hashret()
+
+class ICMPv6ND_NA(_ICMPv6NDGuessPayload, _ICMPv6, Packet):
+ name = "ICMPv6 Neighbor Discovery - Neighbor Advertisement"
+ fields_desc = [ ByteEnumField("type",136, icmp6types),
+ ByteField("code",0),
+ XShortField("cksum", None),
+ BitField("R",1,1),
+ BitField("S",0,1),
+ BitField("O",1,1),
+ XBitField("res",0,29),
+ IP6Field("tgt","::") ]
+ overload_fields = {IPv6: { "nh": 58, "dst": "ff02::1", "hlim": 255 }}
+
+ def mysummary(self):
+ return self.sprintf("%name% (tgt: %tgt%)")
+
+ def hashret(self):
+ return self.getbyteval("tgt")+self.payload.hashret()
+
+ def answers(self, other):
+ return isinstance(other, ICMPv6ND_NS) and self.tgt == other.tgt
+
+# associated possible options : target link-layer option, Redirected header
+class ICMPv6ND_Redirect(_ICMPv6NDGuessPayload, _ICMPv6, Packet):
+ name = "ICMPv6 Neighbor Discovery - Redirect"
+ fields_desc = [ ByteEnumField("type",137, icmp6types),
+ ByteField("code",0),
+ XShortField("cksum", None),
+ XIntField("res",0),
+ IP6Field("tgt","::"),
+ IP6Field("dst","::") ]
+ overload_fields = {IPv6: { "nh": 58, "dst": "ff02::1", "hlim": 255 }}
+
+
+
+################ ICMPv6 Inverse Neighbor Discovery (RFC 3122) ###############
+
+class ICMPv6NDOptSrcAddrList(_ICMPv6NDGuessPayload, Packet):
+ name = "ICMPv6 Inverse Neighbor Discovery Option - Source Address List"
+ fields_desc = [ ByteField("type",9),
+ FieldLenField("len", None, count_of="addrlist", fmt="B",
+ adjust = lambda pkt,x: 2*x+1),
+ StrFixedLenField("res", "\x00"*6, 6),
+ IP6ListField("addrlist", [],
+ length_from = lambda pkt: 8*(pkt.len-1)) ]
+
+class ICMPv6NDOptTgtAddrList(ICMPv6NDOptSrcAddrList):
+ name = "ICMPv6 Inverse Neighbor Discovery Option - Target Address List"
+ type = 10
+
+
+# RFC3122
+# Options requises : source lladdr et target lladdr
+# Autres options valides : source address list, MTU
+# - Comme precise dans le document, il serait bien de prendre l'adresse L2
+# demandee dans l'option requise target lladdr et l'utiliser au niveau
+# de l'adresse destination ethernet si aucune adresse n'est precisee
+# - ca semble pas forcement pratique si l'utilisateur doit preciser toutes
+# les options.
+# Ether() must use the target lladdr as destination
+class ICMPv6ND_INDSol(_ICMPv6NDGuessPayload, _ICMPv6):
+ name = "ICMPv6 Inverse Neighbor Discovery Solicitation"
+ fields_desc = [ ByteEnumField("type",141, icmp6types),
+ ByteField("code",0),
+ XShortField("cksum",None),
+ XIntField("reserved",0) ]
+ overload_fields = {IPv6: { "nh": 58, "dst": "ff02::1", "hlim": 255 }}
+
+# Options requises : target lladdr, target address list
+# Autres options valides : MTU
+class ICMPv6ND_INDAdv(_ICMPv6NDGuessPayload, _ICMPv6):
+ name = "ICMPv6 Inverse Neighbor Discovery Advertisement"
+ fields_desc = [ ByteEnumField("type",142, icmp6types),
+ ByteField("code",0),
+ XShortField("cksum",None),
+ XIntField("reserved",0) ]
+ overload_fields = {IPv6: { "nh": 58, "dst": "ff02::1", "hlim": 255 }}
+
+
+###############################################################################
+# ICMPv6 Node Information Queries (RFC 4620)
+###############################################################################
+
+# [ ] Add automatic destination address computation using computeNIGroupAddr
+# in IPv6 class (Scapy6 modification when integrated) if :
+# - it is not provided
+# - upper layer is ICMPv6NIQueryName() with a valid value
+# [ ] Try to be liberal in what we accept as internal values for _explicit_
+# DNS elements provided by users. Any string should be considered
+# valid and kept like it has been provided. At the moment, i2repr() will
+# crash on many inputs
+# [ ] Do the documentation
+# [ ] Add regression tests
+# [ ] Perform test against real machines (NOOP reply is proof of implementation).
+# [ ] Check if there are differences between different stacks. Among *BSD,
+# with others.
+# [ ] Deal with flags in a consistent way.
+# [ ] Implement compression in names2dnsrepr() and decompresiion in
+# dnsrepr2names(). Should be deactivable.
+
+icmp6_niqtypes = { 0: "NOOP",
+ 2: "Node Name",
+ 3: "IPv6 Address",
+ 4: "IPv4 Address" }
+
+
+class _ICMPv6NIHashret:
+ def hashret(self):
+ return self.nonce
+
+class _ICMPv6NIAnswers:
+ def answers(self, other):
+ return self.nonce == other.nonce
+
+# Buggy; always returns the same value during a session
+class NonceField(StrFixedLenField):
+ def __init__(self, name, default=None):
+ StrFixedLenField.__init__(self, name, default, 8)
+ if default is None:
+ self.default = self.randval()
+
+# Compute the NI group Address. Can take a FQDN as input parameter
+def computeNIGroupAddr(name):
+ import md5
+ name = name.lower().split(".")[0]
+ record = chr(len(name))+name
+ h = md5.new(record)
+ h = h.digest()
+ addr = "ff02::2:%2x%2x:%2x%2x" % struct.unpack("BBBB", h[:4])
+ return addr
+
+
+# Here is the deal. First, that protocol is a piece of shit. Then, we
+# provide 4 classes for the different kinds of Requests (one for every
+# valid qtype: NOOP, Node Name, IPv6@, IPv4@). They all share the same
+# data field class that is made to be smart by guessing the specifc
+# type of value provided :
+#
+# - IPv6 if acceptable for inet_pton(AF_INET6, ): code is set to 0,
+# if not overriden by user
+# - IPv4 if acceptable for inet_pton(AF_INET, ): code is set to 2,
+# if not overriden
+# - Name in the other cases: code is set to 0, if not overriden by user
+#
+# Internal storage, is not only the value, but the a pair providing
+# the type and the value (1 is IPv6@, 1 is Name or string, 2 is IPv4@)
+#
+# Note : I merged getfield() and m2i(). m2i() should not be called
+# directly anyway. Same remark for addfield() and i2m()
+#
+# -- arno
+
+# "The type of information present in the Data field of a query is
+# declared by the ICMP Code, whereas the type of information in a
+# Reply is determined by the Qtype"
+
+def names2dnsrepr(x):
+ """
+ Take as input a list of DNS names or a single DNS name
+ and encode it in DNS format (with possible compression)
+ If a string that is already a DNS name in DNS format
+ is passed, it is returned unmodified. Result is a string.
+ !!! At the moment, compression is not implemented !!!
+ """
+
+ if type(x) is str:
+ if x and x[-1] == '\x00': # stupid heuristic
+ return x.encode('ascii')
+ x = [x.encode('ascii')]
+ elif type(x) is bytes:
+ if x and x[-1] == 0:
+ return x
+ x = [x]
+
+ res = []
+ for n in x:
+ if type(n) is str:
+ n = n.encode('ascii')
+ termin = b"\x00"
+ if n.count(b'.') == 0: # single-component gets one more
+ termin += bytes([0])
+ n = b"".join(map(lambda y: chr(len(y)).encode('ascii')+y, n.split(b"."))) + termin
+ res.append(n)
+ return b"".join(res)
+
+
+def dnsrepr2names(x):
+ """
+ Take as input a DNS encoded string (possibly compressed)
+ and returns a list of DNS names contained in it.
+ If provided string is already in printable format
+ (does not end with a null character, a one element list
+ is returned). Result is a list.
+ """
+ res = []
+ cur = b""
+ if type(x) is str:
+ x = x.encode('ascii')
+ while x:
+ #l = ord(x[0])
+ l = x[0]
+ x = x[1:]
+ if l == 0:
+ if cur and cur[-1] == ord('.'):
+ cur = cur[:-1]
+ res.append(cur)
+ cur = b""
+ #if x and ord(x[0]) == 0: # single component
+ if x and x[0] == 0: # single component
+ x = x[1:]
+ continue
+ if l & 0xc0: # XXX TODO : work on that -- arno
+ raise Exception("DNS message can't be compressed at this point!")
+ else:
+ cur += x[:l]+b"."
+ x = x[l:]
+ return res
+
+
+class NIQueryDataField(StrField):
+ def __init__(self, name, default):
+ StrField.__init__(self, name, default)
+
+ def i2h(self, pkt, x):
+ if x is None:
+ return x
+ t,val = x
+ if t == 1:
+ val = dnsrepr2names(val)[0]
+ return val
+
+ def h2i(self, pkt, x):
+ if x is tuple and type(x[0]) is int:
+ return x
+
+ val = None
+ try: # Try IPv6
+ inet_pton(socket.AF_INET6, x)
+ val = (0, x)
+ except:
+ try: # Try IPv4
+ inet_pton(socket.AF_INET, x)
+ val = (2, x)
+ except: # Try DNS
+ if x is None:
+ x = b""
+ x = names2dnsrepr(x)
+ val = (1, x)
+ return val
+
+ def i2repr(self, pkt, x):
+ t,val = x
+ if t == 1: # DNS Name
+ # we don't use dnsrepr2names() to deal with
+ # possible weird data extracted info
+ res = []
+ weird = None
+ while val:
+ #l = ord(val[0])
+ l = val[0]
+ val = val[1:]
+ if l == 0:
+ if (len(res) > 1 and val): # fqdn with data behind
+ weird = val
+ elif len(val) > 1: # single label with data behind
+ weird = val[1:]
+ break
+ res.append(val[:l]+".")
+ val = val[l:]
+ tmp = "".join(res)
+ if tmp and tmp[-1] == '.':
+ tmp = tmp[:-1]
+ return tmp
+ return repr(val)
+
+ def getfield(self, pkt, s):
+ qtype = getattr(pkt, "qtype")
+ if qtype == 0: # NOOP
+ return s, (0, b"")
+ else:
+ code = getattr(pkt, "code")
+ if code == 0: # IPv6 Addr
+ return s[16:], (0, inet_ntop(socket.AF_INET6, s[:16]))
+ elif code == 2: # IPv4 Addr
+ return s[4:], (2, inet_ntop(socket.AF_INET, s[:4]))
+ else: # Name or Unknown
+ return b"", (1, s)
+
+ def addfield(self, pkt, s, val):
+ if ((type(val) is tuple and val[1] is None) or
+ val is None):
+ val = (1, b"")
+ t = val[0]
+ if t == 1:
+ if type(val[1]) is str:
+ tmp = val[1].encode('ascii')
+ else:
+ tmp = val[1]
+ return s + tmp
+ elif t == 0:
+ return s + inet_pton(socket.AF_INET6, val[1])
+ else:
+ return s + inet_pton(socket.AF_INET, val[1])
+
+class NIQueryCodeField(ByteEnumField):
+ def i2m(self, pkt, x):
+ if x is None:
+ d = pkt.getfieldval("data")
+ if d is None:
+ return 1
+ elif d[0] == 0: # IPv6 address
+ return 0
+ elif d[0] == 1: # Name
+ return 1
+ elif d[0] == 2: # IPv4 address
+ return 2
+ else:
+ return 1
+ return x
+
+
+_niquery_code = {0: "IPv6 Query", 1: "Name Query", 2: "IPv4 Query"}
+
+#_niquery_flags = { 2: "All unicast addresses", 4: "IPv4 addresses",
+# 8: "Link-local addresses", 16: "Site-local addresses",
+# 32: "Global addresses" }
+
+# "This NI type has no defined flags and never has a Data Field". Used
+# to know if the destination is up and implements NI protocol.
+class ICMPv6NIQueryNOOP(_ICMPv6NIHashret, _ICMPv6):
+ name = "ICMPv6 Node Information Query - NOOP Query"
+ fields_desc = [ ByteEnumField("type", 139, icmp6types),
+ NIQueryCodeField("code", None, _niquery_code),
+ XShortField("cksum", None),
+ ShortEnumField("qtype", 0, icmp6_niqtypes),
+ BitField("unused", 0, 10),
+ FlagsField("flags", 0, 6, "TACLSG"),
+ NonceField("nonce", None),
+ NIQueryDataField("data", None) ]
+
+class ICMPv6NIQueryName(ICMPv6NIQueryNOOP):
+ name = "ICMPv6 Node Information Query - IPv6 Name Query"
+ qtype = 2
+
+# We ask for the IPv6 address of the peer
+class ICMPv6NIQueryIPv6(ICMPv6NIQueryNOOP):
+ name = "ICMPv6 Node Information Query - IPv6 Address Query"
+ qtype = 3
+ flags = 0x3E
+
+class ICMPv6NIQueryIPv4(ICMPv6NIQueryNOOP):
+ name = "ICMPv6 Node Information Query - IPv4 Address Query"
+ qtype = 4
+
+_nireply_code = { 0: "Successful Reply",
+ 1: "Response Refusal",
+ 3: "Unknown query type" }
+
+_nireply_flags = { 1: "Reply set incomplete",
+ 2: "All unicast addresses",
+ 4: "IPv4 addresses",
+ 8: "Link-local addresses",
+ 16: "Site-local addresses",
+ 32: "Global addresses" }
+
+# Internal repr is one of those :
+# (0, "some string") : unknow qtype value are mapped to that one
+# (3, [ (ttl, ip6), ... ])
+# (4, [ (ttl, ip4), ... ])
+# (2, [ttl, dns_names]) : dns_names is one string that contains
+# all the DNS names. Internally it is kept ready to be sent
+# (undissected). i2repr() decode it for user. This is to
+# make build after dissection bijective.
+#
+# I also merged getfield() and m2i(), and addfield() and i2m().
+class NIReplyDataField(StrField):
+
+ def i2h(self, pkt, x):
+ if x is None:
+ return x
+ t,val = x
+ if t == 2:
+ ttl, dnsnames = val
+ val = [ttl] + dnsrepr2names(dnsnames)
+ return val
+
+ def h2i(self, pkt, x):
+ qtype = 0 # We will decode it as string if not
+ # overridden through 'qtype' in pkt
+
+ # No user hint, let's use 'qtype' value for that purpose
+ if type(x) is not tuple:
+ if pkt is not None:
+ qtype = getattr(pkt, "qtype")
+ else:
+ qtype = x[0]
+ x = x[1]
+
+ # From that point on, x is the value (second element of the tuple)
+
+ if qtype == 2: # DNS name
+ if type(x) is str: # listify the string
+ x = x.encode('ascii')
+ x = [x]
+ elif type(x) is bytes:
+ x = [x]
+ if type(x) is list and x and type(x[0]) is not int: # ttl was omitted : use 0
+ x = [0] + x
+ ttl = x[0]
+ names = x[1:]
+ return (2, [ttl, names2dnsrepr(names)])
+
+ elif qtype in [3, 4]: # IPv4 or IPv6 addr
+ if type(x) is str or type(x) is bytes:
+ x = [x] # User directly provided an IP, instead of list
+
+ # List elements are not tuples, user probably
+ # omitted ttl value : we will use 0 instead
+ def addttl(x):
+ if type(x) is str or type(x) is bytes:
+ return (0, x)
+ return x
+
+ return (qtype, list(map(addttl, x)))
+
+ return (qtype, x)
+
+
+ def addfield(self, pkt, s, val):
+ t,tmp = val
+ if tmp is None:
+ tmp = b""
+ if t == 2:
+ ttl,dnsstr = tmp
+ return s+ struct.pack("!I", ttl) + dnsstr
+ elif t == 3:
+ #return s + "".join(map(lambda (x,y): struct.pack("!I", x)+inet_pton(socket.AF_INET6, y), tmp))
+ return s + b"".join(map(lambda a: struct.pack("!I", a[0])+inet_pton(socket.AF_INET6, a[1]), tmp))
+ elif t == 4:
+ #return s + "".join(map(lambda (x,y): struct.pack("!I", x)+inet_pton(socket.AF_INET, y), tmp))
+ return s + b"".join(map(lambda a: struct.pack("!I", a[0])+inet_pton(socket.AF_INET, a[1]), tmp))
+ else:
+ return s + tmp
+
+ def getfield(self, pkt, s):
+ code = getattr(pkt, "code")
+ if code != 0:
+ return s, (0, b"")
+
+ qtype = getattr(pkt, "qtype")
+ if qtype == 0: # NOOP
+ return s, (0, b"")
+
+ elif qtype == 2:
+ if len(s) < 4:
+ return s, (0, b"")
+ ttl = struct.unpack("!I", s[:4])[0]
+ return b"", (2, [ttl, s[4:]])
+
+ elif qtype == 3: # IPv6 addresses with TTLs
+ # XXX TODO : get the real length
+ res = []
+ while len(s) >= 20: # 4 + 16
+ ttl = struct.unpack("!I", s[:4])[0]
+ ip = inet_ntop(socket.AF_INET6, s[4:20])
+ res.append((ttl, ip))
+ s = s[20:]
+ return s, (3, res)
+
+ elif qtype == 4: # IPv4 addresses with TTLs
+ # XXX TODO : get the real length
+ res = []
+ while len(s) >= 8: # 4 + 4
+ ttl = struct.unpack("!I", s[:4])[0]
+ ip = inet_ntop(socket.AF_INET, s[4:8])
+ res.append((ttl, ip))
+ s = s[8:]
+ return s, (4, res)
+ else:
+ # XXX TODO : implement me and deal with real length
+ return b"", (0, s)
+
+ def i2repr(self, pkt, x):
+ if x is None:
+ return "[]"
+
+ if type(x) is tuple and len(x) == 2:
+ t, val = x
+ if t == 2: # DNS names
+ ttl,l = val
+ l = dnsrepr2names(l)
+ return "ttl:%d %s" % (ttl, ", ".join(l))
+ elif t == 3 or t == 4:
+ #return "[ %s ]" % (", ".join(map(lambda (x,y): "(%d, %s)" % (x, y), val)))
+ return "[ %s ]" % (", ".join(map(lambda a: "(%d, %s)" % a, val)))
+ return repr(val)
+ return repr(x) # XXX should not happen
+
+# By default, sent responses have code set to 0 (successful)
+class ICMPv6NIReplyNOOP(_ICMPv6NIAnswers, _ICMPv6NIHashret, _ICMPv6):
+ name = "ICMPv6 Node Information Reply - NOOP Reply"
+ fields_desc = [ ByteEnumField("type", 140, icmp6types),
+ ByteEnumField("code", 0, _nireply_code),
+ XShortField("cksum", None),
+ ShortEnumField("qtype", 0, icmp6_niqtypes),
+ BitField("unused", 0, 10),
+ FlagsField("flags", 0, 6, "TACLSG"),
+ NonceField("nonce", None),
+ NIReplyDataField("data", None)]
+
+class ICMPv6NIReplyName(ICMPv6NIReplyNOOP):
+ name = "ICMPv6 Node Information Reply - Node Names"
+ qtype = 2
+
+class ICMPv6NIReplyIPv6(ICMPv6NIReplyNOOP):
+ name = "ICMPv6 Node Information Reply - IPv6 addresses"
+ qtype = 3
+
+class ICMPv6NIReplyIPv4(ICMPv6NIReplyNOOP):
+ name = "ICMPv6 Node Information Reply - IPv4 addresses"
+ qtype = 4
+
+class ICMPv6NIReplyRefuse(ICMPv6NIReplyNOOP):
+ name = "ICMPv6 Node Information Reply - Responder refuses to supply answer"
+ code = 1
+
+class ICMPv6NIReplyUnknown(ICMPv6NIReplyNOOP):
+ name = "ICMPv6 Node Information Reply - Qtype unknown to the responder"
+ code = 2
+
+
+def _niquery_guesser(p):
+ cls = conf.raw_layer
+ #type = ord(p[0])
+ type = p[0]
+ if type == 139: # Node Info Query specific stuff
+ if len(p) > 6:
+ qtype, = struct.unpack("!H", p[4:6])
+ cls = { 0: ICMPv6NIQueryNOOP,
+ 2: ICMPv6NIQueryName,
+ 3: ICMPv6NIQueryIPv6,
+ 4: ICMPv6NIQueryIPv4 }.get(qtype, conf.raw_layer)
+ elif type == 140: # Node Info Reply specific stuff
+ #code = ord(p[1])
+ code = p[1]
+ if code == 0:
+ if len(p) > 6:
+ qtype, = struct.unpack("!H", p[4:6])
+ cls = { 2: ICMPv6NIReplyName,
+ 3: ICMPv6NIReplyIPv6,
+ 4: ICMPv6NIReplyIPv4 }.get(qtype, ICMPv6NIReplyNOOP)
+ elif code == 1:
+ cls = ICMPv6NIReplyRefuse
+ elif code == 2:
+ cls = ICMPv6NIReplyUnknown
+ return cls
+
+
+#############################################################################
+#############################################################################
+### Mobile IPv6 (RFC 3775) and Nemo (RFC 3963) ###
+#############################################################################
+#############################################################################
+
+# Mobile IPv6 ICMPv6 related classes
+
+class ICMPv6HAADRequest(_ICMPv6):
+ name = 'ICMPv6 Home Agent Address Discovery Request'
+ fields_desc = [ ByteEnumField("type", 144, icmp6types),
+ ByteField("code", 0),
+ XShortField("cksum", None),
+ XShortField("id", None),
+ BitEnumField("R", 1, 1, {1: 'MR'}),
+ XBitField("res", 0, 15) ]
+ def hashret(self):
+ return struct.pack("!H",self.id)+self.payload.hashret()
+
+class ICMPv6HAADReply(_ICMPv6):
+ name = 'ICMPv6 Home Agent Address Discovery Reply'
+ fields_desc = [ ByteEnumField("type", 145, icmp6types),
+ ByteField("code", 0),
+ XShortField("cksum", None),
+ XShortField("id", None),
+ BitEnumField("R", 1, 1, {1: 'MR'}),
+ XBitField("res", 0, 15),
+ IP6ListField('addresses', None) ]
+ def hashret(self):
+ return struct.pack("!H",self.id)+self.payload.hashret()
+
+ def answers(self, other):
+ if not isinstance(other, ICMPv6HAADRequest):
+ return 0
+ return self.id == other.id
+
+class ICMPv6MPSol(_ICMPv6):
+ name = 'ICMPv6 Mobile Prefix Solicitation'
+ fields_desc = [ ByteEnumField("type", 146, icmp6types),
+ ByteField("code", 0),
+ XShortField("cksum", None),
+ XShortField("id", None),
+ XShortField("res", 0) ]
+ def _hashret(self):
+ return struct.pack("!H",self.id)
+
+class ICMPv6MPAdv(_ICMPv6NDGuessPayload, _ICMPv6):
+ name = 'ICMPv6 Mobile Prefix Advertisement'
+ fields_desc = [ ByteEnumField("type", 147, icmp6types),
+ ByteField("code", 0),
+ XShortField("cksum", None),
+ XShortField("id", None),
+ BitEnumField("flags", 2, 2, {2: 'M', 1:'O'}),
+ XBitField("res", 0, 14) ]
+ def hashret(self):
+ return struct.pack("!H",self.id)
+
+ def answers(self, other):
+ return isinstance(other, ICMPv6MPSol)
+
+# Mobile IPv6 Options classes
+
+
+_mobopttypes = { 2: "Binding Refresh Advice",
+ 3: "Alternate Care-of Address",
+ 4: "Nonce Indices",
+ 5: "Binding Authorization Data",
+ 6: "Mobile Network Prefix (RFC3963)",
+ 7: "Link-Layer Address (RFC4068)",
+ 8: "Mobile Node Identifier (RFC4283)",
+ 9: "Mobility Message Authentication (RFC4285)",
+ 10: "Replay Protection (RFC4285)",
+ 11: "CGA Parameters Request (RFC4866)",
+ 12: "CGA Parameters (RFC4866)",
+ 13: "Signature (RFC4866)",
+ 14: "Home Keygen Token (RFC4866)",
+ 15: "Care-of Test Init (RFC4866)",
+ 16: "Care-of Test (RFC4866)" }
+
+
+class _MIP6OptAlign:
+ """ Mobile IPv6 options have alignment requirements of the form x*n+y.
+ This class is inherited by all MIPv6 options to help in computing the
+ required Padding for that option, i.e. the need for a Pad1 or PadN
+ option before it. They only need to provide x and y as class
+ parameters. (x=0 and y=0 are used when no alignment is required)"""
+ def alignment_delta(self, curpos):
+ x = self.x ; y = self.y
+ if x == 0 and y ==0:
+ return 0
+ delta = x*((curpos - y + x - 1)//x) + y - curpos
+ return delta
+
+
+class MIP6OptBRAdvice(_MIP6OptAlign, Packet):
+ name = 'Mobile IPv6 Option - Binding Refresh Advice'
+ fields_desc = [ ByteEnumField('otype', 2, _mobopttypes),
+ ByteField('olen', 2),
+ ShortField('rinter', 0) ]
+ x = 2 ; y = 0# alignment requirement: 2n
+
+class MIP6OptAltCoA(_MIP6OptAlign, Packet):
+ name = 'MIPv6 Option - Alternate Care-of Address'
+ fields_desc = [ ByteEnumField('otype', 3, _mobopttypes),
+ ByteField('olen', 16),
+ IP6Field("acoa", "::") ]
+ x = 8 ; y = 6 # alignment requirement: 8n+6
+
+class MIP6OptNonceIndices(_MIP6OptAlign, Packet):
+ name = 'MIPv6 Option - Nonce Indices'
+ fields_desc = [ ByteEnumField('otype', 4, _mobopttypes),
+ ByteField('olen', 16),
+ ShortField('hni', 0),
+ ShortField('coni', 0) ]
+ x = 2 ; y = 0 # alignment requirement: 2n
+
+class MIP6OptBindingAuthData(_MIP6OptAlign, Packet):
+ name = 'MIPv6 Option - Binding Authorization Data'
+ fields_desc = [ ByteEnumField('otype', 5, _mobopttypes),
+ ByteField('olen', 16),
+ BitField('authenticator', 0, 96) ]
+ x = 8 ; y = 2 # alignment requirement: 8n+2
+
+class MIP6OptMobNetPrefix(_MIP6OptAlign, Packet): # NEMO - RFC 3963
+ name = 'NEMO Option - Mobile Network Prefix'
+ fields_desc = [ ByteEnumField("otype", 6, _mobopttypes),
+ ByteField("olen", 18),
+ ByteField("reserved", 0),
+ ByteField("plen", 64),
+ IP6Field("prefix", "::") ]
+ x = 8 ; y = 4 # alignment requirement: 8n+4
+
+class MIP6OptLLAddr(_MIP6OptAlign, Packet): # Sect 6.4.4 of RFC 4068
+ name = "MIPv6 Option - Link-Layer Address (MH-LLA)"
+ fields_desc = [ ByteEnumField("otype", 7, _mobopttypes),
+ ByteField("olen", 7),
+ ByteEnumField("ocode", 2, _rfc4068_lla_optcode),
+ ByteField("pad", 0),
+ MACField("lla", ETHER_ANY) ] # Only support ethernet
+ x = 0 ; y = 0 # alignment requirement: none
+
+class MIP6OptMNID(_MIP6OptAlign, Packet): # RFC 4283
+ name = "MIPv6 Option - Mobile Node Identifier"
+ fields_desc = [ ByteEnumField("otype", 8, _mobopttypes),
+ FieldLenField("olen", None, length_of="id", fmt="B",
+ adjust = lambda pkt,x: x+1),
+ ByteEnumField("subtype", 1, {1: "NAI"}),
+ StrLenField("id", "",
+ length_from = lambda pkt: pkt.olen-1) ]
+ x = 0 ; y = 0 # alignment requirement: none
+
+# We only support decoding and basic build. Automatic HMAC computation is
+# too much work for our current needs. It is left to the user (I mean ...
+# you). --arno
+class MIP6OptMsgAuth(_MIP6OptAlign, Packet): # RFC 4285 (Sect. 5)
+ name = "MIPv6 Option - Mobility Message Authentication"
+ fields_desc = [ ByteEnumField("otype", 9, _mobopttypes),
+ FieldLenField("olen", None, length_of="authdata", fmt="B",
+ adjust = lambda pkt,x: x+5),
+ ByteEnumField("subtype", 1, {1: "MN-HA authentication mobility option",
+ 2: "MN-AAA authentication mobility option"}),
+ IntField("mspi", None),
+ StrLenField("authdata", "A"*12,
+ length_from = lambda pkt: pkt.olen-5) ]
+ x = 4 ; y = 1 # alignment requirement: 4n+1
+
+# Extracted from RFC 1305 (NTP) :
+# NTP timestamps are represented as a 64-bit unsigned fixed-point number,
+# in seconds relative to 0h on 1 January 1900. The integer part is in the
+# first 32 bits and the fraction part in the last 32 bits.
+class NTPTimestampField(LongField):
+ epoch = (1900, 1, 1, 0, 0, 0, 5, 1, 0)
+ def i2repr(self, pkt, x):
+ if x < ((50*31536000)<<32):
+ return "Some date a few decades ago (%d)" % x
+
+ # delta from epoch (= (1900, 1, 1, 0, 0, 0, 5, 1, 0)) to
+ # January 1st 1970 :
+ delta = -2209075761
+ i = int(x >> 32)
+ j = float(x & 0xffffffff) * 2.0**-32
+ res = i + j + delta
+ from time import strftime
+ t = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(res))
+
+ return "%s (%d)" % (t, x)
+
+class MIP6OptReplayProtection(_MIP6OptAlign, Packet): # RFC 4285 (Sect. 6)
+ name = "MIPv6 option - Replay Protection"
+ fields_desc = [ ByteEnumField("otype", 10, _mobopttypes),
+ ByteField("olen", 8),
+ NTPTimestampField("timestamp", 0) ]
+ x = 8 ; y = 2 # alignment requirement: 8n+2
+
+class MIP6OptCGAParamsReq(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.6)
+ name = "MIPv6 option - CGA Parameters Request"
+ fields_desc = [ ByteEnumField("otype", 11, _mobopttypes),
+ ByteField("olen", 0) ]
+ x = 0 ; y = 0 # alignment requirement: none
+
+# XXX TODO: deal with CGA param fragmentation and build of defragmented
+# XXX version. Passing of a big CGAParam structure should be
+# XXX simplified. Make it hold packets, by the way --arno
+class MIP6OptCGAParams(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.1)
+ name = "MIPv6 option - CGA Parameters"
+ fields_desc = [ ByteEnumField("otype", 12, _mobopttypes),
+ FieldLenField("olen", None, length_of="cgaparams", fmt="B"),
+ StrLenField("cgaparams", "",
+ length_from = lambda pkt: pkt.olen) ]
+ x = 0 ; y = 0 # alignment requirement: none
+
+class MIP6OptSignature(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.2)
+ name = "MIPv6 option - Signature"
+ fields_desc = [ ByteEnumField("otype", 13, _mobopttypes),
+ FieldLenField("olen", None, length_of="sig", fmt="B"),
+ StrLenField("sig", "",
+ length_from = lambda pkt: pkt.olen) ]
+ x = 0 ; y = 0 # alignment requirement: none
+
+class MIP6OptHomeKeygenToken(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.3)
+ name = "MIPv6 option - Home Keygen Token"
+ fields_desc = [ ByteEnumField("otype", 14, _mobopttypes),
+ FieldLenField("olen", None, length_of="hkt", fmt="B"),
+ StrLenField("hkt", "",
+ length_from = lambda pkt: pkt.olen) ]
+ x = 0 ; y = 0 # alignment requirement: none
+
+class MIP6OptCareOfTestInit(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.4)
+ name = "MIPv6 option - Care-of Test Init"
+ fields_desc = [ ByteEnumField("otype", 15, _mobopttypes),
+ ByteField("olen", 0) ]
+ x = 0 ; y = 0 # alignment requirement: none
+
+class MIP6OptCareOfTest(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.5)
+ name = "MIPv6 option - Care-of Test"
+ fields_desc = [ ByteEnumField("otype", 16, _mobopttypes),
+ FieldLenField("olen", None, length_of="cokt", fmt="B"),
+ StrLenField("cokt", '\x00'*8,
+ length_from = lambda pkt: pkt.olen) ]
+ x = 0 ; y = 0 # alignment requirement: none
+
+class MIP6OptUnknown(_MIP6OptAlign, Packet):
+ name = 'Scapy6 - Unknown Mobility Option'
+ fields_desc = [ ByteEnumField("otype", 6, _mobopttypes),
+ FieldLenField("olen", None, length_of="odata", fmt="B"),
+ StrLenField("odata", "",
+ length_from = lambda pkt: pkt.olen) ]
+ x = 0 ; y = 0 # alignment requirement: none
+
+moboptcls = { 0: Pad1,
+ 1: PadN,
+ 2: MIP6OptBRAdvice,
+ 3: MIP6OptAltCoA,
+ 4: MIP6OptNonceIndices,
+ 5: MIP6OptBindingAuthData,
+ 6: MIP6OptMobNetPrefix,
+ 7: MIP6OptLLAddr,
+ 8: MIP6OptMNID,
+ 9: MIP6OptMsgAuth,
+ 10: MIP6OptReplayProtection,
+ 11: MIP6OptCGAParamsReq,
+ 12: MIP6OptCGAParams,
+ 13: MIP6OptSignature,
+ 14: MIP6OptHomeKeygenToken,
+ 15: MIP6OptCareOfTestInit,
+ 16: MIP6OptCareOfTest }
+
+
+# Main Mobile IPv6 Classes
+
+mhtypes = { 0: 'BRR',
+ 1: 'HoTI',
+ 2: 'CoTI',
+ 3: 'HoT',
+ 4: 'CoT',
+ 5: 'BU',
+ 6: 'BA',
+ 7: 'BE',
+ 8: 'Fast BU',
+ 9: 'Fast BA',
+ 10: 'Fast NA' }
+
+# From http://www.iana.org/assignments/mobility-parameters
+bastatus = { 0: 'Binding Update accepted',
+ 1: 'Accepted but prefix discovery necessary',
+ 128: 'Reason unspecified',
+ 129: 'Administratively prohibited',
+ 130: 'Insufficient resources',
+ 131: 'Home registration not supported',
+ 132: 'Not home subnet',
+ 133: 'Not home agent for this mobile node',
+ 134: 'Duplicate Address Detection failed',
+ 135: 'Sequence number out of window',
+ 136: 'Expired home nonce index',
+ 137: 'Expired care-of nonce index',
+ 138: 'Expired nonces',
+ 139: 'Registration type change disallowed',
+ 140: 'Mobile Router Operation not permitted',
+ 141: 'Invalid Prefix',
+ 142: 'Not Authorized for Prefix',
+ 143: 'Forwarding Setup failed (prefixes missing)',
+ 144: 'MIPV6-ID-MISMATCH',
+ 145: 'MIPV6-MESG-ID-REQD',
+ 146: 'MIPV6-AUTH-FAIL',
+ 147: 'Permanent home keygen token unavailable',
+ 148: 'CGA and signature verification failed',
+ 149: 'Permanent home keygen token exists',
+ 150: 'Non-null home nonce index expected' }
+
+
+class _MobilityHeader(Packet):
+ name = 'Dummy IPv6 Mobility Header'
+ overload_fields = { IPv6: { "nh": 135 }}
+
+ def post_build(self, p, pay):
+ p += pay
+ l = self.len
+ if self.len is None:
+ l = (len(p)-8)//8
+ p = bytes([p[0]]) + struct.pack("B", l) + p[2:]
+ if self.cksum is None:
+ cksum = in6_chksum(135, self.underlayer, p)
+ else:
+ cksum = self.cksum
+ p = p[:4]+struct.pack("!H", cksum)+p[6:]
+ return p
+
+
+class MIP6MH_Generic(_MobilityHeader): # Mainly for decoding of unknown msg
+ name = "IPv6 Mobility Header - Generic Message"
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+ ByteField("len", None),
+ ByteEnumField("mhtype", None, mhtypes),
+ ByteField("res", None),
+ XShortField("cksum", None),
+ StrLenField("msg", b"\x00"*2,
+ length_from = lambda pkt: 8*pkt.len-6) ]
+
+
+
+# TODO: make a generic _OptionsField
+class _MobilityOptionsField(PacketListField):
+ islist = 1
+ holds_packet = 1
+
+ def __init__(self, name, default, cls, curpos, count_from=None, length_from=None):
+ self.curpos = curpos
+ PacketListField.__init__(self, name, default, cls, count_from=count_from, length_from=length_from)
+
+ def getfield(self, pkt, s):
+ l = self.length_from(pkt)
+ return s[l:],self.m2i(pkt, s[:l])
+
+ def i2len(self, pkt, i):
+ return len(self.i2m(pkt, i))
+
+ def m2i(self, pkt, x):
+ opt = []
+ while x:
+ #o = ord(x[0]) # Option type
+ o = x[0] # Option type
+ cls = self.cls
+ if o in moboptcls:
+ cls = moboptcls[o]
+ try:
+ op = cls(x)
+ except:
+ op = self.cls(x)
+ opt.append(op)
+ if isinstance(op.payload, conf.raw_layer):
+ x = op.payload.load
+ del(op.payload)
+ else:
+ x = b""
+ return opt
+
+ def i2m(self, pkt, x):
+ autopad = None
+ try:
+ autopad = getattr(pkt, "autopad") # Hack : 'autopad' phantom field
+ except:
+ autopad = 1
+
+ if not autopad:
+ return b"".join(map(str, x))
+
+ curpos = self.curpos
+ s = b""
+ for p in x:
+ d = p.alignment_delta(curpos)
+ curpos += d
+ if d == 1:
+ s += bytes(Pad1())
+ elif d != 0:
+ s += bytes(PadN(optdata=b'\x00'*(d-2)))
+ pstr = bytes(p)
+ curpos += len(pstr)
+ s += pstr
+
+ # Let's make the class including our option field
+ # a multiple of 8 octets long
+ d = curpos % 8
+ if d == 0:
+ return s
+ d = 8 - d
+ if d == 1:
+ s +=bytes(Pad1())
+ elif d != 0:
+ s += bytes(PadN(optdata=b'\x00'*(d-2)))
+
+ return s
+
+ def addfield(self, pkt, s, val):
+ return s+self.i2m(pkt, val)
+
+class MIP6MH_BRR(_MobilityHeader):
+ name = "IPv6 Mobility Header - Binding Refresh Request"
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+ ByteField("len", None),
+ ByteEnumField("mhtype", 0, mhtypes),
+ ByteField("res", None),
+ XShortField("cksum", None),
+ ShortField("res2", None),
+ _PhantomAutoPadField("autopad", 1), # autopad activated by default
+ _MobilityOptionsField("options", [], MIP6OptUnknown, 8,
+ length_from = lambda pkt: 8*pkt.len) ]
+ overload_fields = { IPv6: { "nh": 135 } }
+ def hashret(self):
+ # Hack: BRR, BU and BA have the same hashret that returns the same
+ # value "\x00\x08\x09" (concatenation of mhtypes). This is
+ # because we need match BA with BU and BU with BRR. --arno
+ return b"\x00\x08\x09"
+
+class MIP6MH_HoTI(_MobilityHeader):
+ name = "IPv6 Mobility Header - Home Test Init"
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+ ByteField("len", None),
+ ByteEnumField("mhtype", 1, mhtypes),
+ ByteField("res", None),
+ XShortField("cksum", None),
+ StrFixedLenField("reserved", "\x00"*2, 2),
+ StrFixedLenField("cookie", "\x00"*8, 8),
+ _PhantomAutoPadField("autopad", 1), # autopad activated by default
+ _MobilityOptionsField("options", [], MIP6OptUnknown, 16,
+ length_from = lambda pkt: 8*(pkt.len-1)) ]
+ overload_fields = { IPv6: { "nh": 135 } }
+ def hashret(self):
+ return self.cookie
+
+class MIP6MH_CoTI(MIP6MH_HoTI):
+ name = "IPv6 Mobility Header - Care-of Test Init"
+ mhtype = 2
+ def hashret(self):
+ return self.cookie
+
+class MIP6MH_HoT(_MobilityHeader):
+ name = "IPv6 Mobility Header - Home Test"
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+ ByteField("len", None),
+ ByteEnumField("mhtype", 3, mhtypes),
+ ByteField("res", None),
+ XShortField("cksum", None),
+ ShortField("index", None),
+ StrFixedLenField("cookie", "\x00"*8, 8),
+ StrFixedLenField("token", "\x00"*8, 8),
+ _PhantomAutoPadField("autopad", 1), # autopad activated by default
+ _MobilityOptionsField("options", [], MIP6OptUnknown, 24,
+ length_from = lambda pkt: 8*(pkt.len-2)) ]
+ overload_fields = { IPv6: { "nh": 135 } }
+ def hashret(self):
+ return self.cookie
+ def answers(self):
+ if (isinstance(other, MIP6MH_HoTI) and
+ self.cookie == other.cookie):
+ return 1
+ return 0
+
+class MIP6MH_CoT(MIP6MH_HoT):
+ name = "IPv6 Mobility Header - Care-of Test"
+ mhtype = 4
+ def hashret(self):
+ return self.cookie
+
+ def answers(self):
+ if (isinstance(other, MIP6MH_CoTI) and
+ self.cookie == other.cookie):
+ return 1
+ return 0
+
+class LifetimeField(ShortField):
+ def i2repr(self, pkt, x):
+ return "%d sec" % (4*x)
+
+class MIP6MH_BU(_MobilityHeader):
+ name = "IPv6 Mobility Header - Binding Update"
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+ ByteField("len", None), # unit == 8 bytes (excluding the first 8 bytes)
+ ByteEnumField("mhtype", 5, mhtypes),
+ ByteField("res", None),
+ XShortField("cksum", None),
+ XShortField("seq", None), # TODO: ShortNonceField
+ FlagsField("flags", "KHA", 7, "PRMKLHA"),
+ XBitField("reserved", 0, 9),
+ LifetimeField("mhtime", 3), # unit == 4 seconds
+ _PhantomAutoPadField("autopad", 1), # autopad activated by default
+ _MobilityOptionsField("options", [], MIP6OptUnknown, 12,
+ length_from = lambda pkt: 8*pkt.len - 4) ]
+ overload_fields = { IPv6: { "nh": 135 } }
+
+ def hashret(self): # Hack: see comment in MIP6MH_BRR.hashret()
+ return "\x00\x08\x09"
+
+ def answers(self, other):
+ if isinstance(other, MIP6MH_BRR):
+ return 1
+ return 0
+
+class MIP6MH_BA(_MobilityHeader):
+ name = "IPv6 Mobility Header - Binding ACK"
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+ ByteField("len", None), # unit == 8 bytes (excluding the first 8 bytes)
+ ByteEnumField("mhtype", 6, mhtypes),
+ ByteField("res", None),
+ XShortField("cksum", None),
+ ByteEnumField("status", 0, bastatus),
+ FlagsField("flags", "K", 3, "PRK"),
+ XBitField("res2", None, 5),
+ XShortField("seq", None), # TODO: ShortNonceField
+ XShortField("mhtime", 0), # unit == 4 seconds
+ _PhantomAutoPadField("autopad", 1), # autopad activated by default
+ _MobilityOptionsField("options", [], MIP6OptUnknown, 12,
+ length_from = lambda pkt: 8*pkt.len-4) ]
+ overload_fields = { IPv6: { "nh": 135 }}
+
+ def hashret(self): # Hack: see comment in MIP6MH_BRR.hashret()
+ return "\x00\x08\x09"
+
+ def answers(self, other):
+ if (isinstance(other, MIP6MH_BU) and
+ other.mhtype == 5 and
+ self.mhtype == 6 and
+ other.flags & 0x1 and # Ack request flags is set
+ self.seq == other.seq):
+ return 1
+ return 0
+
+_bestatus = { 1: 'Unknown binding for Home Address destination option',
+ 2: 'Unrecognized MH Type value' }
+
+# TODO: match Binding Error to its stimulus
+class MIP6MH_BE(_MobilityHeader):
+ name = "IPv6 Mobility Header - Binding Error"
+ fields_desc = [ ByteEnumField("nh", 59, ipv6nh),
+ ByteField("len", None), # unit == 8 bytes (excluding the first 8 bytes)
+ ByteEnumField("mhtype", 7, mhtypes),
+ ByteField("res", 0),
+ XShortField("cksum", None),
+ ByteEnumField("status", 0, _bestatus),
+ ByteField("reserved", 0),
+ IP6Field("ha", "::"),
+ _MobilityOptionsField("options", [], MIP6OptUnknown, 24,
+ length_from = lambda pkt: 8*(pkt.len-2)) ]
+ overload_fields = { IPv6: { "nh": 135 }}
+
+_mip6_mhtype2cls = { 0: MIP6MH_BRR,
+ 1: MIP6MH_HoTI,
+ 2: MIP6MH_CoTI,
+ 3: MIP6MH_HoT,
+ 4: MIP6MH_CoT,
+ 5: MIP6MH_BU,
+ 6: MIP6MH_BA,
+ 7: MIP6MH_BE }
+
+
+#############################################################################
+#############################################################################
+### Traceroute6 ###
+#############################################################################
+#############################################################################
+
+class AS_resolver6(AS_resolver_riswhois):
+ def _resolve_one(self, ip):
+ """
+ overloaded version to provide a Whois resolution on the
+ embedded IPv4 address if the address is 6to4 or Teredo.
+ Otherwise, the native IPv6 address is passed.
+ """
+
+ if in6_isaddr6to4(ip): # for 6to4, use embedded @
+ tmp = inet_pton(socket.AF_INET6, ip)
+ addr = inet_ntop(socket.AF_INET, tmp[2:6])
+ elif in6_isaddrTeredo(ip): # for Teredo, use mapped address
+ addr = teredoAddrExtractInfo(ip)[2]
+ else:
+ addr = ip
+
+ _, asn, desc = AS_resolver_riswhois._resolve_one(self, addr)
+
+ return ip,asn,desc
+
+class TracerouteResult6(TracerouteResult):
+ def show(self):
+ #return self.make_table(lambda (s,r): (s.sprintf("%-42s,IPv6.dst%:{TCP:tcp%TCP.dport%}{UDP:udp%UDP.dport%}{ICMPv6EchoRequest:IER}"), # TODO: ICMPv6 !
+ return self.make_table(lambda s,r: (s.sprintf("%-42s,IPv6.dst%:{TCP:tcp%TCP.dport%}{UDP:udp%UDP.dport%}{ICMPv6EchoRequest:IER}"), # TODO: ICMPv6 !
+ s.hlim,
+ r.sprintf("%-42s,IPv6.src% {TCP:%TCP.flags%}"+
+ "{ICMPv6DestUnreach:%ir,type%}{ICMPv6PacketTooBig:%ir,type%}"+
+ "{ICMPv6TimeExceeded:%ir,type%}{ICMPv6ParamProblem:%ir,type%}"+
+ "{ICMPv6EchoReply:%ir,type%}")))
+
+ def get_trace(self):
+ trace = {}
+
+ for s,r in self.res:
+ if IPv6 not in s:
+ continue
+ d = s[IPv6].dst
+ if d not in trace:
+ trace[d] = {}
+
+ t = not (ICMPv6TimeExceeded in r or
+ ICMPv6DestUnreach in r or
+ ICMPv6PacketTooBig in r or
+ ICMPv6ParamProblem in r)
+
+ trace[d][s[IPv6].hlim] = r[IPv6].src, t
+
+ for k in trace.values():
+ #m = filter(lambda x: k[x][1], k.keys())
+ m = [ x for x in k.keys() if k[x][1] ]
+ if not m:
+ continue
+ m = min(m)
+ for l in k.keys():
+ if l > m:
+ del(k[l])
+
+ return trace
+
+ def graph(self, ASres=AS_resolver6(), **kargs):
+ TracerouteResult.graph(self, ASres=ASres, **kargs)
+
+def traceroute6(target, dport=80, minttl=1, maxttl=30, sport=RandShort(),
+ l4 = None, timeout=2, verbose=None, **kargs):
+ """
+ Instant TCP traceroute using IPv6 :
+ traceroute6(target, [maxttl=30], [dport=80], [sport=80]) -> None
+ """
+ if verbose is None:
+ verbose = conf.verb
+
+ if l4 is None:
+ a,b = sr(IPv6(dst=target, hlim=(minttl,maxttl))/TCP(seq=RandInt(),sport=sport, dport=dport),
+ timeout=timeout, filter="icmp6 or tcp", verbose=verbose, **kargs)
+ else:
+ a,b = sr(IPv6(dst=target, hlim=(minttl,maxttl))/l4,
+ timeout=timeout, verbose=verbose, **kargs)
+
+ a = TracerouteResult6(a.res)
+
+ if verbose:
+ a.display()
+
+ return a,b
+
+#############################################################################
+#############################################################################
+### Sockets ###
+#############################################################################
+#############################################################################
+
+class L3RawSocket6(L3RawSocket):
+ def __init__(self, type = ETH_P_IPV6, filter=None, iface=None, promisc=None, nofilter=0):
+ L3RawSocket.__init__(self, type, filter, iface, promisc)
+ # NOTE: if fragmentation is needed, it will be done by the kernel (RFC 2292)
+ self.outs = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_RAW)
+ self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
+
+def IPv6inIP(dst='203.178.135.36', src=None):
+ _IPv6inIP.dst = dst
+ _IPv6inIP.src = src
+ if not conf.L3socket == _IPv6inIP:
+ _IPv6inIP.cls = conf.L3socket
+ else:
+ del(conf.L3socket)
+ return _IPv6inIP
+
+class _IPv6inIP(SuperSocket):
+ dst = '127.0.0.1'
+ src = None
+ cls = None
+
+ def __init__(self, family=socket.AF_INET6, type=socket.SOCK_STREAM, proto=0, **args):
+ SuperSocket.__init__(self, family, type, proto)
+ self.worker = self.cls(**args)
+
+ def set(self, dst, src=None):
+ _IPv6inIP.src = src
+ _IPv6inIP.dst = dst
+
+ def nonblock_recv(self):
+ p = self.worker.nonblock_recv()
+ return self._recv(p)
+
+ def recv(self, x):
+ p = self.worker.recv(x)
+ return self._recv(p, x)
+
+ def _recv(self, p, x=MTU):
+ if p is None:
+ return p
+ elif isinstance(p, IP):
+ # TODO: verify checksum
+ if p.src == self.dst and p.proto == socket.IPPROTO_IPV6:
+ if isinstance(p.payload, IPv6):
+ return p.payload
+ return p
+
+ def send(self, x):
+ return self.worker.send(IP(dst=self.dst, src=self.src, proto=socket.IPPROTO_IPV6)/x)
+
+
+#############################################################################
+#############################################################################
+### Layers binding ###
+#############################################################################
+#############################################################################
+
+conf.l3types.register(ETH_P_IPV6, IPv6)
+conf.l2types.register(31, IPv6)
+
+bind_layers(Ether, IPv6, type = 0x86dd )
+bind_layers(CookedLinux, IPv6, proto = 0x86dd )
+bind_layers(IPerror6, TCPerror, nh = socket.IPPROTO_TCP )
+bind_layers(IPerror6, UDPerror, nh = socket.IPPROTO_UDP )
+bind_layers(IPv6, TCP, nh = socket.IPPROTO_TCP )
+bind_layers(IPv6, UDP, nh = socket.IPPROTO_UDP )
+bind_layers(IP, IPv6, proto = socket.IPPROTO_IPV6 )
+bind_layers(IPv6, IPv6, nh = socket.IPPROTO_IPV6 )
+
+bind_layers(IPv6, IP, nh = IPPROTO_IPIP )
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ipsec.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ipsec.py
new file mode 100644
index 00000000..a14925fb
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ipsec.py
@@ -0,0 +1,995 @@
+#############################################################################
+## ipsec.py --- IPSec support for Scapy ##
+## ##
+## Copyright (C) 2014 6WIND ##
+## ##
+## This program is free software; you can redistribute it and/or modify it ##
+## under the terms of the GNU General Public License version 2 as ##
+## published by the Free Software Foundation. ##
+## ##
+## This program is distributed in the hope that it will be useful, but ##
+## WITHOUT ANY WARRANTY; without even the implied warranty of ##
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ##
+## General Public License for more details. ##
+#############################################################################
+"""
+IPSec layer
+===========
+
+Example of use:
+
+>>> sa = SecurityAssociation(ESP, spi=0xdeadbeef, crypt_algo='AES-CBC',
+... crypt_key='sixteenbytes key')
+>>> p = IP(src='1.1.1.1', dst='2.2.2.2')
+>>> p /= TCP(sport=45012, dport=80)
+>>> p /= Raw(b'testdata')
+>>> p = IP(bytes(p))
+>>> p
+<IP version=4L ihl=5L tos=0x0 len=48 id=1 flags= frag=0L ttl=64 proto=tcp chksum=0x74c2 src=1.1.1.1 dst=2.2.2.2 options=[] |<TCP sport=45012 dport=http seq=0 ack=0 dataofs=5L reserved=0L flags=S window=8192 chksum=0x1914 urgptr=0 options=[] |<Raw load='testdata' |>>>
+>>>
+>>> e = sa.encrypt(p)
+>>> e
+<IP version=4L ihl=5L tos=0x0 len=76 id=1 flags= frag=0L ttl=64 proto=esp chksum=0x747a src=1.1.1.1 dst=2.2.2.2 |<ESP spi=0xdeadbeef seq=1 data='\xf8\xdb\x1e\x83[T\xab\\\xd2\x1b\xed\xd1\xe5\xc8Y\xc2\xa5d\x92\xc1\x05\x17\xa6\x92\x831\xe6\xc1]\x9a\xd6K}W\x8bFfd\xa5B*+\xde\xc8\x89\xbf{\xa9' |>>
+>>>
+>>> d = sa.decrypt(e)
+>>> d
+<IP version=4L ihl=5L tos=0x0 len=48 id=1 flags= frag=0L ttl=64 proto=tcp chksum=0x74c2 src=1.1.1.1 dst=2.2.2.2 |<TCP sport=45012 dport=http seq=0 ack=0 dataofs=5L reserved=0L flags=S window=8192 chksum=0x1914 urgptr=0 options=[] |<Raw load='testdata' |>>>
+>>>
+>>> d == p
+True
+"""
+
+import socket
+
+if not hasattr(socket, 'IPPROTO_AH'):
+ socket.IPPROTO_AH = 51
+if not hasattr(socket, 'IPPROTO_ESP'):
+ socket.IPPROTO_ESP = 50
+
+
+import fractions
+
+from scapy.data import IP_PROTOS
+
+from scapy.fields import ByteEnumField, ByteField, StrField, XIntField, IntField, \
+ ShortField, PacketField
+
+from scapy.packet import Packet, bind_layers, Raw
+
+from scapy.layers.inet import IP, UDP
+from scapy.layers.inet6 import IPv6, IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt, \
+ IPv6ExtHdrRouting
+
+
+#------------------------------------------------------------------------------
+class AH(Packet):
+ """
+ Authentication Header
+
+ See https://tools.ietf.org/rfc/rfc4302.txt
+ """
+
+ name = 'AH'
+
+ fields_desc = [
+ ByteEnumField('nh', None, IP_PROTOS),
+ ByteField('payloadlen', None),
+ ShortField('reserved', None),
+ XIntField('spi', 0x0),
+ IntField('seq', 0),
+ StrField('icv', None),
+ StrField('padding', None),
+ ]
+
+ overload_fields = {
+ IP: {'proto': socket.IPPROTO_AH},
+ IPv6: {'nh': socket.IPPROTO_AH},
+ IPv6ExtHdrHopByHop: {'nh': socket.IPPROTO_AH},
+ IPv6ExtHdrDestOpt: {'nh': socket.IPPROTO_AH},
+ IPv6ExtHdrRouting: {'nh': socket.IPPROTO_AH},
+ }
+
+bind_layers(IP, AH, proto=socket.IPPROTO_AH)
+bind_layers(IPv6, AH, nh=socket.IPPROTO_AH)
+
+#------------------------------------------------------------------------------
+class ESP(Packet):
+ """
+ Encapsulated Security Payload
+
+ See https://tools.ietf.org/rfc/rfc4303.txt
+ """
+ name = 'ESP'
+
+ fields_desc = [
+ XIntField('spi', 0x0),
+ IntField('seq', 0),
+ StrField('data', None),
+ ]
+
+ overload_fields = {
+ IP: {'proto': socket.IPPROTO_ESP},
+ IPv6: {'nh': socket.IPPROTO_ESP},
+ IPv6ExtHdrHopByHop: {'nh': socket.IPPROTO_ESP},
+ IPv6ExtHdrDestOpt: {'nh': socket.IPPROTO_ESP},
+ IPv6ExtHdrRouting: {'nh': socket.IPPROTO_ESP},
+ }
+
+bind_layers(IP, ESP, proto=socket.IPPROTO_ESP)
+bind_layers(IPv6, ESP, nh=socket.IPPROTO_ESP)
+bind_layers(UDP, ESP, dport=4500) # NAT-Traversal encapsulation
+bind_layers(UDP, ESP, sport=4500) # NAT-Traversal encapsulation
+
+#------------------------------------------------------------------------------
+class _ESPPlain(Packet):
+ """
+ Internal class to represent unencrypted ESP packets.
+ """
+ name = 'ESP'
+
+ fields_desc = [
+ XIntField('spi', 0x0),
+ IntField('seq', 0),
+
+ StrField('iv', ''),
+ PacketField('data', '', Raw),
+ StrField('padding', ''),
+
+ ByteField('padlen', 0),
+ ByteEnumField('nh', 0, IP_PROTOS),
+ StrField('icv', ''),
+ ]
+
+ def data_for_encryption(self):
+ return bytes(self.data) + self.padding + chr(self.padlen).encode('ascii') + chr(self.nh).encode('ascii')
+
+#------------------------------------------------------------------------------
+try:
+ from Crypto.Cipher import AES
+ from Crypto.Cipher import DES
+ from Crypto.Cipher import DES3
+ from Crypto.Cipher import CAST
+ from Crypto.Cipher import Blowfish
+ from Crypto.Util import Counter
+ from Crypto import Random
+except ImportError:
+ # no error if pycrypto is not available but encryption won't be supported
+ AES = None
+ DES = None
+ DES3 = None
+ CAST = None
+ Blowfish = None
+ Random = None
+
+#------------------------------------------------------------------------------
+def _lcm(a, b):
+ """
+ Least Common Multiple between 2 integers.
+ """
+ if a == 0 or b == 0:
+ return 0
+ else:
+ return abs(a * b) // fractions.gcd(a, b)
+
+class CryptAlgo(object):
+ """
+ IPSec encryption algorithm
+ """
+
+ def __init__(self, name, cipher, mode, block_size=None, iv_size=None, key_size=None):
+ """
+ @param name: the name of this encryption algorithm
+ @param cipher: a Cipher module
+ @param mode: the mode used with the cipher module
+ @param block_size: the length a block for this algo. Defaults to the
+ `block_size` of the cipher.
+ @param iv_size: the length of the initialization vector of this algo.
+ Defaults to the `block_size` of the cipher.
+ @param key_size: an integer or list/tuple of integers. If specified,
+ force the secret keys length to one of the values.
+ Defaults to the `key_size` of the cipher.
+ """
+ self.name = name
+ self.cipher = cipher
+ self.mode = mode
+
+ if block_size is not None:
+ self.block_size = block_size
+ elif cipher is not None:
+ self.block_size = cipher.block_size
+ else:
+ self.block_size = 1
+
+ if iv_size is None:
+ self.iv_size = self.block_size
+ else:
+ self.iv_size = iv_size
+
+ if key_size is not None:
+ self.key_size = key_size
+ elif cipher is not None:
+ self.key_size = cipher.key_size
+ else:
+ self.key_size = None
+
+ def check_key(self, key):
+ """
+ Check that the key length is valid.
+
+ @param key: a byte string
+ """
+ if self.key_size and not (len(key) == self.key_size or len(key) in self.key_size):
+ raise TypeError('invalid key size %s, must be %s' %
+ (len(key), self.key_size))
+
+ def generate_iv(self):
+ """
+ Generate a random initialization vector. If pycrypto is not available,
+ return a buffer of the correct length filled with only '\x00'.
+ """
+ if Random:
+ return Random.get_random_bytes(self.iv_size)
+ else:
+ return chr(0) * self.iv_size
+
+ def new_cipher(self, key, iv):
+ """
+ @param key: the secret key, a byte string
+ @param iv: the initialization vector, a byte string
+ @return: an initialized cipher object for this algo
+ """
+ if type(key) is str:
+ key = key.encode('ascii')
+ if (hasattr(self.cipher, 'MODE_CTR') and self.mode == self.cipher.MODE_CTR
+ or hasattr(self.cipher, 'MODE_GCM') and self.mode == self.cipher.MODE_GCM):
+ # in counter mode, the "iv" must be incremented for each block
+ # it is calculated like this:
+ # +---------+------------------+---------+
+ # | nonce | IV | counter |
+ # +---------+------------------+---------+
+ # m bytes n bytes 4 bytes
+ # <-------------------------------------->
+ # block_size
+ nonce_size = self.cipher.block_size - self.iv_size - 4
+
+ # instead of asking for an extra parameter, we extract the last
+ # nonce_size bytes of the key and use them as the nonce.
+ # +----------------------------+---------+
+ # | cipher key | nonce |
+ # +----------------------------+---------+
+ # <--------->
+ # nonce_size
+ cipher_key, nonce = key[:-nonce_size], key[-nonce_size:]
+
+ return self.cipher.new(cipher_key, self.mode,
+ counter=Counter.new(4 * 8, prefix=nonce + iv))
+ else:
+ return self.cipher.new(key, self.mode, iv)
+
+ def pad(self, esp):
+ """
+ Add the correct amount of padding so that the data to encrypt is
+ exactly a multiple of the algorithm's block size.
+
+ Also, make sure that the total ESP packet length is a multiple of 4 or
+ 8 bytes with IP or IPv6 respectively.
+
+ @param esp: an unencrypted _ESPPlain packet
+ """
+ # 2 extra bytes for padlen and nh
+ data_len = len(esp.data) + 2
+
+ # according to the RFC4303, section 2.4. Padding (for Encryption)
+ # the size of the ESP payload must be a multiple of 32 bits
+ align = _lcm(self.block_size, 4)
+
+ # pad for block size
+ esp.padlen = -data_len % align
+
+ # padding must be an array of bytes starting from 1 to padlen
+ esp.padding = ''
+ for b in range(1, esp.padlen + 1):
+ esp.padding += bytes([b])
+
+ # If the following test fails, it means that this algo does not comply
+ # with the RFC
+ payload_len = len(esp.iv) + len(esp.data) + len(esp.padding) + 2
+ if payload_len % 4 != 0:
+ raise ValueError('The size of the ESP data is not aligned to 32 bits after padding.')
+
+ return esp
+
+ def encrypt(self, esp, key):
+ """
+ Encrypt an ESP packet
+
+ @param esp: an unencrypted _ESPPlain packet with valid padding
+ @param key: the secret key used for encryption
+
+ @return: a valid ESP packet encrypted with this algorithm
+ """
+ data = esp.data_for_encryption()
+
+ if self.cipher:
+ self.check_key(key)
+ cipher = self.new_cipher(key, esp.iv)
+ data = cipher.encrypt(data)
+
+ return ESP(spi=esp.spi, seq=esp.seq, data=esp.iv + data)
+
+ def decrypt(self, esp, key, icv_size=0):
+ """
+ Decrypt an ESP packet
+
+ @param esp: an encrypted ESP packet
+ @param key: the secret key used for encryption
+ @param icv_size: the length of the icv used for integrity check
+
+ @return: a valid ESP packet encrypted with this algorithm
+ """
+ self.check_key(key)
+
+ iv = esp.data[:self.iv_size]
+ data = esp.data[self.iv_size:len(esp.data) - icv_size]
+ icv = esp.data[len(esp.data) - icv_size:]
+
+ if self.cipher:
+ cipher = self.new_cipher(key, iv)
+ data = cipher.decrypt(data)
+
+ # extract padlen and nh
+ #padlen = ord(data[-2])
+ padlen = (data[-2])
+ #nh = ord(data[-1])
+ nh = (data[-1])
+
+ # then use padlen to determine data and padding
+ data = data[:len(data) - padlen - 2]
+ padding = data[len(data) - padlen - 2: len(data) - 2]
+
+ return _ESPPlain(spi=esp.spi,
+ seq=esp.seq,
+ iv=iv,
+ data=data,
+ padding=padding,
+ padlen=padlen,
+ nh=nh,
+ icv=icv)
+
+#------------------------------------------------------------------------------
+# The names of the encryption algorithms are the same than in scapy.contrib.ikev2
+# see http://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml
+
+CRYPT_ALGOS = {
+ 'NULL': CryptAlgo('NULL', cipher=None, mode=None, iv_size=0),
+}
+
+if AES:
+ CRYPT_ALGOS['AES-CBC'] = CryptAlgo('AES-CBC',
+ cipher=AES,
+ mode=AES.MODE_CBC)
+ # specific case for counter mode:
+ # the last 4 bytes of the key are used to carry the nonce of the counter
+ CRYPT_ALGOS['AES-CTR'] = CryptAlgo('AES-CTR',
+ cipher=AES,
+ mode=AES.MODE_CTR,
+ block_size=1,
+ iv_size=8,
+ key_size=(16 + 4, 24 + 4, 32 + 4))
+if DES:
+ CRYPT_ALGOS['DES'] = CryptAlgo('DES',
+ cipher=DES,
+ mode=DES.MODE_CBC)
+if Blowfish:
+ CRYPT_ALGOS['Blowfish'] = CryptAlgo('Blowfish',
+ cipher=Blowfish,
+ mode=Blowfish.MODE_CBC)
+if DES3:
+ CRYPT_ALGOS['3DES'] = CryptAlgo('3DES',
+ cipher=DES3,
+ mode=DES3.MODE_CBC)
+if CAST:
+ CRYPT_ALGOS['CAST'] = CryptAlgo('CAST',
+ cipher=CAST,
+ mode=CAST.MODE_CBC)
+
+#------------------------------------------------------------------------------
+try:
+ from Crypto.Hash import HMAC
+ from Crypto.Hash import SHA
+ from Crypto.Hash import MD5
+ from Crypto.Hash import SHA256
+ from Crypto.Hash import SHA384
+ from Crypto.Hash import SHA512
+except ImportError:
+ # no error if pycrypto is not available but authentication won't be supported
+ HMAC = None
+ SHA = None
+ MD5 = None
+ SHA256 = None
+ SHA384 = None
+try:
+ from Crypto.Hash import XCBCMAC
+except ImportError:
+ XCBCMAC = None
+
+#------------------------------------------------------------------------------
+class IPSecIntegrityError(Exception):
+ """
+ Error risen when the integrity check fails.
+ """
+ pass
+
+class AuthAlgo(object):
+ """
+ IPSec integrity algorithm
+ """
+
+ def __init__(self, name, mac, digestmod, icv_size, key_size=None):
+ """
+ @param name: the name of this integrity algorithm
+ @param mac: a Message Authentication Code module
+ @param digestmod: a Hash or Cipher module
+ @param icv_size: the length of the integrity check value of this algo
+ @param key_size: an integer or list/tuple of integers. If specified,
+ force the secret keys length to one of the values.
+ Defaults to the `key_size` of the cipher.
+ """
+ self.name = name
+ self.mac = mac
+ self.digestmod = digestmod
+ self.icv_size = icv_size
+ self.key_size = key_size
+
+ def check_key(self, key):
+ """
+ Check that the key length is valid.
+
+ @param key: a byte string
+ """
+ if self.key_size and len(key) not in self.key_size:
+ raise TypeError('invalid key size %s, must be one of %s' %
+ (len(key), self.key_size))
+
+ def new_mac(self, key):
+ """
+ @param key: a byte string
+ @return: an initialized mac object for this algo
+ """
+ if type(key) is str:
+ key = key.encode('ascii')
+ if self.mac is XCBCMAC:
+ # specific case here, ciphermod instead of digestmod
+ return self.mac.new(key, ciphermod=self.digestmod)
+ else:
+ print(self.mac)
+ return self.mac.new(key, digestmod=self.digestmod)
+
+ def sign(self, pkt, key):
+ """
+ Sign an IPSec (ESP or AH) packet with this algo.
+
+ @param pkt: a packet that contains a valid encrypted ESP or AH layer
+ @param key: the authentication key, a byte string
+
+ @return: the signed packet
+ """
+ if not self.mac:
+ return pkt
+
+ self.check_key(key)
+
+ mac = self.new_mac(key)
+
+ if pkt.haslayer(ESP):
+ mac.update(bytes(pkt[ESP]))
+ pkt[ESP].data += mac.digest()[:self.icv_size]
+
+ elif pkt.haslayer(AH):
+ clone = zero_mutable_fields(pkt.copy(), sending=True)
+ mac.update(bytes(clone))
+ pkt[AH].icv = mac.digest()[:self.icv_size]
+
+ return pkt
+
+ def verify(self, pkt, key):
+ """
+ Check that the integrity check value (icv) of a packet is valid.
+
+ @param pkt: a packet that contains a valid encrypted ESP or AH layer
+ @param key: the authentication key, a byte string
+
+ @raise IPSecIntegrityError: if the integrity check fails
+ """
+ if not self.mac or self.icv_size == 0:
+ return
+
+ self.check_key(key)
+
+ mac = self.new_mac(key)
+
+ pkt_icv = 'not found'
+ computed_icv = 'not computed'
+
+ if isinstance(pkt, ESP):
+ pkt_icv = pkt.data[len(pkt.data) - self.icv_size:]
+
+ pkt = pkt.copy()
+ pkt.data = pkt.data[:len(pkt.data) - self.icv_size]
+ mac.update(bytes(pkt))
+ computed_icv = mac.digest()[:self.icv_size]
+
+ elif pkt.haslayer(AH):
+ pkt_icv = pkt[AH].icv[:self.icv_size]
+
+ clone = zero_mutable_fields(pkt.copy(), sending=False)
+ mac.update(bytes(clone))
+ computed_icv = mac.digest()[:self.icv_size]
+
+ if pkt_icv != computed_icv:
+ raise IPSecIntegrityError('pkt_icv=%r, computed_icv=%r' %
+ (pkt_icv, computed_icv))
+
+#------------------------------------------------------------------------------
+# The names of the integrity algorithms are the same than in scapy.contrib.ikev2
+# see http://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml
+
+AUTH_ALGOS = {
+ 'NULL': AuthAlgo('NULL', mac=None, digestmod=None, icv_size=0),
+}
+
+if HMAC:
+ if SHA:
+ AUTH_ALGOS['HMAC-SHA1-96'] = AuthAlgo('HMAC-SHA1-96',
+ mac=HMAC,
+ digestmod=SHA,
+ icv_size=12)
+ if SHA256:
+ AUTH_ALGOS['SHA2-256-128'] = AuthAlgo('SHA2-256-128',
+ mac=HMAC,
+ digestmod=SHA256,
+ icv_size=16)
+ if SHA384:
+ AUTH_ALGOS['SHA2-384-192'] = AuthAlgo('SHA2-384-192',
+ mac=HMAC,
+ digestmod=SHA384,
+ icv_size=24)
+ if SHA512:
+ AUTH_ALGOS['SHA2-512-256'] = AuthAlgo('SHA2-512-256',
+ mac=HMAC,
+ digestmod=SHA512,
+ icv_size=32)
+ if MD5:
+ AUTH_ALGOS['HMAC-MD5-96'] = AuthAlgo('HMAC-MD5-96',
+ mac=HMAC,
+ digestmod=MD5,
+ icv_size=12)
+if AES and XCBCMAC:
+ AUTH_ALGOS['AES-XCBC-96'] = AuthAlgo('AES-XCBC-96',
+ mac=XCBCMAC,
+ digestmod=AES,
+ icv_size=12,
+ key_size=(16,))
+
+#------------------------------------------------------------------------------
+
+
+#------------------------------------------------------------------------------
+def split_for_transport(orig_pkt, transport_proto):
+ """
+ Split an IP(v6) packet in the correct location to insert an ESP or AH
+ header.
+
+ @param orig_pkt: the packet to split. Must be an IP or IPv6 packet
+ @param transport_proto: the IPSec protocol number that will be inserted
+ at the split position.
+ @return: a tuple (header, nh, payload) where nh is the protocol number of
+ payload.
+ """
+ header = orig_pkt.copy()
+ next_hdr = header.payload
+ nh = None
+
+ if header.version == 4:
+ nh = header.proto
+ header.proto = transport_proto
+ header.remove_payload()
+ del header.chksum
+ del header.len
+
+ return header, nh, next_hdr
+ else:
+ found_rt_hdr = False
+ prev = header
+
+ # Since the RFC 4302 is vague about where the ESP/AH headers should be
+ # inserted in IPv6, I chose to follow the linux implementation.
+ while isinstance(next_hdr, (IPv6ExtHdrHopByHop, IPv6ExtHdrRouting, IPv6ExtHdrDestOpt)):
+ if isinstance(next_hdr, IPv6ExtHdrHopByHop):
+ pass
+ if isinstance(next_hdr, IPv6ExtHdrRouting):
+ found_rt_hdr = True
+ elif isinstance(next_hdr, IPv6ExtHdrDestOpt) and found_rt_hdr:
+ break
+
+ prev = next_hdr
+ next_hdr = next_hdr.payload
+
+ nh = prev.nh
+ prev.nh = transport_proto
+ prev.remove_payload()
+ del header.plen
+
+ return header, nh, next_hdr
+
+#------------------------------------------------------------------------------
+# see RFC 4302 - Appendix A. Mutability of IP Options/Extension Headers
+IMMUTABLE_IPV4_OPTIONS = (
+ 0, # End Of List
+ 1, # No OPeration
+ 2, # Security
+ 5, # Extended Security
+ 6, # Commercial Security
+ 20, # Router Alert
+ 21, # Sender Directed Multi-Destination Delivery
+)
+def zero_mutable_fields(pkt, sending=False):
+ """
+ When using AH, all "mutable" fields must be "zeroed" before calculating
+ the ICV. See RFC 4302, Section 3.3.3.1. Handling Mutable Fields.
+
+ @param pkt: an IP(v6) packet containing an AH layer.
+ NOTE: The packet will be modified
+ @param sending: if true, ipv6 routing headers will not be reordered
+ """
+
+ if pkt.haslayer(AH):
+ pkt[AH].icv = chr(0) * len(pkt[AH].icv)
+ else:
+ raise TypeError('no AH layer found')
+
+ if pkt.version == 4:
+ # the tos field has been replaced by DSCP and ECN
+ # Routers may rewrite the DS field as needed to provide a
+ # desired local or end-to-end service
+ pkt.tos = 0
+ # an intermediate router might set the DF bit, even if the source
+ # did not select it.
+ pkt.flags = 0
+ # changed en route as a normal course of processing by routers
+ pkt.ttl = 0
+ # will change if any of these other fields change
+ pkt.chksum = 0
+
+ immutable_opts = []
+ for opt in pkt.options:
+ if opt.option in IMMUTABLE_IPV4_OPTIONS:
+ immutable_opts.append(opt)
+ else:
+ immutable_opts.append(Raw(chr(0) * len(opt)))
+ pkt.options = immutable_opts
+
+ else:
+ # holds DSCP and ECN
+ pkt.tc = 0
+ # The flow label described in AHv1 was mutable, and in RFC 2460 [DH98]
+ # was potentially mutable. To retain compatibility with existing AH
+ # implementations, the flow label is not included in the ICV in AHv2.
+ pkt.fl = 0
+ # same as ttl
+ pkt.hlim = 0
+
+ next_hdr = pkt.payload
+
+ while isinstance(next_hdr, (IPv6ExtHdrHopByHop, IPv6ExtHdrRouting, IPv6ExtHdrDestOpt)):
+ if isinstance(next_hdr, (IPv6ExtHdrHopByHop, IPv6ExtHdrDestOpt)):
+ for opt in next_hdr.options:
+ if opt.otype & 0x20:
+ # option data can change en-route and must be zeroed
+ opt.optdata = chr(0) * opt.optlen
+ elif isinstance(next_hdr, IPv6ExtHdrRouting) and sending:
+ # The sender must order the field so that it appears as it
+ # will at the receiver, prior to performing the ICV computation.
+ next_hdr.segleft = 0
+ if next_hdr.addresses:
+ final = next_hdr.addresses.pop()
+ next_hdr.addresses.insert(0, pkt.dst)
+ pkt.dst = final
+ else:
+ break
+
+ next_hdr = next_hdr.payload
+
+ return pkt
+
+#------------------------------------------------------------------------------
+class SecurityAssociation(object):
+ """
+ This class is responsible of "encryption" and "decryption" of IPSec packets.
+ """
+
+ SUPPORTED_PROTOS = (IP, IPv6)
+
+ def __init__(self, proto, spi, seq_num=1, crypt_algo=None, crypt_key=None,
+ auth_algo=None, auth_key=None, tunnel_header=None, nat_t_header=None):
+ """
+ @param proto: the IPSec proto to use (ESP or AH)
+ @param spi: the Security Parameters Index of this SA
+ @param seq_num: the initial value for the sequence number on encrypted
+ packets
+ @param crypt_algo: the encryption algorithm name (only used with ESP)
+ @param crypt_key: the encryption key (only used with ESP)
+ @param auth_algo: the integrity algorithm name
+ @param auth_key: the integrity key
+ @param tunnel_header: an instance of a IP(v6) header that will be used
+ to encapsulate the encrypted packets.
+ @param nat_t_header: an instance of a UDP header that will be used
+ for NAT-Traversal.
+ """
+
+ if proto not in (ESP, AH, ESP.name, AH.name):
+ raise ValueError("proto must be either ESP or AH")
+ if isinstance(proto, str):
+ self.proto = eval(proto)
+ else:
+ self.proto = proto
+
+ self.spi = spi
+ self.seq_num = seq_num
+
+ if crypt_algo:
+ if crypt_algo not in CRYPT_ALGOS:
+ raise TypeError('unsupported encryption algo %r, try %r' %
+ (crypt_algo, CRYPT_ALGOS.keys()))
+ self.crypt_algo = CRYPT_ALGOS[crypt_algo]
+ self.crypt_algo.check_key(crypt_key)
+ self.crypt_key = crypt_key
+ else:
+ self.crypt_algo = CRYPT_ALGOS['NULL']
+ self.crypt_key = None
+
+ if auth_algo:
+ if auth_algo not in AUTH_ALGOS:
+ raise TypeError('unsupported integrity algo %r, try %r' %
+ (auth_algo, AUTH_ALGOS.keys()))
+ self.auth_algo = AUTH_ALGOS[auth_algo]
+ self.auth_algo.check_key(auth_key)
+ self.auth_key = auth_key
+ else:
+ self.auth_algo = AUTH_ALGOS['NULL']
+ self.auth_key = None
+
+ if tunnel_header and not isinstance(tunnel_header, (IP, IPv6)):
+ raise TypeError('tunnel_header must be %s or %s' % (IP.name, IPv6.name))
+ self.tunnel_header = tunnel_header
+
+ if nat_t_header:
+ if proto is not ESP:
+ raise TypeError('nat_t_header is only allowed with ESP')
+ if not isinstance(nat_t_header, UDP):
+ raise TypeError('nat_t_header must be %s' % UDP.name)
+ self.nat_t_header = nat_t_header
+
+ def check_spi(self, pkt):
+ if pkt.spi != self.spi:
+ raise TypeError('packet spi=0x%x does not match the SA spi=0x%x' %
+ (pkt.spi, self.spi))
+
+ def _encrypt_esp(self, pkt, seq_num=None, iv=None):
+
+ if iv is None:
+ iv = self.crypt_algo.generate_iv()
+ else:
+ if len(iv) != self.crypt_algo.iv_size:
+ raise TypeError('iv length must be %s' % self.crypt_algo.iv_size)
+
+ esp = _ESPPlain(spi=self.spi, seq=seq_num or self.seq_num, iv=iv)
+
+ if self.tunnel_header:
+ tunnel = self.tunnel_header.copy()
+
+ if tunnel.version == 4:
+ del tunnel.proto
+ del tunnel.len
+ del tunnel.chksum
+ else:
+ del tunnel.nh
+ del tunnel.plen
+
+ pkt = tunnel.__class__(bytes(tunnel / pkt))
+
+ ip_header, nh, payload = split_for_transport(pkt, socket.IPPROTO_ESP)
+ esp.data = payload
+ esp.nh = nh
+
+ esp = self.crypt_algo.pad(esp)
+ esp = self.crypt_algo.encrypt(esp, self.crypt_key)
+
+ self.auth_algo.sign(esp, self.auth_key)
+
+ if self.nat_t_header:
+ nat_t_header = self.nat_t_header.copy()
+ nat_t_header.chksum = 0
+ del nat_t_header.len
+ if ip_header.version == 4:
+ del ip_header.proto
+ else:
+ del ip_header.nh
+ ip_header /= nat_t_header
+
+ if ip_header.version == 4:
+ ip_header.len = len(ip_header) + len(esp)
+ del ip_header.chksum
+ ip_header = ip_header.__class__(bytes(ip_header))
+ else:
+ ip_header.plen = len(ip_header.payload) + len(esp)
+
+ # sequence number must always change, unless specified by the user
+ if seq_num is None:
+ self.seq_num += 1
+
+ return ip_header / esp
+
+ def _encrypt_ah(self, pkt, seq_num=None):
+
+ ah = AH(spi=self.spi, seq=seq_num or self.seq_num,
+ icv=chr(0) * self.auth_algo.icv_size)
+
+ if self.tunnel_header:
+ tunnel = self.tunnel_header.copy()
+
+ if tunnel.version == 4:
+ del tunnel.proto
+ del tunnel.len
+ del tunnel.chksum
+ else:
+ del tunnel.nh
+ del tunnel.plen
+
+ pkt = tunnel.__class__(bytes(tunnel / pkt))
+
+ ip_header, nh, payload = split_for_transport(pkt, socket.IPPROTO_AH)
+ ah.nh = nh
+
+ if ip_header.version == 6 and len(ah) % 8 != 0:
+ # For IPv6, the total length of the header must be a multiple of
+ # 8-octet units.
+ ah.padding = chr(0) * (-len(ah) % 8)
+ elif len(ah) % 4 != 0:
+ # For IPv4, the total length of the header must be a multiple of
+ # 4-octet units.
+ ah.padding = chr(0) * (-len(ah) % 4)
+
+ # RFC 4302 - Section 2.2. Payload Length
+ # This 8-bit field specifies the length of AH in 32-bit words (4-byte
+ # units), minus "2".
+ ah.payloadlen = len(ah) // 4 - 2
+
+ if ip_header.version == 4:
+ ip_header.len = len(ip_header) + len(ah) + len(payload)
+ del ip_header.chksum
+ ip_header = ip_header.__class__(bytes(ip_header))
+ else:
+ ip_header.plen = len(ip_header.payload) + len(ah) + len(payload)
+
+ signed_pkt = self.auth_algo.sign(ip_header / ah / payload, self.auth_key)
+
+ # sequence number must always change, unless specified by the user
+ if seq_num is None:
+ self.seq_num += 1
+
+ return signed_pkt
+
+ def encrypt(self, pkt, seq_num=None, iv=None):
+ """
+ Encrypt (and encapsulate) an IP(v6) packet with ESP or AH according
+ to this SecurityAssociation.
+
+ @param pkt: the packet to encrypt
+ @param seq_num: if specified, use this sequence number instead of the
+ generated one
+ @param iv: if specified, use this initialization vector for
+ encryption instead of a random one.
+
+ @return: the encrypted/encapsulated packet
+ """
+ if not isinstance(pkt, self.SUPPORTED_PROTOS):
+ raise TypeError('cannot encrypt %s, supported protos are %s'
+ % (pkt.__class__, self.SUPPORTED_PROTOS))
+ if self.proto is ESP:
+ return self._encrypt_esp(pkt, seq_num=seq_num, iv=iv)
+ else:
+ return self._encrypt_ah(pkt, seq_num=seq_num)
+
+ def _decrypt_esp(self, pkt, verify=True):
+
+ encrypted = pkt[ESP]
+
+ if verify:
+ self.check_spi(pkt)
+ self.auth_algo.verify(encrypted, self.auth_key)
+
+ esp = self.crypt_algo.decrypt(encrypted, self.crypt_key,
+ self.auth_algo.icv_size)
+
+ if self.tunnel_header:
+ # drop the tunnel header and return the payload untouched
+
+ pkt.remove_payload()
+ if pkt.version == 4:
+ pkt.proto = esp.nh
+ else:
+ pkt.nh = esp.nh
+ cls = pkt.guess_payload_class(esp.data)
+
+ return cls(esp.data)
+ else:
+ ip_header = pkt
+
+ if ip_header.version == 4:
+ ip_header.proto = esp.nh
+ del ip_header.chksum
+ ip_header.remove_payload()
+ ip_header.len = len(ip_header) + len(esp.data)
+ # recompute checksum
+ ip_header = ip_header.__class__(bytes(ip_header))
+ else:
+ encrypted.underlayer.nh = esp.nh
+ encrypted.underlayer.remove_payload()
+ ip_header.plen = len(ip_header.payload) + len(esp.data)
+
+ cls = ip_header.guess_payload_class(esp.data)
+
+ # reassemble the ip_header with the ESP payload
+ return ip_header / cls(esp.data)
+
+ def _decrypt_ah(self, pkt, verify=True):
+
+ if verify:
+ self.check_spi(pkt)
+ self.auth_algo.verify(pkt, self.auth_key)
+
+ ah = pkt[AH]
+ payload = ah.payload
+ payload.remove_underlayer(None) # useless argument...
+
+ if self.tunnel_header:
+ return payload
+ else:
+ ip_header = pkt
+
+ if ip_header.version == 4:
+ ip_header.proto = ah.nh
+ del ip_header.chksum
+ ip_header.remove_payload()
+ ip_header.len = len(ip_header) + len(payload)
+ # recompute checksum
+ ip_header = ip_header.__class__(bytes(ip_header))
+ else:
+ ah.underlayer.nh = ah.nh
+ ah.underlayer.remove_payload()
+ ip_header.plen = len(ip_header.payload) + len(payload)
+
+ # reassemble the ip_header with the AH payload
+ return ip_header / payload
+
+ def decrypt(self, pkt, verify=True):
+ """
+ Decrypt (and decapsulate) an IP(v6) packet containing ESP or AH.
+
+ @param pkt: the packet to decrypt
+ @param verify: if False, do not perform the integrity check
+
+ @return: the decrypted/decapsulated packet
+ @raise IPSecIntegrityError: if the integrity check fails
+ """
+ if not isinstance(pkt, self.SUPPORTED_PROTOS):
+ raise TypeError('cannot decrypt %s, supported protos are %s'
+ % (pkt.__class__, self.SUPPORTED_PROTOS))
+
+ if self.proto is ESP and pkt.haslayer(ESP):
+ return self._decrypt_esp(pkt, verify=verify)
+ elif self.proto is AH and pkt.haslayer(AH):
+ return self._decrypt_ah(pkt, verify=verify)
+ else:
+ raise TypeError('%s has no %s layer' % (pkt, self.proto.name))
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ir.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ir.py
new file mode 100644
index 00000000..90935aa3
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ir.py
@@ -0,0 +1,44 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+IrDA infrared data communication.
+"""
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.l2 import CookedLinux
+
+
+
+# IR
+
+class IrLAPHead(Packet):
+ name = "IrDA Link Access Protocol Header"
+ fields_desc = [ XBitField("Address", 0x7f, 7),
+ BitEnumField("Type", 1, 1, {"Response":0,
+ "Command":1})]
+
+class IrLAPCommand(Packet):
+ name = "IrDA Link Access Protocol Command"
+ fields_desc = [ XByteField("Control", 0),
+ XByteField("Format identifier", 0),
+ XIntField("Source address", 0),
+ XIntField("Destination address", 0xffffffff),
+ XByteField("Discovery flags", 0x1),
+ ByteEnumField("Slot number", 255, {"final":255}),
+ XByteField("Version", 0)]
+
+
+class IrLMP(Packet):
+ name = "IrDA Link Management Protocol"
+ fields_desc = [ XShortField("Service hints", 0),
+ XByteField("Character set", 0),
+ StrField("Device name", "") ]
+
+
+bind_layers( CookedLinux, IrLAPHead, proto=23)
+bind_layers( IrLAPHead, IrLAPCommand, Type=1)
+bind_layers( IrLAPCommand, IrLMP, )
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/isakmp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/isakmp.py
new file mode 100644
index 00000000..97def8f5
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/isakmp.py
@@ -0,0 +1,355 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+ISAKMP (Internet Security Association and Key Management Protocol).
+"""
+
+import struct
+from scapy.packet import *
+from scapy.fields import *
+from scapy.ansmachine import *
+from scapy.layers.inet import IP,UDP
+from scapy.sendrecv import sr
+
+
+# see http://www.iana.org/assignments/ipsec-registry for details
+ISAKMPAttributeTypes= { "Encryption": (1, { "DES-CBC" : 1,
+ "IDEA-CBC" : 2,
+ "Blowfish-CBC" : 3,
+ "RC5-R16-B64-CBC" : 4,
+ "3DES-CBC" : 5,
+ "CAST-CBC" : 6,
+ "AES-CBC" : 7,
+ "CAMELLIA-CBC" : 8, }, 0),
+ "Hash": (2, { "MD5": 1,
+ "SHA": 2,
+ "Tiger": 3,
+ "SHA2-256": 4,
+ "SHA2-384": 5,
+ "SHA2-512": 6,}, 0),
+ "Authentication":(3, { "PSK": 1,
+ "DSS": 2,
+ "RSA Sig": 3,
+ "RSA Encryption": 4,
+ "RSA Encryption Revised": 5,
+ "ElGamal Encryption": 6,
+ "ElGamal Encryption Revised": 7,
+ "ECDSA Sig": 8,
+ "HybridInitRSA": 64221,
+ "HybridRespRSA": 64222,
+ "HybridInitDSS": 64223,
+ "HybridRespDSS": 64224,
+ "XAUTHInitPreShared": 65001,
+ "XAUTHRespPreShared": 65002,
+ "XAUTHInitDSS": 65003,
+ "XAUTHRespDSS": 65004,
+ "XAUTHInitRSA": 65005,
+ "XAUTHRespRSA": 65006,
+ "XAUTHInitRSAEncryption": 65007,
+ "XAUTHRespRSAEncryption": 65008,
+ "XAUTHInitRSARevisedEncryption": 65009,
+ "XAUTHRespRSARevisedEncryptio": 65010, }, 0),
+ "GroupDesc": (4, { "768MODPgr" : 1,
+ "1024MODPgr" : 2,
+ "EC2Ngr155" : 3,
+ "EC2Ngr185" : 4,
+ "1536MODPgr" : 5,
+ "2048MODPgr" : 14,
+ "3072MODPgr" : 15,
+ "4096MODPgr" : 16,
+ "6144MODPgr" : 17,
+ "8192MODPgr" : 18, }, 0),
+ "GroupType": (5, {"MODP": 1,
+ "ECP": 2,
+ "EC2N": 3}, 0),
+ "GroupPrime": (6, {}, 1),
+ "GroupGenerator1":(7, {}, 1),
+ "GroupGenerator2":(8, {}, 1),
+ "GroupCurveA": (9, {}, 1),
+ "GroupCurveB": (10, {}, 1),
+ "LifeType": (11, {"Seconds": 1,
+ "Kilobytes": 2, }, 0),
+ "LifeDuration": (12, {}, 1),
+ "PRF": (13, {}, 0),
+ "KeyLength": (14, {}, 0),
+ "FieldSize": (15, {}, 0),
+ "GroupOrder": (16, {}, 1),
+ }
+
+# the name 'ISAKMPTransformTypes' is actually a misnomer (since the table
+# holds info for all ISAKMP Attribute types, not just transforms, but we'll
+# keep it for backwards compatibility... for now at least
+ISAKMPTransformTypes = ISAKMPAttributeTypes
+
+ISAKMPTransformNum = {}
+for n in ISAKMPTransformTypes:
+ val = ISAKMPTransformTypes[n]
+ tmp = {}
+ for e in val[1]:
+ tmp[val[1][e]] = e
+ ISAKMPTransformNum[val[0]] = (n,tmp, val[2])
+del(n)
+del(e)
+del(tmp)
+del(val)
+
+
+class ISAKMPTransformSetField(StrLenField):
+ islist=1
+ #def type2num(self, (typ,val)):
+ def type2num(self, typval):
+ typ = typval[0]
+ val = typval[1]
+ type_val,enc_dict,tlv = ISAKMPTransformTypes.get(typval[0], (typval[0],{},0))
+ val = enc_dict.get(val, val)
+ s = b""
+ if (val & ~0xffff):
+ if not tlv:
+ warning("%r should not be TLV but is too big => using TLV encoding" % typval[0])
+ n = 0
+ while val:
+ s = bytes([(val&0xff)])+s
+ val >>= 8
+ n += 1
+ val = n
+ else:
+ type_val |= 0x8000
+ return struct.pack("!HH",type_val, val)+s
+ def num2type(self, typ, enc):
+ val = ISAKMPTransformNum.get(typ,(typ,{}))
+ enc = val[1].get(enc,enc)
+ return (val[0],enc)
+ def i2m(self, pkt, i):
+ if i is None:
+ return b""
+ i = map(self.type2num, i)
+ return b"".join(i)
+ def m2i(self, pkt, m):
+ # I try to ensure that we don't read off the end of our packet based
+ # on bad length fields we're provided in the packet. There are still
+ # conditions where struct.unpack() may not get enough packet data, but
+ # worst case that should result in broken attributes (which would
+ # be expected). (wam)
+ lst = []
+ while len(m) >= 4:
+ trans_type, = struct.unpack("!H", m[:2])
+ is_tlv = not (trans_type & 0x8000)
+ if is_tlv:
+ # We should probably check to make sure the attribute type we
+ # are looking at is allowed to have a TLV format and issue a
+ # warning if we're given an TLV on a basic attribute.
+ value_len, = struct.unpack("!H", m[2:4])
+ if value_len+4 > len(m):
+ warning("Bad length for ISAKMP tranform type=%#6x" % trans_type)
+ value = m[4:4+value_len]
+ r = 0
+ for i in struct.unpack("!%s" % ("B"*len(value),), value):
+ r = (r << 8) | i
+ value = r
+ #value = reduce(lambda x,y: (x<<8)|y, struct.unpack("!%s" % ("B"*len(value),), value),0)
+ else:
+ trans_type &= 0x7fff
+ value_len=0
+ value, = struct.unpack("!H", m[2:4])
+ m=m[4+value_len:]
+ lst.append(self.num2type(trans_type, value))
+ if len(m) > 0:
+ warning("Extra bytes after ISAKMP transform dissection [%r]" % m)
+ return lst
+
+
+ISAKMP_payload_type = ["None","SA","Proposal","Transform","KE","ID","CERT","CR","Hash",
+ "SIG","Nonce","Notification","Delete","VendorID"]
+
+ISAKMP_exchange_type = ["None","base","identity prot.",
+ "auth only", "aggressive", "info"]
+
+
+class ISAKMP_class(Packet):
+ def guess_payload_class(self, payload):
+ np = self.next_payload
+ if np == 0:
+ return conf.raw_layer
+ elif np < len(ISAKMP_payload_type):
+ pt = ISAKMP_payload_type[np]
+ return globals().get("ISAKMP_payload_%s" % pt, ISAKMP_payload)
+ else:
+ return ISAKMP_payload
+
+
+class ISAKMP(ISAKMP_class): # rfc2408
+ name = "ISAKMP"
+ fields_desc = [
+ StrFixedLenField("init_cookie","",8),
+ StrFixedLenField("resp_cookie","",8),
+ ByteEnumField("next_payload",0,ISAKMP_payload_type),
+ XByteField("version",0x10),
+ ByteEnumField("exch_type",0,ISAKMP_exchange_type),
+ FlagsField("flags",0, 8, ["encryption","commit","auth_only","res3","res4","res5","res6","res7"]), # XXX use a Flag field
+ IntField("id",0),
+ IntField("length",None)
+ ]
+
+ def guess_payload_class(self, payload):
+ if self.flags & 1:
+ return conf.raw_layer
+ return ISAKMP_class.guess_payload_class(self, payload)
+
+ def answers(self, other):
+ if isinstance(other, ISAKMP):
+ if other.init_cookie == self.init_cookie:
+ return 1
+ return 0
+ def post_build(self, p, pay):
+ p += pay
+ if self.length is None:
+ p = p[:24]+struct.pack("!I",len(p))+p[28:]
+ return p
+
+
+
+
+class ISAKMP_payload_Transform(ISAKMP_class):
+ name = "IKE Transform"
+ fields_desc = [
+ ByteEnumField("next_payload",None,ISAKMP_payload_type),
+ ByteField("res",0),
+# ShortField("len",None),
+ ShortField("length",None),
+ ByteField("num",None),
+ ByteEnumField("id",1,{1:"KEY_IKE"}),
+ ShortField("res2",0),
+ ISAKMPTransformSetField("transforms",None,length_from=lambda x:x.length-8)
+# XIntField("enc",0x80010005L),
+# XIntField("hash",0x80020002L),
+# XIntField("auth",0x80030001L),
+# XIntField("group",0x80040002L),
+# XIntField("life_type",0x800b0001L),
+# XIntField("durationh",0x000c0004L),
+# XIntField("durationl",0x00007080L),
+ ]
+ def post_build(self, p, pay):
+ if self.length is None:
+ l = len(p)
+ p = p[:2]+bytes([((l>>8)&0xff),(l&0xff)])+p[4:]
+ p += pay
+ return p
+
+
+
+
+class ISAKMP_payload_Proposal(ISAKMP_class):
+ name = "IKE proposal"
+# ISAKMP_payload_type = 0
+ fields_desc = [
+ ByteEnumField("next_payload",None,ISAKMP_payload_type),
+ ByteField("res",0),
+ FieldLenField("length",None,"trans","H", adjust=lambda pkt,x:x+8),
+ ByteField("proposal",1),
+ ByteEnumField("proto",1,{1:"ISAKMP"}),
+ FieldLenField("SPIsize",None,"SPI","B"),
+ ByteField("trans_nb",None),
+ StrLenField("SPI","",length_from=lambda x:x.SPIsize),
+ PacketLenField("trans",conf.raw_layer(),ISAKMP_payload_Transform,length_from=lambda x:x.length-8),
+ ]
+
+
+class ISAKMP_payload(ISAKMP_class):
+ name = "ISAKMP payload"
+ fields_desc = [
+ ByteEnumField("next_payload",None,ISAKMP_payload_type),
+ ByteField("res",0),
+ FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4),
+ StrLenField("load","",length_from=lambda x:x.length-4),
+ ]
+
+
+class ISAKMP_payload_VendorID(ISAKMP_class):
+ name = "ISAKMP Vendor ID"
+ overload_fields = { ISAKMP: { "next_payload":13 }}
+ fields_desc = [
+ ByteEnumField("next_payload",None,ISAKMP_payload_type),
+ ByteField("res",0),
+ FieldLenField("length",None,"vendorID","H", adjust=lambda pkt,x:x+4),
+ StrLenField("vendorID","",length_from=lambda x:x.length-4),
+ ]
+
+class ISAKMP_payload_SA(ISAKMP_class):
+ name = "ISAKMP SA"
+ overload_fields = { ISAKMP: { "next_payload":1 }}
+ fields_desc = [
+ ByteEnumField("next_payload",None,ISAKMP_payload_type),
+ ByteField("res",0),
+ FieldLenField("length",None,"prop","H", adjust=lambda pkt,x:x+12),
+ IntEnumField("DOI",1,{1:"IPSEC"}),
+ IntEnumField("situation",1,{1:"identity"}),
+ PacketLenField("prop",conf.raw_layer(),ISAKMP_payload_Proposal,length_from=lambda x:x.length-12),
+ ]
+
+class ISAKMP_payload_Nonce(ISAKMP_class):
+ name = "ISAKMP Nonce"
+ overload_fields = { ISAKMP: { "next_payload":10 }}
+ fields_desc = [
+ ByteEnumField("next_payload",None,ISAKMP_payload_type),
+ ByteField("res",0),
+ FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4),
+ StrLenField("load","",length_from=lambda x:x.length-4),
+ ]
+
+class ISAKMP_payload_KE(ISAKMP_class):
+ name = "ISAKMP Key Exchange"
+ overload_fields = { ISAKMP: { "next_payload":4 }}
+ fields_desc = [
+ ByteEnumField("next_payload",None,ISAKMP_payload_type),
+ ByteField("res",0),
+ FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4),
+ StrLenField("load","",length_from=lambda x:x.length-4),
+ ]
+
+class ISAKMP_payload_ID(ISAKMP_class):
+ name = "ISAKMP Identification"
+ overload_fields = { ISAKMP: { "next_payload":5 }}
+ fields_desc = [
+ ByteEnumField("next_payload",None,ISAKMP_payload_type),
+ ByteField("res",0),
+ FieldLenField("length",None,"load","H",adjust=lambda pkt,x:x+8),
+ ByteEnumField("IDtype",1,{1:"IPv4_addr", 11:"Key"}),
+ ByteEnumField("ProtoID",0,{0:"Unused"}),
+ ShortEnumField("Port",0,{0:"Unused"}),
+# IPField("IdentData","127.0.0.1"),
+ StrLenField("load","",length_from=lambda x:x.length-8),
+ ]
+
+
+
+class ISAKMP_payload_Hash(ISAKMP_class):
+ name = "ISAKMP Hash"
+ overload_fields = { ISAKMP: { "next_payload":8 }}
+ fields_desc = [
+ ByteEnumField("next_payload",None,ISAKMP_payload_type),
+ ByteField("res",0),
+ FieldLenField("length",None,"load","H",adjust=lambda pkt,x:x+4),
+ StrLenField("load","",length_from=lambda x:x.length-4),
+ ]
+
+
+
+ISAKMP_payload_type_overload = {}
+for i in range(len(ISAKMP_payload_type)):
+ name = "ISAKMP_payload_%s" % ISAKMP_payload_type[i]
+ if name in globals():
+ ISAKMP_payload_type_overload[globals()[name]] = {"next_payload":i}
+
+del(i)
+del(name)
+ISAKMP_class.overload_fields = ISAKMP_payload_type_overload.copy()
+
+
+bind_layers( UDP, ISAKMP, dport=500, sport=500)
+def ikescan(ip):
+ return sr(IP(dst=ip)/UDP()/ISAKMP(init_cookie=RandString(8),
+ exch_type=2)/ISAKMP_payload_SA(prop=ISAKMP_payload_Proposal()))
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/l2.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/l2.py
new file mode 100644
index 00000000..0d0a1c78
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/l2.py
@@ -0,0 +1,543 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+Classes and functions for layer 2 protocols.
+"""
+
+import os,struct,time
+from scapy.base_classes import Net
+from scapy.config import conf
+from scapy.packet import *
+from scapy.ansmachine import *
+from scapy.plist import SndRcvList
+from scapy.fields import *
+from scapy.sendrecv import srp,srp1
+from scapy.arch import get_if_hwaddr
+
+
+
+
+#################
+## Tools ##
+#################
+
+
+class Neighbor:
+ def __init__(self):
+ self.resolvers = {}
+
+ def register_l3(self, l2, l3, resolve_method):
+ self.resolvers[l2,l3]=resolve_method
+
+ def resolve(self, l2inst, l3inst):
+ k = l2inst.__class__,l3inst.__class__
+ if k in self.resolvers:
+ return self.resolvers[k](l2inst,l3inst)
+
+ def __repr__(self):
+ return "\n".join("%-15s -> %-15s" % (l2.__name__, l3.__name__) for l2,l3 in self.resolvers)
+
+conf.neighbor = Neighbor()
+
+conf.netcache.new_cache("arp_cache", 120) # cache entries expire after 120s
+
+
+@conf.commands.register
+def getmacbyip(ip, chainCC=0):
+ """Return MAC address corresponding to a given IP address"""
+ if isinstance(ip,Net):
+ ip = next(iter(ip))
+ ip = inet_ntoa(inet_aton(ip))
+ tmp = inet_aton(ip)
+ if (tmp[0] & 0xf0) == 0xe0: # mcast @
+ return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3])
+ iff,a,gw = conf.route.route(ip)
+ if ( (iff == "lo") or (ip == conf.route.get_if_bcast(iff)) ):
+ return "ff:ff:ff:ff:ff:ff"
+ if gw != "0.0.0.0":
+ ip = gw
+
+ mac = conf.netcache.arp_cache.get(ip)
+ if mac:
+ return mac
+
+ res = srp1(Ether(dst=ETHER_BROADCAST)/ARP(op="who-has", pdst=ip),
+ type=ETH_P_ARP,
+ iface = iff,
+ timeout=2,
+ verbose=0,
+ chainCC=chainCC,
+ nofilter=1)
+ if res is not None:
+ mac = res.payload.hwsrc
+ conf.netcache.arp_cache[ip] = mac
+ return mac
+ return None
+
+
+
+### Fields
+
+class DestMACField(MACField):
+ def __init__(self, name):
+ MACField.__init__(self, name, None)
+ def i2h(self, pkt, x):
+ if x is None:
+ x = conf.neighbor.resolve(pkt,pkt.payload)
+ if x is None:
+ x = "ff:ff:ff:ff:ff:ff"
+ warning("Mac address to reach destination not found. Using broadcast.")
+ return MACField.i2h(self, pkt, x)
+ def i2m(self, pkt, x):
+ return MACField.i2m(self, pkt, self.i2h(pkt, x))
+
+class SourceMACField(MACField):
+ def __init__(self, name):
+ MACField.__init__(self, name, None)
+ def i2h(self, pkt, x):
+ if x is None:
+ iff,a,gw = pkt.payload.route()
+ if iff:
+ try:
+ x = get_if_hwaddr(iff)
+ except:
+ pass
+ if x is None:
+ x = "00:00:00:00:00:00"
+ return MACField.i2h(self, pkt, x)
+ def i2m(self, pkt, x):
+ return MACField.i2m(self, pkt, self.i2h(pkt, x))
+
+class ARPSourceMACField(MACField):
+ def __init__(self, name):
+ MACField.__init__(self, name, None)
+ def i2h(self, pkt, x):
+ if x is None:
+ iff,a,gw = pkt.route()
+ if iff:
+ try:
+ x = get_if_hwaddr(iff)
+ except:
+ pass
+ if x is None:
+ x = "00:00:00:00:00:00"
+ return MACField.i2h(self, pkt, x)
+ def i2m(self, pkt, x):
+ return MACField.i2m(self, pkt, self.i2h(pkt, x))
+
+
+
+### Layers
+
+
+class Ether(Packet):
+ name = "Ethernet"
+ fields_desc = [ MACField("dst","00:00:00:01:00:00"),
+ MACField("src","00:00:00:02:00:00"),
+ XShortEnumField("type", 0x9000, ETHER_TYPES) ]
+ def hashret(self):
+ return struct.pack("H",self.type)+self.payload.hashret()
+ def answers(self, other):
+ if isinstance(other,Ether):
+ if self.type == other.type:
+ return self.payload.answers(other.payload)
+ return 0
+ def mysummary(self):
+ return self.sprintf("%src% > %dst% (%type%)")
+ @classmethod
+ def dispatch_hook(cls, _pkt=None, *args, **kargs):
+ if _pkt and len(_pkt) >= 14:
+ if struct.unpack("!H", _pkt[12:14])[0] <= 1500:
+ return Dot3
+ return cls
+
+
+class Dot3(Packet):
+ name = "802.3"
+ fields_desc = [ DestMACField("dst"),
+ MACField("src", ETHER_ANY),
+ LenField("len", None, "H") ]
+ def extract_padding(self,s):
+ l = self.len
+ return s[:l],s[l:]
+ def answers(self, other):
+ if isinstance(other,Dot3):
+ return self.payload.answers(other.payload)
+ return 0
+ def mysummary(self):
+ return "802.3 %s > %s" % (self.src, self.dst)
+ @classmethod
+ def dispatch_hook(cls, _pkt=None, *args, **kargs):
+ if _pkt and len(_pkt) >= 14:
+ if struct.unpack("!H", _pkt[12:14])[0] > 1500:
+ return Ether
+ return cls
+
+
+class LLC(Packet):
+ name = "LLC"
+ fields_desc = [ XByteField("dsap", 0x00),
+ XByteField("ssap", 0x00),
+ ByteField("ctrl", 0) ]
+
+conf.neighbor.register_l3(Ether, LLC, lambda l2,l3: conf.neighbor.resolve(l2,l3.payload))
+conf.neighbor.register_l3(Dot3, LLC, lambda l2,l3: conf.neighbor.resolve(l2,l3.payload))
+
+
+class CookedLinux(Packet):
+ name = "cooked linux"
+ fields_desc = [ ShortEnumField("pkttype",0, {0: "unicast",
+ 4:"sent-by-us"}), #XXX incomplete
+ XShortField("lladdrtype",512),
+ ShortField("lladdrlen",0),
+ StrFixedLenField("src","",8),
+ XShortEnumField("proto",0x800,ETHER_TYPES) ]
+
+
+
+class SNAP(Packet):
+ name = "SNAP"
+ fields_desc = [ X3BytesField("OUI",0x000000),
+ XShortEnumField("code", 0x000, ETHER_TYPES) ]
+
+conf.neighbor.register_l3(Dot3, SNAP, lambda l2,l3: conf.neighbor.resolve(l2,l3.payload))
+
+
+class Dot1Q(Packet):
+ name = "802.1Q"
+ aliastypes = [ Ether ]
+ fields_desc = [ BitField("prio", 0, 3),
+ BitField("id", 0, 1),
+ BitField("vlan", 1, 12),
+ XShortEnumField("type", 0x0000, ETHER_TYPES) ]
+ def answers(self, other):
+ if isinstance(other,Dot1Q):
+ if ( (self.type == other.type) and
+ (self.vlan == other.vlan) ):
+ return self.payload.answers(other.payload)
+ else:
+ return self.payload.answers(other)
+ return 0
+ def default_payload_class(self, pay):
+ if self.type <= 1500:
+ return LLC
+ return conf.raw_layer
+ def extract_padding(self,s):
+ if self.type <= 1500:
+ return s[:self.type],s[self.type:]
+ return s,None
+ def mysummary(self):
+ if isinstance(self.underlayer, Ether):
+ return self.underlayer.sprintf("802.1q %Ether.src% > %Ether.dst% (%Dot1Q.type%) vlan %Dot1Q.vlan%")
+ else:
+ return self.sprintf("802.1q (%Dot1Q.type%) vlan %Dot1Q.vlan%")
+
+
+conf.neighbor.register_l3(Ether, Dot1Q, lambda l2,l3: conf.neighbor.resolve(l2,l3.payload))
+
+class STP(Packet):
+ name = "Spanning Tree Protocol"
+ fields_desc = [ ShortField("proto", 0),
+ ByteField("version", 0),
+ ByteField("bpdutype", 0),
+ ByteField("bpduflags", 0),
+ ShortField("rootid", 0),
+ MACField("rootmac", ETHER_ANY),
+ IntField("pathcost", 0),
+ ShortField("bridgeid", 0),
+ MACField("bridgemac", ETHER_ANY),
+ ShortField("portid", 0),
+ BCDFloatField("age", 1),
+ BCDFloatField("maxage", 20),
+ BCDFloatField("hellotime", 2),
+ BCDFloatField("fwddelay", 15) ]
+
+
+class EAPOL(Packet):
+ name = "EAPOL"
+ fields_desc = [ ByteField("version", 1),
+ ByteEnumField("type", 0, ["EAP_PACKET", "START", "LOGOFF", "KEY", "ASF"]),
+ LenField("len", None, "H") ]
+
+ EAP_PACKET= 0
+ START = 1
+ LOGOFF = 2
+ KEY = 3
+ ASF = 4
+ def extract_padding(self, s):
+ l = self.len
+ return s[:l],s[l:]
+ def hashret(self):
+ #return chr(self.type)+self.payload.hashret()
+ return bytes([self.type])+self.payload.hashret()
+ def answers(self, other):
+ if isinstance(other,EAPOL):
+ if ( (self.type == self.EAP_PACKET) and
+ (other.type == self.EAP_PACKET) ):
+ return self.payload.answers(other.payload)
+ return 0
+ def mysummary(self):
+ return self.sprintf("EAPOL %EAPOL.type%")
+
+
+class EAP(Packet):
+ name = "EAP"
+ fields_desc = [ ByteEnumField("code", 4, {1:"REQUEST",2:"RESPONSE",3:"SUCCESS",4:"FAILURE"}),
+ ByteField("id", 0),
+ ShortField("len",None),
+ ConditionalField(ByteEnumField("type",0, {1:"ID",4:"MD5"}), lambda pkt:pkt.code not in [EAP.SUCCESS, EAP.FAILURE])
+
+ ]
+
+ REQUEST = 1
+ RESPONSE = 2
+ SUCCESS = 3
+ FAILURE = 4
+ TYPE_ID = 1
+ TYPE_MD5 = 4
+ def answers(self, other):
+ if isinstance(other,EAP):
+ if self.code == self.REQUEST:
+ return 0
+ elif self.code == self.RESPONSE:
+ if ( (other.code == self.REQUEST) and
+ (other.type == self.type) ):
+ return 1
+ elif other.code == self.RESPONSE:
+ return 1
+ return 0
+
+ def post_build(self, p, pay):
+ if self.len is None:
+ l = len(p)+len(pay)
+ p = p[:2]+bytes([((l>>8)&0xff),(l&0xff)])+p[4:]
+ return p+pay
+
+
+class ARP(Packet):
+ name = "ARP"
+ fields_desc = [ XShortField("hwtype", 0x0001),
+ XShortEnumField("ptype", 0x0800, ETHER_TYPES),
+ ByteField("hwlen", 6),
+ ByteField("plen", 4),
+ ShortEnumField("op", 1, {"who-has":1, "is-at":2, "RARP-req":3, "RARP-rep":4, "Dyn-RARP-req":5, "Dyn-RAR-rep":6, "Dyn-RARP-err":7, "InARP-req":8, "InARP-rep":9}),
+ ARPSourceMACField("hwsrc"),
+ SourceIPField("psrc","pdst"),
+ MACField("hwdst", ETHER_ANY),
+ IPField("pdst", "0.0.0.0") ]
+ who_has = 1
+ is_at = 2
+ def answers(self, other):
+ if isinstance(other,ARP):
+ if ( (self.op == self.is_at) and
+ (other.op == self.who_has) and
+ (self.psrc == other.pdst) ):
+ return 1
+ return 0
+ def route(self):
+ dst = self.pdst
+ if isinstance(dst,Gen):
+ dst = next(iter(dst))
+ return conf.route.route(dst)
+ def extract_padding(self, s):
+ return b"",s
+ def mysummary(self):
+ if self.op == self.is_at:
+ return self.sprintf("ARP is at %hwsrc% says %psrc%")
+ elif self.op == self.who_has:
+ return self.sprintf("ARP who has %pdst% says %psrc%")
+ else:
+ return self.sprintf("ARP %op% %psrc% > %pdst%")
+
+conf.neighbor.register_l3(Ether, ARP, lambda l2,l3: getmacbyip(l3.pdst))
+
+class GRErouting(Packet):
+ name = "GRE routing informations"
+ fields_desc = [ ShortField("address_family",0),
+ ByteField("SRE_offset", 0),
+ FieldLenField("SRE_len", None, "routing_info", "B"),
+ StrLenField("routing_info", "", "SRE_len"),
+ ]
+
+
+class GRE(Packet):
+ name = "GRE"
+ fields_desc = [ BitField("chksum_present",0,1),
+ BitField("routing_present",0,1),
+ BitField("key_present",0,1),
+ BitField("seqnum_present",0,1),
+ BitField("strict_route_source",0,1),
+ BitField("recursion_control",0,3),
+ BitField("flags",0,5),
+ BitField("version",0,3),
+ XShortEnumField("proto", 0x0000, ETHER_TYPES),
+ ConditionalField(XShortField("chksum",None), lambda pkt:pkt.chksum_present==1 or pkt.routing_present==1),
+ ConditionalField(XShortField("offset",None), lambda pkt:pkt.chksum_present==1 or pkt.routing_present==1),
+ ConditionalField(XIntField("key",None), lambda pkt:pkt.key_present==1),
+ ConditionalField(XIntField("seqence_number",None), lambda pkt:pkt.seqnum_present==1),
+ ]
+ def post_build(self, p, pay):
+ p += pay
+ if self.chksum_present and self.chksum is None:
+ c = checksum(p)
+ p = p[:4]+bytes([((c>>8)&0xff),(c&0xff)])+p[6:]
+ return p
+
+
+
+
+bind_layers( Dot3, LLC, )
+bind_layers( Ether, LLC, type=122)
+bind_layers( Ether, Dot1Q, type=33024)
+bind_layers( Ether, Ether, type=1)
+bind_layers( Ether, ARP, type=2054)
+bind_layers( Ether, EAPOL, type=34958)
+bind_layers( Ether, EAPOL, dst='01:80:c2:00:00:03', type=34958)
+bind_layers( CookedLinux, LLC, proto=122)
+bind_layers( CookedLinux, Dot1Q, proto=33024)
+bind_layers( CookedLinux, Ether, proto=1)
+bind_layers( CookedLinux, ARP, proto=2054)
+bind_layers( CookedLinux, EAPOL, proto=34958)
+bind_layers( GRE, LLC, proto=122)
+bind_layers( GRE, Dot1Q, proto=33024)
+bind_layers( GRE, Ether, proto=1)
+bind_layers( GRE, ARP, proto=2054)
+bind_layers( GRE, EAPOL, proto=34958)
+bind_layers( GRE, GRErouting, { "routing_present" : 1 } )
+bind_layers( GRErouting, conf.raw_layer,{ "address_family" : 0, "SRE_len" : 0 })
+bind_layers( GRErouting, GRErouting, { } )
+bind_layers( EAPOL, EAP, type=0)
+bind_layers( LLC, STP, dsap=66, ssap=66, ctrl=3)
+bind_layers( LLC, SNAP, dsap=170, ssap=170, ctrl=3)
+bind_layers( SNAP, Dot1Q, code=33024)
+bind_layers( SNAP, Ether, code=1)
+bind_layers( SNAP, ARP, code=2054)
+bind_layers( SNAP, EAPOL, code=34958)
+bind_layers( SNAP, STP, code=267)
+
+conf.l2types.register(ARPHDR_ETHER, Ether)
+conf.l2types.register_num2layer(ARPHDR_METRICOM, Ether)
+conf.l2types.register_num2layer(ARPHDR_LOOPBACK, Ether)
+conf.l2types.register_layer2num(ARPHDR_ETHER, Dot3)
+conf.l2types.register(144, CookedLinux) # called LINUX_IRDA, similar to CookedLinux
+conf.l2types.register(113, CookedLinux)
+
+conf.l3types.register(ETH_P_ARP, ARP)
+
+
+
+
+### Technics
+
+
+
+@conf.commands.register
+def arpcachepoison(target, victim, interval=60):
+ """Poison target's cache with (your MAC,victim's IP) couple
+arpcachepoison(target, victim, [interval=60]) -> None
+"""
+ tmac = getmacbyip(target)
+ p = Ether(dst=tmac)/ARP(op="who-has", psrc=victim, pdst=target)
+ try:
+ while 1:
+ sendp(p, iface_hint=target)
+ if conf.verb > 1:
+ os.write(1,b".")
+ time.sleep(interval)
+ except KeyboardInterrupt:
+ pass
+
+
+class ARPingResult(SndRcvList):
+ def __init__(self, res=None, name="ARPing", stats=None):
+ SndRcvList.__init__(self, res, name, stats)
+
+ def show(self):
+ for s,r in self.res:
+ print(r.sprintf("%19s,Ether.src% %ARP.psrc%"))
+
+
+
+@conf.commands.register
+def arping(net, timeout=2, cache=0, verbose=None, **kargs):
+ """Send ARP who-has requests to determine which hosts are up
+arping(net, [cache=0,] [iface=conf.iface,] [verbose=conf.verb]) -> None
+Set cache=True if you want arping to modify internal ARP-Cache"""
+ if verbose is None:
+ verbose = conf.verb
+ ans,unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=net), verbose=verbose,
+ filter="arp and arp[7] = 2", timeout=timeout, iface_hint=net, **kargs)
+ ans = ARPingResult(ans.res)
+
+ if cache and ans is not None:
+ for pair in ans:
+ conf.netcache.arp_cache[pair[1].psrc] = (pair[1].hwsrc, time.time())
+ if verbose:
+ ans.show()
+ return ans,unans
+
+@conf.commands.register
+def is_promisc(ip, fake_bcast="ff:ff:00:00:00:00",**kargs):
+ """Try to guess if target is in Promisc mode. The target is provided by its ip."""
+
+ responses = srp1(Ether(dst=fake_bcast) / ARP(op="who-has", pdst=ip),type=ETH_P_ARP, iface_hint=ip, timeout=1, verbose=0,**kargs)
+
+ return responses is not None
+
+@conf.commands.register
+def promiscping(net, timeout=2, fake_bcast="ff:ff:ff:ff:ff:fe", **kargs):
+ """Send ARP who-has requests to determine which hosts are in promiscuous mode
+ promiscping(net, iface=conf.iface)"""
+ ans,unans = srp(Ether(dst=fake_bcast)/ARP(pdst=net),
+ filter="arp and arp[7] = 2", timeout=timeout, iface_hint=net, **kargs)
+ ans = ARPingResult(ans.res, name="PROMISCPing")
+
+ ans.display()
+ return ans,unans
+
+
+class ARP_am(AnsweringMachine):
+ function_name="farpd"
+ filter = "arp"
+ send_function = staticmethod(sendp)
+
+ def parse_options(self, IP_addr=None, iface=None, ARP_addr=None):
+ self.IP_addr=IP_addr
+ self.iface=iface
+ self.ARP_addr=ARP_addr
+
+ def is_request(self, req):
+ return (req.haslayer(ARP) and
+ req.getlayer(ARP).op == 1 and
+ (self.IP_addr == None or self.IP_addr == req.getlayer(ARP).pdst))
+
+ def make_reply(self, req):
+ ether = req.getlayer(Ether)
+ arp = req.getlayer(ARP)
+ iff,a,gw = conf.route.route(arp.psrc)
+ if self.iface != None:
+ iff = iface
+ ARP_addr = self.ARP_addr
+ IP_addr = arp.pdst
+ resp = Ether(dst=ether.src,
+ src=ARP_addr)/ARP(op="is-at",
+ hwsrc=ARP_addr,
+ psrc=IP_addr,
+ hwdst=arp.hwsrc,
+ pdst=arp.pdst)
+ return resp
+
+ def sniff(self):
+ sniff(iface=self.iface, **self.optsniff)
+
+@conf.commands.register
+def etherleak(target, **kargs):
+ """Exploit Etherleak flaw"""
+ return srpflood(Ether()/ARP(pdst=target),
+ prn=lambda a: conf.padding_layer in a[1] and hexstr(a[1][conf.padding_layer].load),
+ filter="arp", **kargs)
+
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/l2tp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/l2tp.py
new file mode 100644
index 00000000..0b56db21
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/l2tp.py
@@ -0,0 +1,36 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+L2TP (Layer 2 Tunneling Protocol) for VPNs.
+
+[RFC 2661]
+"""
+
+import struct
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.inet import UDP
+from scapy.layers.ppp import PPP
+
+class L2TP(Packet):
+ fields_desc = [ ShortEnumField("pkt_type",2,{2:"data"}),
+ ShortField("len", None),
+ ShortField("tunnel_id", 0),
+ ShortField("session_id", 0),
+ ShortField("ns", 0),
+ ShortField("nr", 0),
+ ShortField("offset", 0) ]
+
+ def post_build(self, pkt, pay):
+ if self.len is None:
+ l = len(pkt)+len(pay)
+ pkt = pkt[:2]+struct.pack("!H", l)+pkt[4:]
+ return pkt+pay
+
+
+bind_layers( UDP, L2TP, sport=1701, dport=1701)
+bind_layers( L2TP, PPP, )
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/llmnr.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/llmnr.py
new file mode 100644
index 00000000..65ecad41
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/llmnr.py
@@ -0,0 +1,65 @@
+from scapy.fields import *
+from scapy.packet import *
+from scapy.layers.inet import UDP
+from scapy.layers.dns import DNSQRField, DNSRRField, DNSRRCountField
+
+"""
+LLMNR (Link Local Multicast Node Resolution).
+
+[RFC 4795]
+"""
+
+#############################################################################
+### LLMNR (RFC4795) ###
+#############################################################################
+# LLMNR is based on the DNS packet format (RFC1035 Section 4)
+# RFC also envisions LLMNR over TCP. Like vista, we don't support it -- arno
+
+_LLMNR_IPv6_mcast_Addr = "FF02:0:0:0:0:0:1:3"
+_LLMNR_IPv4_mcast_addr = "224.0.0.252"
+
+class LLMNRQuery(Packet):
+ name = "Link Local Multicast Node Resolution - Query"
+ fields_desc = [ ShortField("id", 0),
+ BitField("qr", 0, 1),
+ BitEnumField("opcode", 0, 4, { 0:"QUERY" }),
+ BitField("c", 0, 1),
+ BitField("tc", 0, 2),
+ BitField("z", 0, 4),
+ BitEnumField("rcode", 0, 4, { 0:"ok" }),
+ DNSRRCountField("qdcount", None, "qd"),
+ DNSRRCountField("ancount", None, "an"),
+ DNSRRCountField("nscount", None, "ns"),
+ DNSRRCountField("arcount", None, "ar"),
+ DNSQRField("qd", "qdcount"),
+ DNSRRField("an", "ancount"),
+ DNSRRField("ns", "nscount"),
+ DNSRRField("ar", "arcount",0)]
+ overload_fields = {UDP: {"sport": 5355, "dport": 5355 }}
+ def hashret(self):
+ return struct.pack("!H", self.id)
+
+class LLMNRResponse(LLMNRQuery):
+ name = "Link Local Multicast Node Resolution - Response"
+ qr = 1
+ def answers(self, other):
+ return (isinstance(other, LLMNRQuery) and
+ self.id == other.id and
+ self.qr == 1 and
+ other.qr == 0)
+
+def _llmnr_dispatcher(x, *args, **kargs):
+ cls = conf.raw_layer
+ if len(x) >= 3:
+ if (ord(x[4]) & 0x80): # Response
+ cls = LLMNRResponse
+ else: # Query
+ cls = LLMNRQuery
+ return cls(x, *args, **kargs)
+
+bind_bottom_up(UDP, _llmnr_dispatcher, { "dport": 5355 })
+bind_bottom_up(UDP, _llmnr_dispatcher, { "sport": 5355 })
+
+# LLMNRQuery(id=RandShort(), qd=DNSQR(qname="vista.")))
+
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/mgcp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/mgcp.py
new file mode 100644
index 00000000..5d8a064e
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/mgcp.py
@@ -0,0 +1,45 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+MGCP (Media Gateway Control Protocol)
+
+[RFC 2805]
+"""
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.inet import UDP
+
+class MGCP(Packet):
+ name = "MGCP"
+ longname = "Media Gateway Control Protocol"
+ fields_desc = [ StrStopField("verb","AUEP"," ", -1),
+ StrFixedLenField("sep1"," ",1),
+ StrStopField("transaction_id","1234567"," ", -1),
+ StrFixedLenField("sep2"," ",1),
+ StrStopField("endpoint","dummy@dummy.net"," ", -1),
+ StrFixedLenField("sep3"," ",1),
+ StrStopField("version","MGCP 1.0 NCS 1.0","\x0a", -1),
+ StrFixedLenField("sep4","\x0a",1),
+ ]
+
+
+#class MGCP(Packet):
+# name = "MGCP"
+# longname = "Media Gateway Control Protocol"
+# fields_desc = [ ByteEnumField("type",0, ["request","response","others"]),
+# ByteField("code0",0),
+# ByteField("code1",0),
+# ByteField("code2",0),
+# ByteField("code3",0),
+# ByteField("code4",0),
+# IntField("trasid",0),
+# IntField("req_time",0),
+# ByteField("is_duplicate",0),
+# ByteField("req_available",0) ]
+#
+bind_layers( UDP, MGCP, dport=2727)
+bind_layers( UDP, MGCP, sport=2727)
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/mobileip.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/mobileip.py
new file mode 100644
index 00000000..bbaa8ce7
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/mobileip.py
@@ -0,0 +1,47 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+Mobile IP.
+"""
+
+from scapy.fields import *
+from scapy.packet import *
+from scapy.layers.inet import IP,UDP
+
+
+class MobileIP(Packet):
+ name = "Mobile IP (RFC3344)"
+ fields_desc = [ ByteEnumField("type", 1, {1:"RRQ", 3:"RRP"}) ]
+
+class MobileIPRRQ(Packet):
+ name = "Mobile IP Registration Request (RFC3344)"
+ fields_desc = [ XByteField("flags", 0),
+ ShortField("lifetime", 180),
+ IPField("homeaddr", "0.0.0.0"),
+ IPField("haaddr", "0.0.0.0"),
+ IPField("coaddr", "0.0.0.0"),
+ LongField("id", 0), ]
+
+class MobileIPRRP(Packet):
+ name = "Mobile IP Registration Reply (RFC3344)"
+ fields_desc = [ ByteField("code", 0),
+ ShortField("lifetime", 180),
+ IPField("homeaddr", "0.0.0.0"),
+ IPField("haaddr", "0.0.0.0"),
+ LongField("id", 0), ]
+
+class MobileIPTunnelData(Packet):
+ name = "Mobile IP Tunnel Data Message (RFC3519)"
+ fields_desc = [ ByteField("nexthdr", 4),
+ ShortField("res", 0) ]
+
+
+bind_layers( UDP, MobileIP, sport=434)
+bind_layers( UDP, MobileIP, dport=434)
+bind_layers( MobileIP, MobileIPRRQ, type=1)
+bind_layers( MobileIP, MobileIPRRP, type=3)
+bind_layers( MobileIP, MobileIPTunnelData, type=4)
+bind_layers( MobileIPTunnelData, IP, nexthdr=4)
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/netbios.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/netbios.py
new file mode 100644
index 00000000..f06e9307
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/netbios.py
@@ -0,0 +1,222 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+NetBIOS over TCP/IP
+
+[RFC 1001/1002]
+"""
+
+import struct
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.inet import UDP,TCP
+from scapy.layers.l2 import SourceMACField
+
+class NetBIOS_DS(Packet):
+ name = "NetBIOS datagram service"
+ fields_desc = [
+ ByteEnumField("type",17, {17:"direct_group"}),
+ ByteField("flags",0),
+ XShortField("id",0),
+ IPField("src","127.0.0.1"),
+ ShortField("sport",138),
+ ShortField("len",None),
+ ShortField("ofs",0),
+ NetBIOSNameField("srcname",""),
+ NetBIOSNameField("dstname",""),
+ ]
+ def post_build(self, p, pay):
+ p += pay
+ if self.len is None:
+ l = len(p)-14
+ p = p[:10]+struct.pack("!H", l)+p[12:]
+ return p
+
+# ShortField("length",0),
+# ShortField("Delimitor",0),
+# ByteField("command",0),
+# ByteField("data1",0),
+# ShortField("data2",0),
+# ShortField("XMIt",0),
+# ShortField("RSPCor",0),
+# StrFixedLenField("dest","",16),
+# StrFixedLenField("source","",16),
+#
+# ]
+#
+
+#NetBIOS
+
+
+# Name Query Request
+# Node Status Request
+class NBNSQueryRequest(Packet):
+ name="NBNS query request"
+ fields_desc = [ShortField("NAME_TRN_ID",0),
+ ShortField("FLAGS", 0x0110),
+ ShortField("QDCOUNT",1),
+ ShortField("ANCOUNT",0),
+ ShortField("NSCOUNT",0),
+ ShortField("ARCOUNT",0),
+ NetBIOSNameField("QUESTION_NAME","windows"),
+ ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
+ ByteField("NULL",0),
+ ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
+ ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"})]
+
+# Name Registration Request
+# Name Refresh Request
+# Name Release Request or Demand
+class NBNSRequest(Packet):
+ name="NBNS request"
+ fields_desc = [ShortField("NAME_TRN_ID",0),
+ ShortField("FLAGS", 0x2910),
+ ShortField("QDCOUNT",1),
+ ShortField("ANCOUNT",0),
+ ShortField("NSCOUNT",0),
+ ShortField("ARCOUNT",1),
+ NetBIOSNameField("QUESTION_NAME","windows"),
+ ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
+ ByteField("NULL",0),
+ ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
+ ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"}),
+ ShortEnumField("RR_NAME",0xC00C,{0xC00C:"Label String Pointer to QUESTION_NAME"}),
+ ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
+ ShortEnumField("RR_CLASS",1,{1:"INTERNET"}),
+ IntField("TTL", 0),
+ ShortField("RDLENGTH", 6),
+ BitEnumField("G",0,1,{0:"Unique name",1:"Group name"}),
+ BitEnumField("OWNER_NODE_TYPE",00,2,{0:"B node",1:"P node",2:"M node",3:"H node"}),
+ BitEnumField("UNUSED",0,13,{0:"Unused"}),
+ IPField("NB_ADDRESS", "127.0.0.1")]
+
+# Name Query Response
+# Name Registration Response
+class NBNSQueryResponse(Packet):
+ name="NBNS query response"
+ fields_desc = [ShortField("NAME_TRN_ID",0),
+ ShortField("FLAGS", 0x8500),
+ ShortField("QDCOUNT",0),
+ ShortField("ANCOUNT",1),
+ ShortField("NSCOUNT",0),
+ ShortField("ARCOUNT",0),
+ NetBIOSNameField("RR_NAME","windows"),
+ ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
+ ByteField("NULL",0),
+ ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
+ ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"}),
+ IntField("TTL", 0x493e0),
+ ShortField("RDLENGTH", 6),
+ ShortField("NB_FLAGS", 0),
+ IPField("NB_ADDRESS", "127.0.0.1")]
+
+# Name Query Response (negative)
+# Name Release Response
+class NBNSQueryResponseNegative(Packet):
+ name="NBNS query response (negative)"
+ fields_desc = [ShortField("NAME_TRN_ID",0),
+ ShortField("FLAGS", 0x8506),
+ ShortField("QDCOUNT",0),
+ ShortField("ANCOUNT",1),
+ ShortField("NSCOUNT",0),
+ ShortField("ARCOUNT",0),
+ NetBIOSNameField("RR_NAME","windows"),
+ ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
+ ByteField("NULL",0),
+ ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
+ ShortEnumField("RR_CLASS",1,{1:"INTERNET"}),
+ IntField("TTL",0),
+ ShortField("RDLENGTH",6),
+ BitEnumField("G",0,1,{0:"Unique name",1:"Group name"}),
+ BitEnumField("OWNER_NODE_TYPE",00,2,{0:"B node",1:"P node",2:"M node",3:"H node"}),
+ BitEnumField("UNUSED",0,13,{0:"Unused"}),
+ IPField("NB_ADDRESS", "127.0.0.1")]
+
+# Node Status Response
+class NBNSNodeStatusResponse(Packet):
+ name="NBNS Node Status Response"
+ fields_desc = [ShortField("NAME_TRN_ID",0),
+ ShortField("FLAGS", 0x8500),
+ ShortField("QDCOUNT",0),
+ ShortField("ANCOUNT",1),
+ ShortField("NSCOUNT",0),
+ ShortField("ARCOUNT",0),
+ NetBIOSNameField("RR_NAME","windows"),
+ ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
+ ByteField("NULL",0),
+ ShortEnumField("RR_TYPE",0x21, {0x20:"NB",0x21:"NBSTAT"}),
+ ShortEnumField("RR_CLASS",1,{1:"INTERNET"}),
+ IntField("TTL",0),
+ ShortField("RDLENGTH",83),
+ ByteField("NUM_NAMES",1)]
+
+# Service for Node Status Response
+class NBNSNodeStatusResponseService(Packet):
+ name="NBNS Node Status Response Service"
+ fields_desc = [StrFixedLenField("NETBIOS_NAME","WINDOWS ",15),
+ ByteEnumField("SUFFIX",0,{0:"workstation",0x03:"messenger service",0x20:"file server service",0x1b:"domain master browser",0x1c:"domain controller", 0x1e:"browser election service"}),
+ ByteField("NAME_FLAGS",0x4),
+ ByteEnumField("UNUSED",0,{0:"unused"})]
+
+# End of Node Status Response packet
+class NBNSNodeStatusResponseEnd(Packet):
+ name="NBNS Node Status Response"
+ fields_desc = [SourceMACField("MAC_ADDRESS"),
+ BitField("STATISTICS",0,57*8)]
+
+# Wait for Acknowledgement Response
+class NBNSWackResponse(Packet):
+ name="NBNS Wait for Acknowledgement Response"
+ fields_desc = [ShortField("NAME_TRN_ID",0),
+ ShortField("FLAGS", 0xBC07),
+ ShortField("QDCOUNT",0),
+ ShortField("ANCOUNT",1),
+ ShortField("NSCOUNT",0),
+ ShortField("ARCOUNT",0),
+ NetBIOSNameField("RR_NAME","windows"),
+ ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
+ ByteField("NULL",0),
+ ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
+ ShortEnumField("RR_CLASS",1,{1:"INTERNET"}),
+ IntField("TTL", 2),
+ ShortField("RDLENGTH",2),
+ BitField("RDATA",10512,16)] #10512=0010100100010000
+
+class NBTDatagram(Packet):
+ name="NBT Datagram Packet"
+ fields_desc= [ByteField("Type", 0x10),
+ ByteField("Flags", 0x02),
+ ShortField("ID", 0),
+ IPField("SourceIP", "127.0.0.1"),
+ ShortField("SourcePort", 138),
+ ShortField("Length", 272),
+ ShortField("Offset", 0),
+ NetBIOSNameField("SourceName",b"windows"),
+ ShortEnumField("SUFFIX1",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
+ ByteField("NULL",0),
+ NetBIOSNameField("DestinationName",b"windows"),
+ ShortEnumField("SUFFIX2",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
+ ByteField("NULL",0)]
+
+
+class NBTSession(Packet):
+ name="NBT Session Packet"
+ fields_desc= [ByteEnumField("TYPE",0,{0x00:"Session Message",0x81:"Session Request",0x82:"Positive Session Response",0x83:"Negative Session Response",0x84:"Retarget Session Response",0x85:"Session Keepalive"}),
+ BitField("RESERVED",0x00,7),
+ BitField("LENGTH",0,17)]
+
+bind_layers( UDP, NBNSQueryRequest, dport=137)
+bind_layers( UDP, NBNSRequest, dport=137)
+bind_layers( UDP, NBNSQueryResponse, sport=137)
+bind_layers( UDP, NBNSQueryResponseNegative, sport=137)
+bind_layers( UDP, NBNSNodeStatusResponse, sport=137)
+bind_layers( NBNSNodeStatusResponse, NBNSNodeStatusResponseService, )
+bind_layers( NBNSNodeStatusResponse, NBNSNodeStatusResponseService, )
+bind_layers( NBNSNodeStatusResponseService, NBNSNodeStatusResponseService, )
+bind_layers( NBNSNodeStatusResponseService, NBNSNodeStatusResponseEnd, )
+bind_layers( UDP, NBNSWackResponse, sport=137)
+bind_layers( UDP, NBTDatagram, dport=138)
+bind_layers( TCP, NBTSession, dport=139)
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/netflow.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/netflow.py
new file mode 100644
index 00000000..44567737
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/netflow.py
@@ -0,0 +1,48 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+Cisco NetFlow protocol v1
+"""
+
+
+from scapy.fields import *
+from scapy.packet import *
+
+# Cisco Netflow Protocol version 1
+class NetflowHeader(Packet):
+ name = "Netflow Header"
+ fields_desc = [ ShortField("version", 1) ]
+
+class NetflowHeaderV1(Packet):
+ name = "Netflow Header V1"
+ fields_desc = [ ShortField("count", 0),
+ IntField("sysUptime", 0),
+ IntField("unixSecs", 0),
+ IntField("unixNanoSeconds", 0) ]
+
+
+class NetflowRecordV1(Packet):
+ name = "Netflow Record"
+ fields_desc = [ IPField("ipsrc", "0.0.0.0"),
+ IPField("ipdst", "0.0.0.0"),
+ IPField("nexthop", "0.0.0.0"),
+ ShortField("inputIfIndex", 0),
+ ShortField("outpuIfIndex", 0),
+ IntField("dpkts", 0),
+ IntField("dbytes", 0),
+ IntField("starttime", 0),
+ IntField("endtime", 0),
+ ShortField("srcport", 0),
+ ShortField("dstport", 0),
+ ShortField("padding", 0),
+ ByteField("proto", 0),
+ ByteField("tos", 0),
+ IntField("padding1", 0),
+ IntField("padding2", 0) ]
+
+
+bind_layers( NetflowHeader, NetflowHeaderV1, version=1)
+bind_layers( NetflowHeaderV1, NetflowRecordV1, )
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ntp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ntp.py
new file mode 100644
index 00000000..6d11966c
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ntp.py
@@ -0,0 +1,77 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+NTP (Network Time Protocol).
+"""
+
+import time
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.inet import UDP
+
+
+# seconds between 01-01-1900 and 01-01-1970
+_NTP_BASETIME = 2208988800
+
+class TimeStampField(FixedPointField):
+ def __init__(self, name, default):
+ FixedPointField.__init__(self, name, default, 64, 32)
+
+ def i2repr(self, pkt, val):
+ if val is None:
+ return "--"
+ val = self.i2h(pkt,val)
+ if val < _NTP_BASETIME:
+ return val
+ return time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(val-_NTP_BASETIME))
+
+ def any2i(self, pkt, val):
+ if type(val) is str:
+ return int(time.mktime(time.strptime(val))) + _NTP_BASETIME + 3600 # XXX
+ return FixedPointField.any2i(self,pkt,val)
+
+ def i2m(self, pkt, val):
+ if val is None:
+ val = FixedPointField.any2i(self, pkt, time.time()+_NTP_BASETIME)
+ return FixedPointField.i2m(self, pkt, val)
+
+
+
+class NTP(Packet):
+ # RFC 1769
+ name = "NTP"
+ fields_desc = [
+ BitEnumField('leap', 0, 2,
+ { 0: 'nowarning',
+ 1: 'longminute',
+ 2: 'shortminute',
+ 3: 'notsync'}),
+ BitField('version', 3, 3),
+ BitEnumField('mode', 3, 3,
+ { 0: 'reserved',
+ 1: 'sym_active',
+ 2: 'sym_passive',
+ 3: 'client',
+ 4: 'server',
+ 5: 'broadcast',
+ 6: 'control',
+ 7: 'private'}),
+ BitField('stratum', 2, 8),
+ BitField('poll', 0xa, 8), ### XXX : it's a signed int
+ BitField('precision', 0, 8), ### XXX : it's a signed int
+ FixedPointField('delay', 0, size=32, frac_bits=16),
+ FixedPointField('dispersion', 0, size=32, frac_bits=16),
+ IPField('id', "127.0.0.1"),
+ TimeStampField('ref', 0),
+ TimeStampField('orig', None), # None means current time
+ TimeStampField('recv', 0),
+ TimeStampField('sent', None)
+ ]
+ def mysummary(self):
+ return self.sprintf("NTP v%ir,NTP.version%, %NTP.mode%")
+
+
+bind_layers( UDP, NTP, dport=123, sport=123)
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/pflog.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/pflog.py
new file mode 100644
index 00000000..a8fc9fe0
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/pflog.py
@@ -0,0 +1,59 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+PFLog: OpenBSD PF packet filter logging.
+"""
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.inet import IP
+if conf.ipv6_enabled:
+ from scapy.layers.inet6 import IPv6
+from scapy.config import conf
+
+class PFLog(Packet):
+ name = "PFLog"
+ # from OpenBSD src/sys/net/pfvar.h and src/sys/net/if_pflog.h
+ fields_desc = [ ByteField("hdrlen", 0),
+ ByteEnumField("addrfamily", 2, {socket.AF_INET: "IPv4",
+ socket.AF_INET6: "IPv6"}),
+ ByteEnumField("action", 1, {0: "pass", 1: "drop",
+ 2: "scrub", 3: "no-scrub",
+ 4: "nat", 5: "no-nat",
+ 6: "binat", 7: "no-binat",
+ 8: "rdr", 9: "no-rdr",
+ 10: "syn-proxy-drop" }),
+ ByteEnumField("reason", 0, {0: "match", 1: "bad-offset",
+ 2: "fragment", 3: "short",
+ 4: "normalize", 5: "memory",
+ 6: "bad-timestamp",
+ 7: "congestion",
+ 8: "ip-options",
+ 9: "proto-cksum",
+ 10: "state-mismatch",
+ 11: "state-insert",
+ 12: "state-limit",
+ 13: "src-limit",
+ 14: "syn-proxy" }),
+ StrFixedLenField("iface", "", 16),
+ StrFixedLenField("ruleset", "", 16),
+ SignedIntField("rulenumber", 0),
+ SignedIntField("subrulenumber", 0),
+ SignedIntField("uid", 0),
+ IntField("pid", 0),
+ SignedIntField("ruleuid", 0),
+ IntField("rulepid", 0),
+ ByteEnumField("direction", 255, {0: "inout", 1: "in",
+ 2:"out", 255: "unknown"}),
+ StrFixedLenField("pad", "\x00\x00\x00", 3 ) ]
+ def mysummary(self):
+ return self.sprintf("%PFLog.addrfamily% %PFLog.action% on %PFLog.iface% by rule %PFLog.rulenumber%")
+
+bind_layers(PFLog, IP, addrfamily=socket.AF_INET)
+if conf.ipv6_enabled:
+ bind_layers(PFLog, IPv6, addrfamily=socket.AF_INET6)
+
+conf.l2types.register(117, PFLog)
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ppp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ppp.py
new file mode 100644
index 00000000..08cf62cd
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/ppp.py
@@ -0,0 +1,349 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+PPP (Point to Point Protocol)
+
+[RFC 1661]
+"""
+
+import struct
+from scapy.packet import *
+from scapy.layers.l2 import *
+from scapy.layers.inet import *
+from scapy.fields import *
+
+class PPPoE(Packet):
+ name = "PPP over Ethernet"
+ fields_desc = [ BitField("version", 1, 4),
+ BitField("type", 1, 4),
+ ByteEnumField("code", 0, {0:"Session"}),
+ XShortField("sessionid", 0x0),
+ ShortField("len", None) ]
+
+ def post_build(self, p, pay):
+ p += pay
+ if self.len is None:
+ l = len(p)-6
+ p = p[:4]+struct.pack("!H", l)+p[6:]
+ return p
+
+class PPPoED(PPPoE):
+ name = "PPP over Ethernet Discovery"
+ fields_desc = [ BitField("version", 1, 4),
+ BitField("type", 1, 4),
+ ByteEnumField("code", 0x09, {0x09:"PADI",0x07:"PADO",0x19:"PADR",0x65:"PADS",0xa7:"PADT"}),
+ XShortField("sessionid", 0x0),
+ ShortField("len", None) ]
+
+
+_PPP_proto = { 0x0001: "Padding Protocol",
+ 0x0003: "ROHC small-CID [RFC3095]",
+ 0x0005: "ROHC large-CID [RFC3095]",
+ 0x0021: "Internet Protocol version 4",
+ 0x0023: "OSI Network Layer",
+ 0x0025: "Xerox NS IDP",
+ 0x0027: "DECnet Phase IV",
+ 0x0029: "Appletalk",
+ 0x002b: "Novell IPX",
+ 0x002d: "Van Jacobson Compressed TCP/IP",
+ 0x002f: "Van Jacobson Uncompressed TCP/IP",
+ 0x0031: "Bridging PDU",
+ 0x0033: "Stream Protocol (ST-II)",
+ 0x0035: "Banyan Vines",
+ 0x0037: "reserved (until 1993) [Typo in RFC1172]",
+ 0x0039: "AppleTalk EDDP",
+ 0x003b: "AppleTalk SmartBuffered",
+ 0x003d: "Multi-Link [RFC1717]",
+ 0x003f: "NETBIOS Framing",
+ 0x0041: "Cisco Systems",
+ 0x0043: "Ascom Timeplex",
+ 0x0045: "Fujitsu Link Backup and Load Balancing (LBLB)",
+ 0x0047: "DCA Remote Lan",
+ 0x0049: "Serial Data Transport Protocol (PPP-SDTP)",
+ 0x004b: "SNA over 802.2",
+ 0x004d: "SNA",
+ 0x004f: "IPv6 Header Compression",
+ 0x0051: "KNX Bridging Data [ianp]",
+ 0x0053: "Encryption [Meyer]",
+ 0x0055: "Individual Link Encryption [Meyer]",
+ 0x0057: "Internet Protocol version 6 [Hinden]",
+ 0x0059: "PPP Muxing [RFC3153]",
+ 0x005b: "Vendor-Specific Network Protocol (VSNP) [RFC3772]",
+ 0x0061: "RTP IPHC Full Header [RFC3544]",
+ 0x0063: "RTP IPHC Compressed TCP [RFC3544]",
+ 0x0065: "RTP IPHC Compressed Non TCP [RFC3544]",
+ 0x0067: "RTP IPHC Compressed UDP 8 [RFC3544]",
+ 0x0069: "RTP IPHC Compressed RTP 8 [RFC3544]",
+ 0x006f: "Stampede Bridging",
+ 0x0071: "Reserved [Fox]",
+ 0x0073: "MP+ Protocol [Smith]",
+ 0x007d: "reserved (Control Escape) [RFC1661]",
+ 0x007f: "reserved (compression inefficient [RFC1662]",
+ 0x0081: "Reserved Until 20-Oct-2000 [IANA]",
+ 0x0083: "Reserved Until 20-Oct-2000 [IANA]",
+ 0x00c1: "NTCITS IPI [Ungar]",
+ 0x00cf: "reserved (PPP NLID)",
+ 0x00fb: "single link compression in multilink [RFC1962]",
+ 0x00fd: "compressed datagram [RFC1962]",
+ 0x00ff: "reserved (compression inefficient)",
+ 0x0201: "802.1d Hello Packets",
+ 0x0203: "IBM Source Routing BPDU",
+ 0x0205: "DEC LANBridge100 Spanning Tree",
+ 0x0207: "Cisco Discovery Protocol [Sastry]",
+ 0x0209: "Netcs Twin Routing [Korfmacher]",
+ 0x020b: "STP - Scheduled Transfer Protocol [Segal]",
+ 0x020d: "EDP - Extreme Discovery Protocol [Grosser]",
+ 0x0211: "Optical Supervisory Channel Protocol (OSCP)[Prasad]",
+ 0x0213: "Optical Supervisory Channel Protocol (OSCP)[Prasad]",
+ 0x0231: "Luxcom",
+ 0x0233: "Sigma Network Systems",
+ 0x0235: "Apple Client Server Protocol [Ridenour]",
+ 0x0281: "MPLS Unicast [RFC3032] ",
+ 0x0283: "MPLS Multicast [RFC3032]",
+ 0x0285: "IEEE p1284.4 standard - data packets [Batchelder]",
+ 0x0287: "ETSI TETRA Network Protocol Type 1 [Nieminen]",
+ 0x0289: "Multichannel Flow Treatment Protocol [McCann]",
+ 0x2063: "RTP IPHC Compressed TCP No Delta [RFC3544]",
+ 0x2065: "RTP IPHC Context State [RFC3544]",
+ 0x2067: "RTP IPHC Compressed UDP 16 [RFC3544]",
+ 0x2069: "RTP IPHC Compressed RTP 16 [RFC3544]",
+ 0x4001: "Cray Communications Control Protocol [Stage]",
+ 0x4003: "CDPD Mobile Network Registration Protocol [Quick]",
+ 0x4005: "Expand accelerator protocol [Rachmani]",
+ 0x4007: "ODSICP NCP [Arvind]",
+ 0x4009: "DOCSIS DLL [Gaedtke]",
+ 0x400B: "Cetacean Network Detection Protocol [Siller]",
+ 0x4021: "Stacker LZS [Simpson]",
+ 0x4023: "RefTek Protocol [Banfill]",
+ 0x4025: "Fibre Channel [Rajagopal]",
+ 0x4027: "EMIT Protocols [Eastham]",
+ 0x405b: "Vendor-Specific Protocol (VSP) [RFC3772]",
+ 0x8021: "Internet Protocol Control Protocol",
+ 0x8023: "OSI Network Layer Control Protocol",
+ 0x8025: "Xerox NS IDP Control Protocol",
+ 0x8027: "DECnet Phase IV Control Protocol",
+ 0x8029: "Appletalk Control Protocol",
+ 0x802b: "Novell IPX Control Protocol",
+ 0x802d: "reserved",
+ 0x802f: "reserved",
+ 0x8031: "Bridging NCP",
+ 0x8033: "Stream Protocol Control Protocol",
+ 0x8035: "Banyan Vines Control Protocol",
+ 0x8037: "reserved (until 1993)",
+ 0x8039: "reserved",
+ 0x803b: "reserved",
+ 0x803d: "Multi-Link Control Protocol",
+ 0x803f: "NETBIOS Framing Control Protocol",
+ 0x8041: "Cisco Systems Control Protocol",
+ 0x8043: "Ascom Timeplex",
+ 0x8045: "Fujitsu LBLB Control Protocol",
+ 0x8047: "DCA Remote Lan Network Control Protocol (RLNCP)",
+ 0x8049: "Serial Data Control Protocol (PPP-SDCP)",
+ 0x804b: "SNA over 802.2 Control Protocol",
+ 0x804d: "SNA Control Protocol",
+ 0x804f: "IP6 Header Compression Control Protocol",
+ 0x8051: "KNX Bridging Control Protocol [ianp]",
+ 0x8053: "Encryption Control Protocol [Meyer]",
+ 0x8055: "Individual Link Encryption Control Protocol [Meyer]",
+ 0x8057: "IPv6 Control Protovol [Hinden]",
+ 0x8059: "PPP Muxing Control Protocol [RFC3153]",
+ 0x805b: "Vendor-Specific Network Control Protocol (VSNCP) [RFC3772]",
+ 0x806f: "Stampede Bridging Control Protocol",
+ 0x8073: "MP+ Control Protocol [Smith]",
+ 0x8071: "Reserved [Fox]",
+ 0x807d: "Not Used - reserved [RFC1661]",
+ 0x8081: "Reserved Until 20-Oct-2000 [IANA]",
+ 0x8083: "Reserved Until 20-Oct-2000 [IANA]",
+ 0x80c1: "NTCITS IPI Control Protocol [Ungar]",
+ 0x80cf: "Not Used - reserved [RFC1661]",
+ 0x80fb: "single link compression in multilink control [RFC1962]",
+ 0x80fd: "Compression Control Protocol [RFC1962]",
+ 0x80ff: "Not Used - reserved [RFC1661]",
+ 0x8207: "Cisco Discovery Protocol Control [Sastry]",
+ 0x8209: "Netcs Twin Routing [Korfmacher]",
+ 0x820b: "STP - Control Protocol [Segal]",
+ 0x820d: "EDPCP - Extreme Discovery Protocol Ctrl Prtcl [Grosser]",
+ 0x8235: "Apple Client Server Protocol Control [Ridenour]",
+ 0x8281: "MPLSCP [RFC3032]",
+ 0x8285: "IEEE p1284.4 standard - Protocol Control [Batchelder]",
+ 0x8287: "ETSI TETRA TNP1 Control Protocol [Nieminen]",
+ 0x8289: "Multichannel Flow Treatment Protocol [McCann]",
+ 0xc021: "Link Control Protocol",
+ 0xc023: "Password Authentication Protocol",
+ 0xc025: "Link Quality Report",
+ 0xc027: "Shiva Password Authentication Protocol",
+ 0xc029: "CallBack Control Protocol (CBCP)",
+ 0xc02b: "BACP Bandwidth Allocation Control Protocol [RFC2125]",
+ 0xc02d: "BAP [RFC2125]",
+ 0xc05b: "Vendor-Specific Authentication Protocol (VSAP) [RFC3772]",
+ 0xc081: "Container Control Protocol [KEN]",
+ 0xc223: "Challenge Handshake Authentication Protocol",
+ 0xc225: "RSA Authentication Protocol [Narayana]",
+ 0xc227: "Extensible Authentication Protocol [RFC2284]",
+ 0xc229: "Mitsubishi Security Info Exch Ptcl (SIEP) [Seno]",
+ 0xc26f: "Stampede Bridging Authorization Protocol",
+ 0xc281: "Proprietary Authentication Protocol [KEN]",
+ 0xc283: "Proprietary Authentication Protocol [Tackabury]",
+ 0xc481: "Proprietary Node ID Authentication Protocol [KEN]"}
+
+
+class HDLC(Packet):
+ fields_desc = [ XByteField("address",0xff),
+ XByteField("control",0x03) ]
+
+class PPP(Packet):
+ name = "PPP Link Layer"
+ fields_desc = [ ShortEnumField("proto", 0x0021, _PPP_proto) ]
+ @classmethod
+ def dispatch_hook(cls, _pkt=None, *args, **kargs):
+ if _pkt and _pkt[0] == 0xff:
+ cls = HDLC
+ return cls
+
+_PPP_conftypes = { 1:"Configure-Request",
+ 2:"Configure-Ack",
+ 3:"Configure-Nak",
+ 4:"Configure-Reject",
+ 5:"Terminate-Request",
+ 6:"Terminate-Ack",
+ 7:"Code-Reject",
+ 8:"Protocol-Reject",
+ 9:"Echo-Request",
+ 10:"Echo-Reply",
+ 11:"Discard-Request",
+ 14:"Reset-Request",
+ 15:"Reset-Ack",
+ }
+
+
+### PPP IPCP stuff (RFC 1332)
+
+# All IPCP options are defined below (names and associated classes)
+_PPP_ipcpopttypes = { 1:"IP-Addresses (Deprecated)",
+ 2:"IP-Compression-Protocol",
+ 3:"IP-Address",
+ 4:"Mobile-IPv4", # not implemented, present for completeness
+ 129:"Primary-DNS-Address",
+ 130:"Primary-NBNS-Address",
+ 131:"Secondary-DNS-Address",
+ 132:"Secondary-NBNS-Address"}
+
+
+class PPP_IPCP_Option(Packet):
+ name = "PPP IPCP Option"
+ fields_desc = [ ByteEnumField("type" , None , _PPP_ipcpopttypes),
+ FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
+ StrLenField("data", b"", length_from=lambda p:max(0,p.len-2)) ]
+ def extract_padding(self, pay):
+ return b"",pay
+
+ registered_options = {}
+ @classmethod
+ def register_variant(cls):
+ cls.registered_options[cls.type.default] = cls
+ @classmethod
+ def dispatch_hook(cls, _pkt=None, *args, **kargs):
+ if _pkt:
+ #o = ord(_pkt[0])
+ o = (_pkt[0])
+ return cls.registered_options.get(o, cls)
+ return cls
+
+
+class PPP_IPCP_Option_IPAddress(PPP_IPCP_Option):
+ name = "PPP IPCP Option: IP Address"
+ fields_desc = [ ByteEnumField("type" , 3 , _PPP_ipcpopttypes),
+ FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
+ IPField("data","0.0.0.0"),
+ ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ]
+
+class PPP_IPCP_Option_DNS1(PPP_IPCP_Option):
+ name = "PPP IPCP Option: DNS1 Address"
+ fields_desc = [ ByteEnumField("type" , 129 , _PPP_ipcpopttypes),
+ FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
+ IPField("data","0.0.0.0"),
+ ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ]
+
+class PPP_IPCP_Option_DNS2(PPP_IPCP_Option):
+ name = "PPP IPCP Option: DNS2 Address"
+ fields_desc = [ ByteEnumField("type" , 131 , _PPP_ipcpopttypes),
+ FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
+ IPField("data","0.0.0.0"),
+ ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ]
+
+class PPP_IPCP_Option_NBNS1(PPP_IPCP_Option):
+ name = "PPP IPCP Option: NBNS1 Address"
+ fields_desc = [ ByteEnumField("type" , 130 , _PPP_ipcpopttypes),
+ FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
+ IPField("data","0.0.0.0"),
+ ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ]
+
+class PPP_IPCP_Option_NBNS2(PPP_IPCP_Option):
+ name = "PPP IPCP Option: NBNS2 Address"
+ fields_desc = [ ByteEnumField("type" , 132 , _PPP_ipcpopttypes),
+ FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
+ IPField("data","0.0.0.0"),
+ ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ]
+
+
+class PPP_IPCP(Packet):
+ fields_desc = [ ByteEnumField("code" , 1, _PPP_conftypes),
+ XByteField("id", 0 ),
+ FieldLenField("len" , None, fmt="H", length_of="options", adjust=lambda p,x:x+4 ),
+ PacketListField("options", [], PPP_IPCP_Option, length_from=lambda p:p.len-4,) ]
+
+
+### ECP
+
+_PPP_ecpopttypes = { 0:"OUI",
+ 1:"DESE", }
+
+class PPP_ECP_Option(Packet):
+ name = "PPP ECP Option"
+ fields_desc = [ ByteEnumField("type" , None , _PPP_ecpopttypes),
+ FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2),
+ StrLenField("data", "", length_from=lambda p:max(0,p.len-2)) ]
+ def extract_padding(self, pay):
+ return b"",pay
+
+ registered_options = {}
+ @classmethod
+ def register_variant(cls):
+ cls.registered_options[cls.type.default] = cls
+ @classmethod
+ def dispatch_hook(cls, _pkt=None, *args, **kargs):
+ if _pkt:
+ #o = ord(_pkt[0])
+ o = (_pkt[0])
+ return cls.registered_options.get(o, cls)
+ return cls
+
+class PPP_ECP_Option_OUI(PPP_ECP_Option):
+ fields_desc = [ ByteEnumField("type" , 0 , _PPP_ecpopttypes),
+ FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+6),
+ StrFixedLenField("oui","",3),
+ ByteField("subtype",0),
+ StrLenField("data", "", length_from=lambda p:p.len-6) ]
+
+
+
+class PPP_ECP(Packet):
+ fields_desc = [ ByteEnumField("code" , 1, _PPP_conftypes),
+ XByteField("id", 0 ),
+ FieldLenField("len" , None, fmt="H", length_of="options", adjust=lambda p,x:x+4 ),
+ PacketListField("options", [], PPP_ECP_Option, length_from=lambda p:p.len-4,) ]
+
+bind_layers( Ether, PPPoED, type=0x8863)
+bind_layers( Ether, PPPoE, type=0x8864)
+bind_layers( CookedLinux, PPPoED, proto=0x8863)
+bind_layers( CookedLinux, PPPoE, proto=0x8864)
+bind_layers( PPPoE, PPP, code=0)
+bind_layers( HDLC, PPP, )
+bind_layers( PPP, IP, proto=33)
+bind_layers( PPP, PPP_IPCP, proto=0x8021)
+bind_layers( PPP, PPP_ECP, proto=0x8053)
+bind_layers( Ether, PPP_IPCP, type=0x8021)
+bind_layers( Ether, PPP_ECP, type=0x8053)
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/radius.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/radius.py
new file mode 100644
index 00000000..13239603
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/radius.py
@@ -0,0 +1,65 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+RADIUS (Remote Authentication Dial In User Service)
+"""
+
+import struct
+from scapy.packet import *
+from scapy.fields import *
+
+class Radius(Packet):
+ name = "Radius"
+ fields_desc = [ ByteEnumField("code", 1, {1: "Access-Request",
+ 2: "Access-Accept",
+ 3: "Access-Reject",
+ 4: "Accounting-Request",
+ 5: "Accounting-Accept",
+ 6: "Accounting-Status",
+ 7: "Password-Request",
+ 8: "Password-Ack",
+ 9: "Password-Reject",
+ 10: "Accounting-Message",
+ 11: "Access-Challenge",
+ 12: "Status-Server",
+ 13: "Status-Client",
+ 21: "Resource-Free-Request",
+ 22: "Resource-Free-Response",
+ 23: "Resource-Query-Request",
+ 24: "Resource-Query-Response",
+ 25: "Alternate-Resource-Reclaim-Request",
+ 26: "NAS-Reboot-Request",
+ 27: "NAS-Reboot-Response",
+ 29: "Next-Passcode",
+ 30: "New-Pin",
+ 31: "Terminate-Session",
+ 32: "Password-Expired",
+ 33: "Event-Request",
+ 34: "Event-Response",
+ 40: "Disconnect-Request",
+ 41: "Disconnect-ACK",
+ 42: "Disconnect-NAK",
+ 43: "CoA-Request",
+ 44: "CoA-ACK",
+ 45: "CoA-NAK",
+ 50: "IP-Address-Allocate",
+ 51: "IP-Address-Release",
+ 253: "Experimental-use",
+ 254: "Reserved",
+ 255: "Reserved"} ),
+ ByteField("id", 0),
+ ShortField("len", None),
+ StrFixedLenField("authenticator","",16) ]
+ def post_build(self, p, pay):
+ p += pay
+ l = self.len
+ if l is None:
+ l = len(p)
+ p = p[:2]+struct.pack("!H",l)+p[4:]
+ return p
+
+
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/rip.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/rip.py
new file mode 100644
index 00000000..1507fe5c
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/rip.py
@@ -0,0 +1,74 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+RIP (Routing Information Protocol).
+"""
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.inet import UDP
+
+class RIP(Packet):
+ name = "RIP header"
+ fields_desc = [
+ ByteEnumField("cmd", 1, {1:"req", 2:"resp", 3:"traceOn", 4:"traceOff",
+ 5:"sun", 6:"trigReq", 7:"trigResp", 8:"trigAck",
+ 9:"updateReq", 10:"updateResp", 11:"updateAck"}),
+ ByteField("version", 1),
+ ShortField("null", 0),
+ ]
+
+ def guess_payload_class(self, payload):
+ if payload[:2] == "\xff\xff":
+ return RIPAuth
+ else:
+ return Packet.guess_payload_class(self, payload)
+
+class RIPEntry(RIP):
+ name = "RIP entry"
+ fields_desc = [
+ ShortEnumField("AF", 2, {2:"IP"}),
+ ShortField("RouteTag", 0),
+ IPField("addr", "0.0.0.0"),
+ IPField("mask", "0.0.0.0"),
+ IPField("nextHop", "0.0.0.0"),
+ IntEnumField("metric", 1, {16:"Unreach"}),
+ ]
+
+class RIPAuth(Packet):
+ name = "RIP authentication"
+ fields_desc = [
+ ShortEnumField("AF", 0xffff, {0xffff:"Auth"}),
+ ShortEnumField("authtype", 2, {1:"md5authdata", 2:"simple", 3:"md5"}),
+ ConditionalField(StrFixedLenField("password", None, 16),
+ lambda pkt: pkt.authtype == 2),
+ ConditionalField(ShortField("digestoffset", 0),
+ lambda pkt: pkt.authtype == 3),
+ ConditionalField(ByteField("keyid", 0),
+ lambda pkt: pkt.authtype == 3),
+ ConditionalField(ByteField("authdatalen", 0),
+ lambda pkt: pkt.authtype == 3),
+ ConditionalField(IntField("seqnum", 0),
+ lambda pkt: pkt.authtype == 3),
+ ConditionalField(StrFixedLenField("zeropad", None, 8),
+ lambda pkt: pkt.authtype == 3),
+ ConditionalField(StrLenField("authdata", None,
+ length_from=lambda pkt: pkt.md5datalen),
+ lambda pkt: pkt.authtype == 1)
+ ]
+
+ def pre_dissect(self, s):
+ if s[2:4] == "\x00\x01":
+ self.md5datalen = len(s) - 4
+
+ return s
+
+
+bind_layers( UDP, RIP, sport=520)
+bind_layers( UDP, RIP, dport=520)
+bind_layers( RIP, RIPEntry, )
+bind_layers( RIPEntry, RIPEntry, )
+bind_layers( RIPAuth, RIPEntry, )
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/rtp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/rtp.py
new file mode 100644
index 00000000..629dccdd
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/rtp.py
@@ -0,0 +1,40 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+RTP (Real-time Transport Protocol).
+"""
+
+from scapy.packet import *
+from scapy.fields import *
+
+_rtp_payload_types = {
+ # http://www.iana.org/assignments/rtp-parameters
+ 0: 'G.711 PCMU', 3: 'GSM',
+ 4: 'G723', 5: 'DVI4',
+ 6: 'DVI4', 7: 'LPC',
+ 8: 'PCMA', 9: 'G722',
+ 10: 'L16', 11: 'L16',
+ 12: 'QCELP', 13: 'CN',
+ 14: 'MPA', 15: 'G728',
+ 16: 'DVI4', 17: 'DVI4',
+ 18: 'G729', 25: 'CelB',
+ 26: 'JPEG', 28: 'nv',
+ 31: 'H261', 32: 'MPV',
+ 33: 'MP2T', 34: 'H263' }
+
+class RTP(Packet):
+ name="RTP"
+ fields_desc = [ BitField('version', 2, 2),
+ BitField('padding', 0, 1),
+ BitField('extension', 0, 1),
+ BitFieldLenField('numsync', None, 4, count_of='sync'),
+ BitField('marker', 0, 1),
+ BitEnumField('payload', 0, 7, _rtp_payload_types),
+ ShortField('sequence', 0),
+ IntField('timestamp', 0),
+ IntField('sourcesync', 0),
+ FieldListField('sync', [], IntField("id",0), count_from=lambda pkt:pkt.numsync) ]
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/sctp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/sctp.py
new file mode 100644
index 00000000..57712112
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/sctp.py
@@ -0,0 +1,439 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## Copyright (C) 6WIND <olivier.matz@6wind.com>
+## This program is published under a GPLv2 license
+
+"""
+SCTP (Stream Control Transmission Protocol).
+"""
+
+import struct
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.inet import IP
+from scapy.layers.inet6 import IP6Field
+
+IPPROTO_SCTP=132
+
+# crc32-c (Castagnoli) (crc32c_poly=0x1EDC6F41)
+crc32c_table = [
+ 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
+ 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
+ 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
+ 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
+ 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
+ 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
+ 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
+ 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
+ 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
+ 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
+ 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
+ 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
+ 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
+ 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
+ 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
+ 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
+ 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
+ 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
+ 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
+ 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
+ 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
+ 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
+ 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
+ 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
+ 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
+ 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
+ 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
+ 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
+ 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
+ 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
+ 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
+ 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
+ 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
+ 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
+ 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
+ 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
+ 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
+ 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
+ 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
+ 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
+ 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
+ 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
+ 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
+ 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
+ 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
+ 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
+ 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
+ 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
+ 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
+ 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
+ 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
+ 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
+ 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
+ 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
+ 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
+ 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
+ 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
+ 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
+ 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
+ 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
+ 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
+ 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
+ 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
+ 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351,
+ ]
+
+def crc32c(buf):
+ crc = 0xffffffff
+ for c in buf:
+ #crc = (crc>>8) ^ crc32c_table[(crc^(ord(c))) & 0xFF]
+ crc = (crc>>8) ^ crc32c_table[(crc^(c)) & 0xFF]
+ crc = (~crc) & 0xffffffff
+ # reverse endianness
+ return struct.unpack(">I",struct.pack("<I", crc))[0]
+
+# old checksum (RFC2960)
+"""
+BASE = 65521 # largest prime smaller than 65536
+def update_adler32(adler, buf):
+ s1 = adler & 0xffff
+ s2 = (adler >> 16) & 0xffff
+ print(s1,s2)
+
+ for c in buf:
+ print(ord(c))
+ s1 = (s1 + ord(c)) % BASE
+ s2 = (s2 + s1) % BASE
+ print(s1,s2)
+ return (s2 << 16) + s1
+
+def sctp_checksum(buf):
+ return update_adler32(1, buf)
+"""
+
+sctpchunktypescls = {
+ 0 : "SCTPChunkData",
+ 1 : "SCTPChunkInit",
+ 2 : "SCTPChunkInitAck",
+ 3 : "SCTPChunkSACK",
+ 4 : "SCTPChunkHeartbeatReq",
+ 5 : "SCTPChunkHeartbeatAck",
+ 6 : "SCTPChunkAbort",
+ 7 : "SCTPChunkShutdown",
+ 8 : "SCTPChunkShutdownAck",
+ 9 : "SCTPChunkError",
+ 10 : "SCTPChunkCookieEcho",
+ 11 : "SCTPChunkCookieAck",
+ 14 : "SCTPChunkShutdownComplete",
+ }
+
+sctpchunktypes = {
+ 0 : "data",
+ 1 : "init",
+ 2 : "init-ack",
+ 3 : "sack",
+ 4 : "heartbeat-req",
+ 5 : "heartbeat-ack",
+ 6 : "abort",
+ 7 : "shutdown",
+ 8 : "shutdown-ack",
+ 9 : "error",
+ 10 : "cookie-echo",
+ 11 : "cookie-ack",
+ 14 : "shutdown-complete",
+ }
+
+sctpchunkparamtypescls = {
+ 1 : "SCTPChunkParamHearbeatInfo",
+ 5 : "SCTPChunkParamIPv4Addr",
+ 6 : "SCTPChunkParamIPv6Addr",
+ 7 : "SCTPChunkParamStateCookie",
+ 8 : "SCTPChunkParamUnrocognizedParam",
+ 9 : "SCTPChunkParamCookiePreservative",
+ 11 : "SCTPChunkParamHostname",
+ 12 : "SCTPChunkParamSupportedAddrTypes",
+ 32768 : "SCTPChunkParamECNCapable",
+ 49152 : "SCTPChunkParamFwdTSN",
+ 49158 : "SCTPChunkParamAdaptationLayer",
+ }
+
+sctpchunkparamtypes = {
+ 1 : "heartbeat-info",
+ 5 : "IPv4",
+ 6 : "IPv6",
+ 7 : "state-cookie",
+ 8 : "unrecognized-param",
+ 9 : "cookie-preservative",
+ 11 : "hostname",
+ 12 : "addrtypes",
+ 32768 : "ecn-capable",
+ 49152 : "fwd-tsn-supported",
+ 49158 : "adaptation-layer",
+ }
+
+############## SCTP header
+
+# Dummy class to guess payload type (variable parameters)
+class _SCTPChunkGuessPayload:
+ def default_payload_class(self,p):
+ if len(p) < 4:
+ return conf.padding_layer
+ else:
+ t = p[0]
+ return globals().get(sctpchunktypescls.get(t, "Raw"), conf.raw_layer)
+
+
+class SCTP(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ShortField("sport", None),
+ ShortField("dport", None),
+ XIntField("tag", None),
+ XIntField("chksum", None), ]
+ def answers(self, other):
+ if not isinstance(other, SCTP):
+ return 0
+ if conf.checkIPsrc:
+ if not ((self.sport == other.dport) and
+ (self.dport == other.sport)):
+ return 0
+ return 1
+ def post_build(self, p, pay):
+ p += pay
+ if self.chksum is None:
+ crc = crc32c(str(p))
+ p = p[:8]+struct.pack(">I", crc)+p[12:]
+ return p
+
+############## SCTP Chunk variable params
+
+class ChunkParamField(PacketListField):
+ islist = 1
+ holds_packets=1
+ def __init__(self, name, default, count_from=None, length_from=None):
+ PacketListField.__init__(self, name, default, conf.raw_layer, count_from=count_from, length_from=length_from)
+ def m2i(self, p, m):
+ cls = conf.raw_layer
+ if len(m) >= 4:
+ #t = ord(m[0]) * 256 + ord(m[1])
+ t = (m[0]) * 256 + (m[1])
+ cls = globals().get(sctpchunkparamtypescls.get(t, "Raw"), conf.raw_layer)
+ return cls(m)
+
+# dummy class to avoid Raw() after Chunk params
+class _SCTPChunkParam:
+ def extract_padding(self, s):
+ return b"",s[:]
+
+class SCTPChunkParamHearbeatInfo(_SCTPChunkParam, Packet):
+ fields_desc = [ ShortEnumField("type", 1, sctpchunkparamtypes),
+ FieldLenField("len", None, length_of="data",
+ adjust = lambda pkt,x:x+4),
+ PadField(StrLenField("data", b"",
+ length_from=lambda pkt: pkt.len-4),
+ 4, padwith=b"\x00"),]
+
+class SCTPChunkParamIPv4Addr(_SCTPChunkParam, Packet):
+ fields_desc = [ ShortEnumField("type", 5, sctpchunkparamtypes),
+ ShortField("len", 8),
+ IPField("addr","127.0.0.1"), ]
+
+class SCTPChunkParamIPv6Addr(_SCTPChunkParam, Packet):
+ fields_desc = [ ShortEnumField("type", 6, sctpchunkparamtypes),
+ ShortField("len", 20),
+ IP6Field("addr","::1"), ]
+
+class SCTPChunkParamStateCookie(_SCTPChunkParam, Packet):
+ fields_desc = [ ShortEnumField("type", 7, sctpchunkparamtypes),
+ FieldLenField("len", None, length_of="cookie",
+ adjust = lambda pkt,x:x+4),
+ PadField(StrLenField("cookie", b"",
+ length_from=lambda pkt: pkt.len-4),
+ 4, padwith=b"\x00"),]
+
+class SCTPChunkParamUnrocognizedParam(_SCTPChunkParam, Packet):
+ fields_desc = [ ShortEnumField("type", 8, sctpchunkparamtypes),
+ FieldLenField("len", None, length_of="param",
+ adjust = lambda pkt,x:x+4),
+ PadField(StrLenField("param", b"",
+ length_from=lambda pkt: pkt.len-4),
+ 4, padwith=b"\x00"),]
+
+class SCTPChunkParamCookiePreservative(_SCTPChunkParam, Packet):
+ fields_desc = [ ShortEnumField("type", 9, sctpchunkparamtypes),
+ ShortField("len", 8),
+ XIntField("sug_cookie_inc", None), ]
+
+class SCTPChunkParamHostname(_SCTPChunkParam, Packet):
+ fields_desc = [ ShortEnumField("type", 11, sctpchunkparamtypes),
+ FieldLenField("len", None, length_of="hostname",
+ adjust = lambda pkt,x:x+4),
+ PadField(StrLenField("hostname", b"",
+ length_from=lambda pkt: pkt.len-4),
+ 4, padwith=b"\x00"), ]
+
+class SCTPChunkParamSupportedAddrTypes(_SCTPChunkParam, Packet):
+ fields_desc = [ ShortEnumField("type", 12, sctpchunkparamtypes),
+ FieldLenField("len", None, length_of="addr_type_list",
+ adjust = lambda pkt,x:x+4),
+ PadField(FieldListField("addr_type_list", [ "IPv4" ],
+ ShortEnumField("addr_type", 5, sctpchunkparamtypes),
+ length_from=lambda pkt: pkt.len-4),
+ 4, padwith=b"\x00"), ]
+
+class SCTPChunkParamECNCapable(_SCTPChunkParam, Packet):
+ fields_desc = [ ShortEnumField("type", 32768, sctpchunkparamtypes),
+ ShortField("len", 4), ]
+
+class SCTPChunkParamFwdTSN(_SCTPChunkParam, Packet):
+ fields_desc = [ ShortEnumField("type", 49152, sctpchunkparamtypes),
+ ShortField("len", 4), ]
+
+class SCTPChunkParamAdaptationLayer(_SCTPChunkParam, Packet):
+ fields_desc = [ ShortEnumField("type", 49158, sctpchunkparamtypes),
+ ShortField("len", 8),
+ XIntField("indication", None), ]
+
+############## SCTP Chunks
+
+class SCTPChunkData(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 0, sctpchunktypes),
+ BitField("reserved", None, 4),
+ BitField("delay_sack", 0, 1),
+ BitField("unordered", 0, 1),
+ BitField("beginning", 0, 1),
+ BitField("ending", 0, 1),
+ FieldLenField("len", None, length_of="data", adjust = lambda pkt,x:x+16),
+ XIntField("tsn", None),
+ XShortField("stream_id", None),
+ XShortField("stream_seq", None),
+ XIntField("proto_id", None),
+ PadField(StrLenField("data", None, length_from=lambda pkt: pkt.len-16),
+ 4, padwith=b"\x00"),
+ ]
+
+class SCTPChunkInit(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 1, sctpchunktypes),
+ XByteField("flags", None),
+ FieldLenField("len", None, length_of="params", adjust = lambda pkt,x:x+20),
+ XIntField("init_tag", None),
+ IntField("a_rwnd", None),
+ ShortField("n_out_streams", None),
+ ShortField("n_in_streams", None),
+ XIntField("init_tsn", None),
+ ChunkParamField("params", None, length_from=lambda pkt:pkt.len-20),
+ ]
+
+class SCTPChunkInitAck(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 2, sctpchunktypes),
+ XByteField("flags", None),
+ FieldLenField("len", None, length_of="params", adjust = lambda pkt,x:x+20),
+ XIntField("init_tag", None),
+ IntField("a_rwnd", None),
+ ShortField("n_out_streams", None),
+ ShortField("n_in_streams", None),
+ XIntField("init_tsn", None),
+ ChunkParamField("params", None, length_from=lambda pkt:pkt.len-20),
+ ]
+
+class GapAckField(Field):
+ def __init__(self, name, default):
+ Field.__init__(self, name, default, "4s")
+ def i2m(self, pkt, x):
+ if x is None:
+ return "\0\0\0\0"
+ sta, end = map(int, x.split(":"))
+ args = tuple([">HH", sta, end])
+ return struct.pack(*args)
+ def m2i(self, pkt, x):
+ return "%d:%d"%(struct.unpack(">HH", x))
+ def any2i(self, pkt, x):
+ if type(x) is tuple and len(x) == 2:
+ return "%d:%d"%(x)
+ return x
+
+class SCTPChunkSACK(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 3, sctpchunktypes),
+ XByteField("flags", None),
+ ShortField("len", None),
+ XIntField("cumul_tsn_ack", None),
+ IntField("a_rwnd", None),
+ FieldLenField("n_gap_ack", None, count_of="gap_ack_list"),
+ FieldLenField("n_dup_tsn", None, count_of="dup_tsn_list"),
+ FieldListField("gap_ack_list", [ ], GapAckField("gap_ack", None), count_from=lambda pkt:pkt.n_gap_ack),
+ FieldListField("dup_tsn_list", [ ], XIntField("dup_tsn", None), count_from=lambda pkt:pkt.n_dup_tsn),
+ ]
+
+ def post_build(self, p, pay):
+ if self.len is None:
+ p = p[:2] + struct.pack(">H", len(p)) + p[4:]
+ return p+pay
+
+
+class SCTPChunkHeartbeatReq(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 4, sctpchunktypes),
+ XByteField("flags", None),
+ FieldLenField("len", None, length_of="params", adjust = lambda pkt,x:x+4),
+ ChunkParamField("params", None, length_from=lambda pkt:pkt.len-4),
+ ]
+
+class SCTPChunkHeartbeatAck(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 5, sctpchunktypes),
+ XByteField("flags", None),
+ FieldLenField("len", None, length_of="params", adjust = lambda pkt,x:x+4),
+ ChunkParamField("params", None, length_from=lambda pkt:pkt.len-4),
+ ]
+
+class SCTPChunkAbort(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 6, sctpchunktypes),
+ BitField("reserved", None, 7),
+ BitField("TCB", 0, 1),
+ FieldLenField("len", None, length_of="error_causes", adjust = lambda pkt,x:x+4),
+ PadField(StrLenField("error_causes", b"", length_from=lambda pkt: pkt.len-4),
+ 4, padwith=b"\x00"),
+ ]
+
+class SCTPChunkShutdown(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 7, sctpchunktypes),
+ XByteField("flags", None),
+ ShortField("len", 8),
+ XIntField("cumul_tsn_ack", None),
+ ]
+
+class SCTPChunkShutdownAck(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 8, sctpchunktypes),
+ XByteField("flags", None),
+ ShortField("len", 4),
+ ]
+
+class SCTPChunkError(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 9, sctpchunktypes),
+ XByteField("flags", None),
+ FieldLenField("len", None, length_of="error_causes", adjust = lambda pkt,x:x+4),
+ PadField(StrLenField("error_causes", b"", length_from=lambda pkt: pkt.len-4),
+ 4, padwith=b"\x00"),
+ ]
+
+class SCTPChunkCookieEcho(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 10, sctpchunktypes),
+ XByteField("flags", None),
+ FieldLenField("len", None, length_of="cookie", adjust = lambda pkt,x:x+4),
+ PadField(StrLenField("cookie", b"", length_from=lambda pkt: pkt.len-4),
+ 4, padwith=b"\x00"),
+ ]
+
+class SCTPChunkCookieAck(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 11, sctpchunktypes),
+ XByteField("flags", None),
+ ShortField("len", 4),
+ ]
+
+class SCTPChunkShutdownComplete(_SCTPChunkGuessPayload, Packet):
+ fields_desc = [ ByteEnumField("type", 12, sctpchunktypes),
+ BitField("reserved", None, 7),
+ BitField("TCB", 0, 1),
+ ShortField("len", 4),
+ ]
+
+bind_layers( IP, SCTP, proto=IPPROTO_SCTP)
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/sebek.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/sebek.py
new file mode 100644
index 00000000..c54e6728
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/sebek.py
@@ -0,0 +1,109 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+Sebek: Linux kernel module for data collection on honeypots.
+"""
+
+from scapy.fields import *
+from scapy.packet import *
+from scapy.layers.inet import UDP
+
+
+### SEBEK
+
+
+class SebekHead(Packet):
+ name = "Sebek header"
+ fields_desc = [ XIntField("magic", 0xd0d0d0),
+ ShortField("version", 1),
+ ShortEnumField("type", 0, {"read":0, "write":1,
+ "socket":2, "open":3}),
+ IntField("counter", 0),
+ IntField("time_sec", 0),
+ IntField("time_usec", 0) ]
+ def mysummary(self):
+ return self.sprintf("Sebek Header v%SebekHead.version% %SebekHead.type%")
+
+# we need this because Sebek headers differ between v1 and v3, and
+# between v3 type socket and v3 others
+
+class SebekV1(Packet):
+ name = "Sebek v1"
+ fields_desc = [ IntField("pid", 0),
+ IntField("uid", 0),
+ IntField("fd", 0),
+ StrFixedLenField("command", "", 12),
+ FieldLenField("data_length", None, "data",fmt="I"),
+ StrLenField("data", "", length_from=lambda x:x.data_length) ]
+ def mysummary(self):
+ if isinstance(self.underlayer, SebekHead):
+ return self.underlayer.sprintf("Sebek v1 %SebekHead.type% (%SebekV1.command%)")
+ else:
+ return self.sprintf("Sebek v1 (%SebekV1.command%)")
+
+class SebekV3(Packet):
+ name = "Sebek v3"
+ fields_desc = [ IntField("parent_pid", 0),
+ IntField("pid", 0),
+ IntField("uid", 0),
+ IntField("fd", 0),
+ IntField("inode", 0),
+ StrFixedLenField("command", "", 12),
+ FieldLenField("data_length", None, "data",fmt="I"),
+ StrLenField("data", "", length_from=lambda x:x.data_length) ]
+ def mysummary(self):
+ if isinstance(self.underlayer, SebekHead):
+ return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV3.command%)")
+ else:
+ return self.sprintf("Sebek v3 (%SebekV3.command%)")
+
+class SebekV2(SebekV3):
+ def mysummary(self):
+ if isinstance(self.underlayer, SebekHead):
+ return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV2.command%)")
+ else:
+ return self.sprintf("Sebek v2 (%SebekV2.command%)")
+
+class SebekV3Sock(Packet):
+ name = "Sebek v2 socket"
+ fields_desc = [ IntField("parent_pid", 0),
+ IntField("pid", 0),
+ IntField("uid", 0),
+ IntField("fd", 0),
+ IntField("inode", 0),
+ StrFixedLenField("command", "", 12),
+ IntField("data_length", 15),
+ IPField("dip", "127.0.0.1"),
+ ShortField("dport", 0),
+ IPField("sip", "127.0.0.1"),
+ ShortField("sport", 0),
+ ShortEnumField("call", 0, { "bind":2,
+ "connect":3, "listen":4,
+ "accept":5, "sendmsg":16,
+ "recvmsg":17, "sendto":11,
+ "recvfrom":12}),
+ ByteEnumField("proto", 0, IP_PROTOS) ]
+ def mysummary(self):
+ if isinstance(self.underlayer, SebekHead):
+ return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV3Sock.command%)")
+ else:
+ return self.sprintf("Sebek v3 socket (%SebekV3Sock.command%)")
+
+class SebekV2Sock(SebekV3Sock):
+ def mysummary(self):
+ if isinstance(self.underlayer, SebekHead):
+ return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV2Sock.command%)")
+ else:
+ return self.sprintf("Sebek v2 socket (%SebekV2Sock.command%)")
+
+bind_layers( UDP, SebekHead, sport=1101)
+bind_layers( UDP, SebekHead, dport=1101)
+bind_layers( UDP, SebekHead, dport=1101, sport=1101)
+bind_layers( SebekHead, SebekV1, version=1)
+bind_layers( SebekHead, SebekV2Sock, version=2, type=2)
+bind_layers( SebekHead, SebekV2, version=2)
+bind_layers( SebekHead, SebekV3Sock, version=3, type=2)
+bind_layers( SebekHead, SebekV3, version=3)
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/skinny.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/skinny.py
new file mode 100644
index 00000000..9fb6ac06
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/skinny.py
@@ -0,0 +1,161 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+Cisco Skinny protocol.
+"""
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.inet import TCP
+
+# shamelessly ripped from Ethereal dissector
+skinny_messages = {
+# Station -> Callmanager
+ 0x0000: "KeepAliveMessage",
+ 0x0001: "RegisterMessage",
+ 0x0002: "IpPortMessage",
+ 0x0003: "KeypadButtonMessage",
+ 0x0004: "EnblocCallMessage",
+ 0x0005: "StimulusMessage",
+ 0x0006: "OffHookMessage",
+ 0x0007: "OnHookMessage",
+ 0x0008: "HookFlashMessage",
+ 0x0009: "ForwardStatReqMessage",
+ 0x000A: "SpeedDialStatReqMessage",
+ 0x000B: "LineStatReqMessage",
+ 0x000C: "ConfigStatReqMessage",
+ 0x000D: "TimeDateReqMessage",
+ 0x000E: "ButtonTemplateReqMessage",
+ 0x000F: "VersionReqMessage",
+ 0x0010: "CapabilitiesResMessage",
+ 0x0011: "MediaPortListMessage",
+ 0x0012: "ServerReqMessage",
+ 0x0020: "AlarmMessage",
+ 0x0021: "MulticastMediaReceptionAck",
+ 0x0022: "OpenReceiveChannelAck",
+ 0x0023: "ConnectionStatisticsRes",
+ 0x0024: "OffHookWithCgpnMessage",
+ 0x0025: "SoftKeySetReqMessage",
+ 0x0026: "SoftKeyEventMessage",
+ 0x0027: "UnregisterMessage",
+ 0x0028: "SoftKeyTemplateReqMessage",
+ 0x0029: "RegisterTokenReq",
+ 0x002A: "MediaTransmissionFailure",
+ 0x002B: "HeadsetStatusMessage",
+ 0x002C: "MediaResourceNotification",
+ 0x002D: "RegisterAvailableLinesMessage",
+ 0x002E: "DeviceToUserDataMessage",
+ 0x002F: "DeviceToUserDataResponseMessage",
+ 0x0030: "UpdateCapabilitiesMessage",
+ 0x0031: "OpenMultiMediaReceiveChannelAckMessage",
+ 0x0032: "ClearConferenceMessage",
+ 0x0033: "ServiceURLStatReqMessage",
+ 0x0034: "FeatureStatReqMessage",
+ 0x0035: "CreateConferenceResMessage",
+ 0x0036: "DeleteConferenceResMessage",
+ 0x0037: "ModifyConferenceResMessage",
+ 0x0038: "AddParticipantResMessage",
+ 0x0039: "AuditConferenceResMessage",
+ 0x0040: "AuditParticipantResMessage",
+ 0x0041: "DeviceToUserDataVersion1Message",
+# Callmanager -> Station */
+ 0x0081: "RegisterAckMessage",
+ 0x0082: "StartToneMessage",
+ 0x0083: "StopToneMessage",
+ 0x0085: "SetRingerMessage",
+ 0x0086: "SetLampMessage",
+ 0x0087: "SetHkFDetectMessage",
+ 0x0088: "SetSpeakerModeMessage",
+ 0x0089: "SetMicroModeMessage",
+ 0x008A: "StartMediaTransmission",
+ 0x008B: "StopMediaTransmission",
+ 0x008C: "StartMediaReception",
+ 0x008D: "StopMediaReception",
+ 0x008F: "CallInfoMessage",
+ 0x0090: "ForwardStatMessage",
+ 0x0091: "SpeedDialStatMessage",
+ 0x0092: "LineStatMessage",
+ 0x0093: "ConfigStatMessage",
+ 0x0094: "DefineTimeDate",
+ 0x0095: "StartSessionTransmission",
+ 0x0096: "StopSessionTransmission",
+ 0x0097: "ButtonTemplateMessage",
+ 0x0098: "VersionMessage",
+ 0x0099: "DisplayTextMessage",
+ 0x009A: "ClearDisplay",
+ 0x009B: "CapabilitiesReqMessage",
+ 0x009C: "EnunciatorCommandMessage",
+ 0x009D: "RegisterRejectMessage",
+ 0x009E: "ServerResMessage",
+ 0x009F: "Reset",
+ 0x0100: "KeepAliveAckMessage",
+ 0x0101: "StartMulticastMediaReception",
+ 0x0102: "StartMulticastMediaTransmission",
+ 0x0103: "StopMulticastMediaReception",
+ 0x0104: "StopMulticastMediaTransmission",
+ 0x0105: "OpenReceiveChannel",
+ 0x0106: "CloseReceiveChannel",
+ 0x0107: "ConnectionStatisticsReq",
+ 0x0108: "SoftKeyTemplateResMessage",
+ 0x0109: "SoftKeySetResMessage",
+ 0x0110: "SelectSoftKeysMessage",
+ 0x0111: "CallStateMessage",
+ 0x0112: "DisplayPromptStatusMessage",
+ 0x0113: "ClearPromptStatusMessage",
+ 0x0114: "DisplayNotifyMessage",
+ 0x0115: "ClearNotifyMessage",
+ 0x0116: "ActivateCallPlaneMessage",
+ 0x0117: "DeactivateCallPlaneMessage",
+ 0x0118: "UnregisterAckMessage",
+ 0x0119: "BackSpaceReqMessage",
+ 0x011A: "RegisterTokenAck",
+ 0x011B: "RegisterTokenReject",
+ 0x0042: "DeviceToUserDataResponseVersion1Message",
+ 0x011C: "StartMediaFailureDetection",
+ 0x011D: "DialedNumberMessage",
+ 0x011E: "UserToDeviceDataMessage",
+ 0x011F: "FeatureStatMessage",
+ 0x0120: "DisplayPriNotifyMessage",
+ 0x0121: "ClearPriNotifyMessage",
+ 0x0122: "StartAnnouncementMessage",
+ 0x0123: "StopAnnouncementMessage",
+ 0x0124: "AnnouncementFinishMessage",
+ 0x0127: "NotifyDtmfToneMessage",
+ 0x0128: "SendDtmfToneMessage",
+ 0x0129: "SubscribeDtmfPayloadReqMessage",
+ 0x012A: "SubscribeDtmfPayloadResMessage",
+ 0x012B: "SubscribeDtmfPayloadErrMessage",
+ 0x012C: "UnSubscribeDtmfPayloadReqMessage",
+ 0x012D: "UnSubscribeDtmfPayloadResMessage",
+ 0x012E: "UnSubscribeDtmfPayloadErrMessage",
+ 0x012F: "ServiceURLStatMessage",
+ 0x0130: "CallSelectStatMessage",
+ 0x0131: "OpenMultiMediaChannelMessage",
+ 0x0132: "StartMultiMediaTransmission",
+ 0x0133: "StopMultiMediaTransmission",
+ 0x0134: "MiscellaneousCommandMessage",
+ 0x0135: "FlowControlCommandMessage",
+ 0x0136: "CloseMultiMediaReceiveChannel",
+ 0x0137: "CreateConferenceReqMessage",
+ 0x0138: "DeleteConferenceReqMessage",
+ 0x0139: "ModifyConferenceReqMessage",
+ 0x013A: "AddParticipantReqMessage",
+ 0x013B: "DropParticipantReqMessage",
+ 0x013C: "AuditConferenceReqMessage",
+ 0x013D: "AuditParticipantReqMessage",
+ 0x013F: "UserToDeviceDataVersion1Message",
+ }
+
+
+
+class Skinny(Packet):
+ name="Skinny"
+ fields_desc = [ LEIntField("len",0),
+ LEIntField("res",0),
+ LEIntEnumField("msg",0,skinny_messages) ]
+
+bind_layers( TCP, Skinny, dport=2000)
+bind_layers( TCP, Skinny, sport=2000)
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/smb.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/smb.py
new file mode 100644
index 00000000..f8e0da7a
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/smb.py
@@ -0,0 +1,354 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+SMB (Server Message Block), also known as CIFS.
+"""
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.netbios import NBTSession
+
+
+# SMB NetLogon Response Header
+class SMBNetlogon_Protocol_Response_Header(Packet):
+ name="SMBNetlogon Protocol Response Header"
+ fields_desc = [StrFixedLenField("Start","\xffSMB",4),
+ ByteEnumField("Command",0x25,{0x25:"Trans"}),
+ ByteField("Error_Class",0x02),
+ ByteField("Reserved",0),
+ LEShortField("Error_code",4),
+ ByteField("Flags",0),
+ LEShortField("Flags2",0x0000),
+ LEShortField("PIDHigh",0x0000),
+ LELongField("Signature",0x0),
+ LEShortField("Unused",0x0),
+ LEShortField("TID",0),
+ LEShortField("PID",0),
+ LEShortField("UID",0),
+ LEShortField("MID",0),
+ ByteField("WordCount",17),
+ LEShortField("TotalParamCount",0),
+ LEShortField("TotalDataCount",112),
+ LEShortField("MaxParamCount",0),
+ LEShortField("MaxDataCount",0),
+ ByteField("MaxSetupCount",0),
+ ByteField("unused2",0),
+ LEShortField("Flags3",0),
+ ByteField("TimeOut1",0xe8),
+ ByteField("TimeOut2",0x03),
+ LEShortField("unused3",0),
+ LEShortField("unused4",0),
+ LEShortField("ParamCount2",0),
+ LEShortField("ParamOffset",0),
+ LEShortField("DataCount",112),
+ LEShortField("DataOffset",92),
+ ByteField("SetupCount", 3),
+ ByteField("unused5", 0)]
+
+# SMB MailSlot Protocol
+class SMBMailSlot(Packet):
+ name = "SMB Mail Slot Protocol"
+ fields_desc = [LEShortField("opcode", 1),
+ LEShortField("priority", 1),
+ LEShortField("class", 2),
+ LEShortField("size", 135),
+ StrNullField("name","\\MAILSLOT\\NET\\GETDC660")]
+
+# SMB NetLogon Protocol Response Tail SAM
+class SMBNetlogon_Protocol_Response_Tail_SAM(Packet):
+ name = "SMB Netlogon Protocol Response Tail SAM"
+ fields_desc = [ByteEnumField("Command", 0x17, {0x12:"SAM logon request", 0x17:"SAM Active directory Response"}),
+ ByteField("unused", 0),
+ ShortField("Data1", 0),
+ ShortField("Data2", 0xfd01),
+ ShortField("Data3", 0),
+ ShortField("Data4", 0xacde),
+ ShortField("Data5", 0x0fe5),
+ ShortField("Data6", 0xd10a),
+ ShortField("Data7", 0x374c),
+ ShortField("Data8", 0x83e2),
+ ShortField("Data9", 0x7dd9),
+ ShortField("Data10", 0x3a16),
+ ShortField("Data11", 0x73ff),
+ ByteField("Data12", 0x04),
+ StrFixedLenField("Data13", "rmff", 4),
+ ByteField("Data14", 0x0),
+ ShortField("Data16", 0xc018),
+ ByteField("Data18", 0x0a),
+ StrFixedLenField("Data20", "rmff-win2k", 10),
+ ByteField("Data21", 0xc0),
+ ShortField("Data22", 0x18c0),
+ ShortField("Data23", 0x180a),
+ StrFixedLenField("Data24", "RMFF-WIN2K", 10),
+ ShortField("Data25", 0),
+ ByteField("Data26", 0x17),
+ StrFixedLenField("Data27", "Default-First-Site-Name", 23),
+ ShortField("Data28", 0x00c0),
+ ShortField("Data29", 0x3c10),
+ ShortField("Data30", 0x00c0),
+ ShortField("Data31", 0x0200),
+ ShortField("Data32", 0x0),
+ ShortField("Data33", 0xac14),
+ ShortField("Data34", 0x0064),
+ ShortField("Data35", 0x0),
+ ShortField("Data36", 0x0),
+ ShortField("Data37", 0x0),
+ ShortField("Data38", 0x0),
+ ShortField("Data39", 0x0d00),
+ ShortField("Data40", 0x0),
+ ShortField("Data41", 0xffff)]
+
+# SMB NetLogon Protocol Response Tail LM2.0
+class SMBNetlogon_Protocol_Response_Tail_LM20(Packet):
+ name = "SMB Netlogon Protocol Response Tail LM20"
+ fields_desc = [ByteEnumField("Command",0x06,{0x06:"LM 2.0 Response to logon request"}),
+ ByteField("unused", 0),
+ StrFixedLenField("DblSlash", "\\\\", 2),
+ StrNullField("ServerName","WIN"),
+ LEShortField("LM20Token", 0xffff)]
+
+# SMBNegociate Protocol Request Header
+class SMBNegociate_Protocol_Request_Header(Packet):
+ name="SMBNegociate Protocol Request Header"
+ fields_desc = [StrFixedLenField("Start","\xffSMB",4),
+ ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}),
+ ByteField("Error_Class",0),
+ ByteField("Reserved",0),
+ LEShortField("Error_code",0),
+ ByteField("Flags",0x18),
+ LEShortField("Flags2",0x0000),
+ LEShortField("PIDHigh",0x0000),
+ LELongField("Signature",0x0),
+ LEShortField("Unused",0x0),
+ LEShortField("TID",0),
+ LEShortField("PID",1),
+ LEShortField("UID",0),
+ LEShortField("MID",2),
+ ByteField("WordCount",0),
+ LEShortField("ByteCount",12)]
+
+# SMB Negociate Protocol Request Tail
+class SMBNegociate_Protocol_Request_Tail(Packet):
+ name="SMB Negociate Protocol Request Tail"
+ fields_desc=[ByteField("BufferFormat",0x02),
+ StrNullField("BufferData","NT LM 0.12")]
+
+# SMBNegociate Protocol Response Advanced Security
+class SMBNegociate_Protocol_Response_Advanced_Security(Packet):
+ name="SMBNegociate Protocol Response Advanced Security"
+ fields_desc = [StrFixedLenField("Start","\xffSMB",4),
+ ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}),
+ ByteField("Error_Class",0),
+ ByteField("Reserved",0),
+ LEShortField("Error_Code",0),
+ ByteField("Flags",0x98),
+ LEShortField("Flags2",0x0000),
+ LEShortField("PIDHigh",0x0000),
+ LELongField("Signature",0x0),
+ LEShortField("Unused",0x0),
+ LEShortField("TID",0),
+ LEShortField("PID",1),
+ LEShortField("UID",0),
+ LEShortField("MID",2),
+ ByteField("WordCount",17),
+ LEShortField("DialectIndex",7),
+ ByteField("SecurityMode",0x03),
+ LEShortField("MaxMpxCount",50),
+ LEShortField("MaxNumberVC",1),
+ LEIntField("MaxBufferSize",16144),
+ LEIntField("MaxRawSize",65536),
+ LEIntField("SessionKey",0x0000),
+ LEShortField("ServerCapabilities",0xf3f9),
+ BitField("UnixExtensions",0,1),
+ BitField("Reserved2",0,7),
+ BitField("ExtendedSecurity",1,1),
+ BitField("CompBulk",0,2),
+ BitField("Reserved3",0,5),
+# There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94.
+ LEIntField("ServerTimeHigh",0xD6228000),
+ LEIntField("ServerTimeLow",0x1C4EF94),
+ LEShortField("ServerTimeZone",0x3c),
+ ByteField("EncryptionKeyLength",0),
+ LEFieldLenField("ByteCount", None, "SecurityBlob", adjust=lambda pkt,x:x-16),
+ BitField("GUID",0,128),
+ StrLenField("SecurityBlob", "", length_from=lambda x:x.ByteCount+16)]
+
+# SMBNegociate Protocol Response No Security
+# When using no security, with EncryptionKeyLength=8, you must have an EncryptionKey before the DomainName
+class SMBNegociate_Protocol_Response_No_Security(Packet):
+ name="SMBNegociate Protocol Response No Security"
+ fields_desc = [StrFixedLenField("Start","\xffSMB",4),
+ ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}),
+ ByteField("Error_Class",0),
+ ByteField("Reserved",0),
+ LEShortField("Error_Code",0),
+ ByteField("Flags",0x98),
+ LEShortField("Flags2",0x0000),
+ LEShortField("PIDHigh",0x0000),
+ LELongField("Signature",0x0),
+ LEShortField("Unused",0x0),
+ LEShortField("TID",0),
+ LEShortField("PID",1),
+ LEShortField("UID",0),
+ LEShortField("MID",2),
+ ByteField("WordCount",17),
+ LEShortField("DialectIndex",7),
+ ByteField("SecurityMode",0x03),
+ LEShortField("MaxMpxCount",50),
+ LEShortField("MaxNumberVC",1),
+ LEIntField("MaxBufferSize",16144),
+ LEIntField("MaxRawSize",65536),
+ LEIntField("SessionKey",0x0000),
+ LEShortField("ServerCapabilities",0xf3f9),
+ BitField("UnixExtensions",0,1),
+ BitField("Reserved2",0,7),
+ BitField("ExtendedSecurity",0,1),
+ FlagsField("CompBulk",0,2,"CB"),
+ BitField("Reserved3",0,5),
+ # There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94.
+ LEIntField("ServerTimeHigh",0xD6228000),
+ LEIntField("ServerTimeLow",0x1C4EF94),
+ LEShortField("ServerTimeZone",0x3c),
+ ByteField("EncryptionKeyLength",8),
+ LEShortField("ByteCount",24),
+ BitField("EncryptionKey",0,64),
+ StrNullField("DomainName","WORKGROUP"),
+ StrNullField("ServerName","RMFF1")]
+
+# SMBNegociate Protocol Response No Security No Key
+class SMBNegociate_Protocol_Response_No_Security_No_Key(Packet):
+ namez="SMBNegociate Protocol Response No Security No Key"
+ fields_desc = [StrFixedLenField("Start","\xffSMB",4),
+ ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}),
+ ByteField("Error_Class",0),
+ ByteField("Reserved",0),
+ LEShortField("Error_Code",0),
+ ByteField("Flags",0x98),
+ LEShortField("Flags2",0x0000),
+ LEShortField("PIDHigh",0x0000),
+ LELongField("Signature",0x0),
+ LEShortField("Unused",0x0),
+ LEShortField("TID",0),
+ LEShortField("PID",1),
+ LEShortField("UID",0),
+ LEShortField("MID",2),
+ ByteField("WordCount",17),
+ LEShortField("DialectIndex",7),
+ ByteField("SecurityMode",0x03),
+ LEShortField("MaxMpxCount",50),
+ LEShortField("MaxNumberVC",1),
+ LEIntField("MaxBufferSize",16144),
+ LEIntField("MaxRawSize",65536),
+ LEIntField("SessionKey",0x0000),
+ LEShortField("ServerCapabilities",0xf3f9),
+ BitField("UnixExtensions",0,1),
+ BitField("Reserved2",0,7),
+ BitField("ExtendedSecurity",0,1),
+ FlagsField("CompBulk",0,2,"CB"),
+ BitField("Reserved3",0,5),
+ # There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94.
+ LEIntField("ServerTimeHigh",0xD6228000),
+ LEIntField("ServerTimeLow",0x1C4EF94),
+ LEShortField("ServerTimeZone",0x3c),
+ ByteField("EncryptionKeyLength",0),
+ LEShortField("ByteCount",16),
+ StrNullField("DomainName","WORKGROUP"),
+ StrNullField("ServerName","RMFF1")]
+
+# Session Setup AndX Request
+class SMBSession_Setup_AndX_Request(Packet):
+ name="Session Setup AndX Request"
+ fields_desc=[StrFixedLenField("Start","\xffSMB",4),
+ ByteEnumField("Command",0x73,{0x73:"SMB_COM_SESSION_SETUP_ANDX"}),
+ ByteField("Error_Class",0),
+ ByteField("Reserved",0),
+ LEShortField("Error_Code",0),
+ ByteField("Flags",0x18),
+ LEShortField("Flags2",0x0001),
+ LEShortField("PIDHigh",0x0000),
+ LELongField("Signature",0x0),
+ LEShortField("Unused",0x0),
+ LEShortField("TID",0),
+ LEShortField("PID",1),
+ LEShortField("UID",0),
+ LEShortField("MID",2),
+ ByteField("WordCount",13),
+ ByteEnumField("AndXCommand",0x75,{0x75:"SMB_COM_TREE_CONNECT_ANDX"}),
+ ByteField("Reserved2",0),
+ LEShortField("AndXOffset",96),
+ LEShortField("MaxBufferS",2920),
+ LEShortField("MaxMPXCount",50),
+ LEShortField("VCNumber",0),
+ LEIntField("SessionKey",0),
+ LEFieldLenField("ANSIPasswordLength",None,"ANSIPassword"),
+ LEShortField("UnicodePasswordLength",0),
+ LEIntField("Reserved3",0),
+ LEShortField("ServerCapabilities",0x05),
+ BitField("UnixExtensions",0,1),
+ BitField("Reserved4",0,7),
+ BitField("ExtendedSecurity",0,1),
+ BitField("CompBulk",0,2),
+ BitField("Reserved5",0,5),
+ LEShortField("ByteCount",35),
+ StrLenField("ANSIPassword", "Pass",length_from=lambda x:x.ANSIPasswordLength),
+ StrNullField("Account","GUEST"),
+ StrNullField("PrimaryDomain", ""),
+ StrNullField("NativeOS","Windows 4.0"),
+ StrNullField("NativeLanManager","Windows 4.0"),
+ ByteField("WordCount2",4),
+ ByteEnumField("AndXCommand2",0xFF,{0xFF:"SMB_COM_NONE"}),
+ ByteField("Reserved6",0),
+ LEShortField("AndXOffset2",0),
+ LEShortField("Flags3",0x2),
+ LEShortField("PasswordLength",0x1),
+ LEShortField("ByteCount2",18),
+ ByteField("Password",0),
+ StrNullField("Path","\\\\WIN2K\\IPC$"),
+ StrNullField("Service","IPC")]
+
+# Session Setup AndX Response
+class SMBSession_Setup_AndX_Response(Packet):
+ name="Session Setup AndX Response"
+ fields_desc=[StrFixedLenField("Start","\xffSMB",4),
+ ByteEnumField("Command",0x73,{0x73:"SMB_COM_SESSION_SETUP_ANDX"}),
+ ByteField("Error_Class",0),
+ ByteField("Reserved",0),
+ LEShortField("Error_Code",0),
+ ByteField("Flags",0x90),
+ LEShortField("Flags2",0x1001),
+ LEShortField("PIDHigh",0x0000),
+ LELongField("Signature",0x0),
+ LEShortField("Unused",0x0),
+ LEShortField("TID",0),
+ LEShortField("PID",1),
+ LEShortField("UID",0),
+ LEShortField("MID",2),
+ ByteField("WordCount",3),
+ ByteEnumField("AndXCommand",0x75,{0x75:"SMB_COM_TREE_CONNECT_ANDX"}),
+ ByteField("Reserved2",0),
+ LEShortField("AndXOffset",66),
+ LEShortField("Action",0),
+ LEShortField("ByteCount",25),
+ StrNullField("NativeOS","Windows 4.0"),
+ StrNullField("NativeLanManager","Windows 4.0"),
+ StrNullField("PrimaryDomain",""),
+ ByteField("WordCount2",3),
+ ByteEnumField("AndXCommand2",0xFF,{0xFF:"SMB_COM_NONE"}),
+ ByteField("Reserved3",0),
+ LEShortField("AndXOffset2",80),
+ LEShortField("OptionalSupport",0x01),
+ LEShortField("ByteCount2",5),
+ StrNullField("Service","IPC"),
+ StrNullField("NativeFileSystem","")]
+
+bind_layers( NBTSession, SMBNegociate_Protocol_Request_Header, )
+bind_layers( NBTSession, SMBNegociate_Protocol_Response_Advanced_Security, ExtendedSecurity=1)
+bind_layers( NBTSession, SMBNegociate_Protocol_Response_No_Security, ExtendedSecurity=0, EncryptionKeyLength=8)
+bind_layers( NBTSession, SMBNegociate_Protocol_Response_No_Security_No_Key, ExtendedSecurity=0, EncryptionKeyLength=0)
+bind_layers( NBTSession, SMBSession_Setup_AndX_Request, )
+bind_layers( NBTSession, SMBSession_Setup_AndX_Response, )
+bind_layers( SMBNegociate_Protocol_Request_Header, SMBNegociate_Protocol_Request_Tail, )
+bind_layers( SMBNegociate_Protocol_Request_Tail, SMBNegociate_Protocol_Request_Tail, )
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/snmp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/snmp.py
new file mode 100644
index 00000000..dddd4e27
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/snmp.py
@@ -0,0 +1,255 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+SNMP (Simple Network Management Protocol).
+"""
+
+from scapy.asn1packet import *
+from scapy.asn1fields import *
+from scapy.layers.inet import UDP
+
+##########
+## SNMP ##
+##########
+
+######[ ASN1 class ]######
+
+class ASN1_Class_SNMP(ASN1_Class_UNIVERSAL):
+ name="SNMP"
+ PDU_GET = 0xa0
+ PDU_NEXT = 0xa1
+ PDU_RESPONSE = 0xa2
+ PDU_SET = 0xa3
+ PDU_TRAPv1 = 0xa4
+ PDU_BULK = 0xa5
+ PDU_INFORM = 0xa6
+ PDU_TRAPv2 = 0xa7
+
+
+class ASN1_SNMP_PDU_GET(ASN1_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_GET
+
+class ASN1_SNMP_PDU_NEXT(ASN1_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_NEXT
+
+class ASN1_SNMP_PDU_RESPONSE(ASN1_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_RESPONSE
+
+class ASN1_SNMP_PDU_SET(ASN1_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_SET
+
+class ASN1_SNMP_PDU_TRAPv1(ASN1_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_TRAPv1
+
+class ASN1_SNMP_PDU_BULK(ASN1_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_BULK
+
+class ASN1_SNMP_PDU_INFORM(ASN1_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_INFORM
+
+class ASN1_SNMP_PDU_TRAPv2(ASN1_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_TRAPv2
+
+
+######[ BER codecs ]#######
+
+class BERcodec_SNMP_PDU_GET(BERcodec_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_GET
+
+class BERcodec_SNMP_PDU_NEXT(BERcodec_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_NEXT
+
+class BERcodec_SNMP_PDU_RESPONSE(BERcodec_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_RESPONSE
+
+class BERcodec_SNMP_PDU_SET(BERcodec_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_SET
+
+class BERcodec_SNMP_PDU_TRAPv1(BERcodec_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_TRAPv1
+
+class BERcodec_SNMP_PDU_BULK(BERcodec_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_BULK
+
+class BERcodec_SNMP_PDU_INFORM(BERcodec_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_INFORM
+
+class BERcodec_SNMP_PDU_TRAPv2(BERcodec_SEQUENCE):
+ tag = ASN1_Class_SNMP.PDU_TRAPv2
+
+
+
+######[ ASN1 fields ]######
+
+class ASN1F_SNMP_PDU_GET(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_SNMP.PDU_GET
+
+class ASN1F_SNMP_PDU_NEXT(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_SNMP.PDU_NEXT
+
+class ASN1F_SNMP_PDU_RESPONSE(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_SNMP.PDU_RESPONSE
+
+class ASN1F_SNMP_PDU_SET(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_SNMP.PDU_SET
+
+class ASN1F_SNMP_PDU_TRAPv1(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_SNMP.PDU_TRAPv1
+
+class ASN1F_SNMP_PDU_BULK(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_SNMP.PDU_BULK
+
+class ASN1F_SNMP_PDU_INFORM(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_SNMP.PDU_INFORM
+
+class ASN1F_SNMP_PDU_TRAPv2(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_SNMP.PDU_TRAPv2
+
+
+
+######[ SNMP Packet ]######
+
+SNMP_error = { 0: "no_error",
+ 1: "too_big",
+ 2: "no_such_name",
+ 3: "bad_value",
+ 4: "read_only",
+ 5: "generic_error",
+ 6: "no_access",
+ 7: "wrong_type",
+ 8: "wrong_length",
+ 9: "wrong_encoding",
+ 10: "wrong_value",
+ 11: "no_creation",
+ 12: "inconsistent_value",
+ 13: "ressource_unavailable",
+ 14: "commit_failed",
+ 15: "undo_failed",
+ 16: "authorization_error",
+ 17: "not_writable",
+ 18: "inconsistent_name",
+ }
+
+SNMP_trap_types = { 0: "cold_start",
+ 1: "warm_start",
+ 2: "link_down",
+ 3: "link_up",
+ 4: "auth_failure",
+ 5: "egp_neigh_loss",
+ 6: "enterprise_specific",
+ }
+
+class SNMPvarbind(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SEQUENCE( ASN1F_OID("oid","1.3"),
+ ASN1F_field("value",ASN1_NULL(0))
+ )
+
+
+class SNMPget(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SNMP_PDU_GET( ASN1F_INTEGER("id",0),
+ ASN1F_enum_INTEGER("error",0, SNMP_error),
+ ASN1F_INTEGER("error_index",0),
+ ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
+ )
+
+class SNMPnext(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SNMP_PDU_NEXT( ASN1F_INTEGER("id",0),
+ ASN1F_enum_INTEGER("error",0, SNMP_error),
+ ASN1F_INTEGER("error_index",0),
+ ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
+ )
+
+class SNMPresponse(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SNMP_PDU_RESPONSE( ASN1F_INTEGER("id",0),
+ ASN1F_enum_INTEGER("error",0, SNMP_error),
+ ASN1F_INTEGER("error_index",0),
+ ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
+ )
+
+class SNMPset(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SNMP_PDU_SET( ASN1F_INTEGER("id",0),
+ ASN1F_enum_INTEGER("error",0, SNMP_error),
+ ASN1F_INTEGER("error_index",0),
+ ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
+ )
+
+class SNMPtrapv1(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SNMP_PDU_TRAPv1( ASN1F_OID("enterprise", "1.3"),
+ ASN1F_IPADDRESS("agent_addr","0.0.0.0"),
+ ASN1F_enum_INTEGER("generic_trap", 0, SNMP_trap_types),
+ ASN1F_INTEGER("specific_trap", 0),
+ ASN1F_TIME_TICKS("time_stamp", IntAutoTime()),
+ ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
+ )
+
+class SNMPbulk(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SNMP_PDU_BULK( ASN1F_INTEGER("id",0),
+ ASN1F_INTEGER("non_repeaters",0),
+ ASN1F_INTEGER("max_repetitions",0),
+ ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
+ )
+
+class SNMPinform(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SNMP_PDU_INFORM( ASN1F_INTEGER("id",0),
+ ASN1F_enum_INTEGER("error",0, SNMP_error),
+ ASN1F_INTEGER("error_index",0),
+ ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
+ )
+
+class SNMPtrapv2(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SNMP_PDU_TRAPv2( ASN1F_INTEGER("id",0),
+ ASN1F_enum_INTEGER("error",0, SNMP_error),
+ ASN1F_INTEGER("error_index",0),
+ ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
+ )
+
+
+class SNMP(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SEQUENCE(
+ ASN1F_enum_INTEGER("version", 1, {0:"v1", 1:"v2c", 2:"v2", 3:"v3"}),
+ ASN1F_STRING("community",b"public"),
+ ASN1F_CHOICE("PDU", SNMPget(),
+ SNMPget, SNMPnext, SNMPresponse, SNMPset,
+ SNMPtrapv1, SNMPbulk, SNMPinform, SNMPtrapv2)
+ )
+ def answers(self, other):
+ return ( isinstance(self.PDU, SNMPresponse) and
+ ( isinstance(other.PDU, SNMPget) or
+ isinstance(other.PDU, SNMPnext) or
+ isinstance(other.PDU, SNMPset) ) and
+ self.PDU.id == other.PDU.id )
+
+bind_layers( UDP, SNMP, sport=161)
+bind_layers( UDP, SNMP, dport=161)
+bind_layers( UDP, SNMP, sport=162)
+bind_layers( UDP, SNMP, dport=162)
+
+def snmpwalk(dst, oid="1", community=b"public"):
+ try:
+ while 1:
+ r = sr1(IP(dst=dst)/UDP(sport=RandShort())/SNMP(community=community, PDU=SNMPnext(varbindlist=[SNMPvarbind(oid=oid)])),timeout=2, chainCC=1, verbose=0, retry=2)
+ if ICMP in r:
+ print(repr(r))
+ break
+ if r is None:
+ print("No answers")
+ break
+ print("%-40s: %r" % (r[SNMPvarbind].oid.val,r[SNMPvarbind].value))
+ oid = r[SNMPvarbind].oid
+
+ except KeyboardInterrupt:
+ pass
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/tftp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/tftp.py
new file mode 100644
index 00000000..1535e99c
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/tftp.py
@@ -0,0 +1,477 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+TFTP (Trivial File Transfer Protocol).
+"""
+
+import os,random
+from scapy.packet import *
+from scapy.fields import *
+from scapy.automaton import *
+from scapy.layers.inet import UDP
+
+
+
+TFTP_operations = { 1:"RRQ",2:"WRQ",3:"DATA",4:"ACK",5:"ERROR",6:"OACK" }
+
+
+class TFTP(Packet):
+ name = "TFTP opcode"
+ fields_desc = [ ShortEnumField("op", 1, TFTP_operations), ]
+
+
+
+class TFTP_RRQ(Packet):
+ name = "TFTP Read Request"
+ fields_desc = [ StrNullField("filename", ""),
+ StrNullField("mode", "octet") ]
+ def answers(self, other):
+ return 0
+ def mysummary(self):
+ return self.sprintf("RRQ %filename%"),[UDP]
+
+
+class TFTP_WRQ(Packet):
+ name = "TFTP Write Request"
+ fields_desc = [ StrNullField("filename", ""),
+ StrNullField("mode", "octet") ]
+ def answers(self, other):
+ return 0
+ def mysummary(self):
+ return self.sprintf("WRQ %filename%"),[UDP]
+
+class TFTP_DATA(Packet):
+ name = "TFTP Data"
+ fields_desc = [ ShortField("block", 0) ]
+ def answers(self, other):
+ return self.block == 1 and isinstance(other, TFTP_RRQ)
+ def mysummary(self):
+ return self.sprintf("DATA %block%"),[UDP]
+
+class TFTP_Option(Packet):
+ fields_desc = [ StrNullField("oname",""),
+ StrNullField("value","") ]
+ def extract_padding(self, pkt):
+ return "",pkt
+
+class TFTP_Options(Packet):
+ fields_desc = [ PacketListField("options", [], TFTP_Option, length_from=lambda x:None) ]
+
+
+class TFTP_ACK(Packet):
+ name = "TFTP Ack"
+ fields_desc = [ ShortField("block", 0) ]
+ def answers(self, other):
+ if isinstance(other, TFTP_DATA):
+ return self.block == other.block
+ elif isinstance(other, TFTP_RRQ) or isinstance(other, TFTP_WRQ) or isinstance(other, TFTP_OACK):
+ return self.block == 0
+ return 0
+ def mysummary(self):
+ return self.sprintf("ACK %block%"),[UDP]
+
+TFTP_Error_Codes = { 0: "Not defined",
+ 1: "File not found",
+ 2: "Access violation",
+ 3: "Disk full or allocation exceeded",
+ 4: "Illegal TFTP operation",
+ 5: "Unknown transfer ID",
+ 6: "File already exists",
+ 7: "No such user",
+ 8: "Terminate transfer due to option negotiation",
+ }
+
+class TFTP_ERROR(Packet):
+ name = "TFTP Error"
+ fields_desc = [ ShortEnumField("errorcode", 0, TFTP_Error_Codes),
+ StrNullField("errormsg", "")]
+ def answers(self, other):
+ return (isinstance(other, TFTP_DATA) or
+ isinstance(other, TFTP_RRQ) or
+ isinstance(other, TFTP_WRQ) or
+ isinstance(other, TFTP_ACK))
+ def mysummary(self):
+ return self.sprintf("ERROR %errorcode%: %errormsg%"),[UDP]
+
+
+class TFTP_OACK(Packet):
+ name = "TFTP Option Ack"
+ fields_desc = [ ]
+ def answers(self, other):
+ return isinstance(other, TFTP_WRQ) or isinstance(other, TFTP_RRQ)
+
+
+bind_layers(UDP, TFTP, dport=69)
+bind_layers(TFTP, TFTP_RRQ, op=1)
+bind_layers(TFTP, TFTP_WRQ, op=2)
+bind_layers(TFTP, TFTP_DATA, op=3)
+bind_layers(TFTP, TFTP_ACK, op=4)
+bind_layers(TFTP, TFTP_ERROR, op=5)
+bind_layers(TFTP, TFTP_OACK, op=6)
+bind_layers(TFTP_RRQ, TFTP_Options)
+bind_layers(TFTP_WRQ, TFTP_Options)
+bind_layers(TFTP_OACK, TFTP_Options)
+
+
+class TFTP_read(Automaton):
+ def parse_args(self, filename, server, sport = None, port=69, **kargs):
+ Automaton.parse_args(self, **kargs)
+ self.filename = filename
+ self.server = server
+ self.port = port
+ self.sport = sport
+
+
+ def master_filter(self, pkt):
+ return ( IP in pkt and pkt[IP].src == self.server and UDP in pkt
+ and pkt[UDP].dport == self.my_tid
+ and (self.server_tid is None or pkt[UDP].sport == self.server_tid) )
+
+ # BEGIN
+ @ATMT.state(initial=1)
+ def BEGIN(self):
+ self.blocksize=512
+ self.my_tid = self.sport or RandShort()._fix()
+ bind_bottom_up(UDP, TFTP, dport=self.my_tid)
+ self.server_tid = None
+ self.res = ""
+
+ self.l3 = IP(dst=self.server)/UDP(sport=self.my_tid, dport=self.port)/TFTP()
+ self.last_packet = self.l3/TFTP_RRQ(filename=self.filename, mode="octet")
+ self.send(self.last_packet)
+ self.awaiting=1
+
+ raise self.WAITING()
+
+ # WAITING
+ @ATMT.state()
+ def WAITING(self):
+ pass
+
+
+ @ATMT.receive_condition(WAITING)
+ def receive_data(self, pkt):
+ if TFTP_DATA in pkt and pkt[TFTP_DATA].block == self.awaiting:
+ if self.server_tid is None:
+ self.server_tid = pkt[UDP].sport
+ self.l3[UDP].dport = self.server_tid
+ raise self.RECEIVING(pkt)
+
+ @ATMT.receive_condition(WAITING, prio=1)
+ def receive_error(self, pkt):
+ if TFTP_ERROR in pkt:
+ raise self.ERROR(pkt)
+
+
+ @ATMT.timeout(WAITING, 3)
+ def timeout_waiting(self):
+ raise self.WAITING()
+ @ATMT.action(timeout_waiting)
+ def retransmit_last_packet(self):
+ self.send(self.last_packet)
+
+ @ATMT.action(receive_data)
+# @ATMT.action(receive_error)
+ def send_ack(self):
+ self.last_packet = self.l3 / TFTP_ACK(block = self.awaiting)
+ self.send(self.last_packet)
+
+
+ # RECEIVED
+ @ATMT.state()
+ def RECEIVING(self, pkt):
+ if conf.raw_layer in pkt:
+ recvd = pkt[conf.raw_layer].load
+ else:
+ recvd = ""
+ self.res += recvd
+ self.awaiting += 1
+ if len(recvd) == self.blocksize:
+ raise self.WAITING()
+ raise self.END()
+
+ # ERROR
+ @ATMT.state(error=1)
+ def ERROR(self,pkt):
+ split_bottom_up(UDP, TFTP, dport=self.my_tid)
+ return pkt[TFTP_ERROR].summary()
+
+ #END
+ @ATMT.state(final=1)
+ def END(self):
+ split_bottom_up(UDP, TFTP, dport=self.my_tid)
+ return self.res
+
+
+
+
+class TFTP_write(Automaton):
+ def parse_args(self, filename, data, server, sport=None, port=69,**kargs):
+ Automaton.parse_args(self, **kargs)
+ self.filename = filename
+ self.server = server
+ self.port = port
+ self.sport = sport
+ self.blocksize = 512
+ self.origdata = data
+
+ def master_filter(self, pkt):
+ return ( IP in pkt and pkt[IP].src == self.server and UDP in pkt
+ and pkt[UDP].dport == self.my_tid
+ and (self.server_tid is None or pkt[UDP].sport == self.server_tid) )
+
+
+ # BEGIN
+ @ATMT.state(initial=1)
+ def BEGIN(self):
+ self.data = [ self.origdata[i*self.blocksize:(i+1)*self.blocksize]
+ for i in range( len(self.origdata)/self.blocksize+1) ]
+ self.my_tid = self.sport or RandShort()._fix()
+ bind_bottom_up(UDP, TFTP, dport=self.my_tid)
+ self.server_tid = None
+
+ self.l3 = IP(dst=self.server)/UDP(sport=self.my_tid, dport=self.port)/TFTP()
+ self.last_packet = self.l3/TFTP_WRQ(filename=self.filename, mode="octet")
+ self.send(self.last_packet)
+ self.res = ""
+ self.awaiting=0
+
+ raise self.WAITING_ACK()
+
+ # WAITING_ACK
+ @ATMT.state()
+ def WAITING_ACK(self):
+ pass
+
+ @ATMT.receive_condition(WAITING_ACK)
+ def received_ack(self,pkt):
+ if TFTP_ACK in pkt and pkt[TFTP_ACK].block == self.awaiting:
+ if self.server_tid is None:
+ self.server_tid = pkt[UDP].sport
+ self.l3[UDP].dport = self.server_tid
+ raise self.SEND_DATA()
+
+ @ATMT.receive_condition(WAITING_ACK)
+ def received_error(self, pkt):
+ if TFTP_ERROR in pkt:
+ raise self.ERROR(pkt)
+
+ @ATMT.timeout(WAITING_ACK, 3)
+ def timeout_waiting(self):
+ raise self.WAITING_ACK()
+ @ATMT.action(timeout_waiting)
+ def retransmit_last_packet(self):
+ self.send(self.last_packet)
+
+ # SEND_DATA
+ @ATMT.state()
+ def SEND_DATA(self):
+ self.awaiting += 1
+ self.last_packet = self.l3/TFTP_DATA(block=self.awaiting)/self.data.pop(0)
+ self.send(self.last_packet)
+ if self.data:
+ raise self.WAITING_ACK()
+ raise self.END()
+
+
+ # ERROR
+ @ATMT.state(error=1)
+ def ERROR(self,pkt):
+ split_bottom_up(UDP, TFTP, dport=self.my_tid)
+ return pkt[TFTP_ERROR].summary()
+
+ # END
+ @ATMT.state(final=1)
+ def END(self):
+ split_bottom_up(UDP, TFTP, dport=self.my_tid)
+
+
+class TFTP_WRQ_server(Automaton):
+
+ def parse_args(self, ip=None, sport=None, *args, **kargs):
+ Automaton.parse_args(self, *args, **kargs)
+ self.ip = ip
+ self.sport = sport
+
+ def master_filter(self, pkt):
+ return TFTP in pkt and (not self.ip or pkt[IP].dst == self.ip)
+
+ @ATMT.state(initial=1)
+ def BEGIN(self):
+ self.blksize=512
+ self.blk=1
+ self.filedata=""
+ self.my_tid = self.sport or random.randint(10000,65500)
+ bind_bottom_up(UDP, TFTP, dport=self.my_tid)
+
+ @ATMT.receive_condition(BEGIN)
+ def receive_WRQ(self,pkt):
+ if TFTP_WRQ in pkt:
+ raise self.WAIT_DATA().action_parameters(pkt)
+
+ @ATMT.action(receive_WRQ)
+ def ack_WRQ(self, pkt):
+ ip = pkt[IP]
+ self.ip = ip.dst
+ self.dst = ip.src
+ self.filename = pkt[TFTP_WRQ].filename
+ options = pkt[TFTP_Options]
+ self.l3 = IP(src=ip.dst, dst=ip.src)/UDP(sport=self.my_tid, dport=pkt.sport)/TFTP()
+ if options is None:
+ self.last_packet = self.l3/TFTP_ACK(block=0)
+ self.send(self.last_packet)
+ else:
+ opt = [x for x in options.options if x.oname.upper() == "BLKSIZE"]
+ if opt:
+ self.blksize = int(opt[0].value)
+ self.debug(2,"Negotiated new blksize at %i" % self.blksize)
+ self.last_packet = self.l3/TFTP_OACK()/TFTP_Options(options=opt)
+ self.send(self.last_packet)
+
+ @ATMT.state()
+ def WAIT_DATA(self):
+ pass
+
+ @ATMT.timeout(WAIT_DATA, 1)
+ def resend_ack(self):
+ self.send(self.last_packet)
+ raise self.WAIT_DATA()
+
+ @ATMT.receive_condition(WAIT_DATA)
+ def receive_data(self, pkt):
+ if TFTP_DATA in pkt:
+ data = pkt[TFTP_DATA]
+ if data.block == self.blk:
+ raise self.DATA(data)
+
+ @ATMT.action(receive_data)
+ def ack_data(self):
+ self.last_packet = self.l3/TFTP_ACK(block = self.blk)
+ self.send(self.last_packet)
+
+ @ATMT.state()
+ def DATA(self, data):
+ self.filedata += data.load
+ if len(data.load) < self.blksize:
+ raise self.END()
+ self.blk += 1
+ raise self.WAIT_DATA()
+
+ @ATMT.state(final=1)
+ def END(self):
+ return self.filename,self.filedata
+ split_bottom_up(UDP, TFTP, dport=self.my_tid)
+
+
+class TFTP_RRQ_server(Automaton):
+ def parse_args(self, store=None, joker=None, dir=None, ip=None, sport=None, serve_one=False, **kargs):
+ Automaton.parse_args(self,**kargs)
+ if store is None:
+ store = {}
+ if dir is not None:
+ self.dir = os.path.join(os.path.abspath(dir),"")
+ else:
+ self.dir = None
+ self.store = store
+ self.joker = joker
+ self.ip = ip
+ self.sport = sport
+ self.serve_one = serve_one
+ self.my_tid = self.sport or random.randint(10000,65500)
+ bind_bottom_up(UDP, TFTP, dport=self.my_tid)
+
+ def master_filter(self, pkt):
+ return TFTP in pkt and (not self.ip or pkt[IP].dst == self.ip)
+
+ @ATMT.state(initial=1)
+ def WAIT_RRQ(self):
+ self.blksize=512
+ self.blk=0
+
+ @ATMT.receive_condition(WAIT_RRQ)
+ def receive_rrq(self, pkt):
+ if TFTP_RRQ in pkt:
+ raise self.RECEIVED_RRQ(pkt)
+
+
+ @ATMT.state()
+ def RECEIVED_RRQ(self, pkt):
+ ip = pkt[IP]
+ options = pkt[TFTP_Options]
+ self.l3 = IP(src=ip.dst, dst=ip.src)/UDP(sport=self.my_tid, dport=ip.sport)/TFTP()
+ self.filename = pkt[TFTP_RRQ].filename
+ self.blk=1
+ self.data = None
+ if self.filename in self.store:
+ self.data = self.store[self.filename]
+ elif self.dir is not None:
+ fn = os.path.abspath(os.path.join(self.dir, self.filename))
+ if fn.startswith(self.dir): # Check we're still in the server's directory
+ try:
+ self.data=open(fn).read()
+ except IOError:
+ pass
+ if self.data is None:
+ self.data = self.joker
+
+ if options:
+ opt = [x for x in options.options if x.oname.upper() == "BLKSIZE"]
+ if opt:
+ self.blksize = int(opt[0].value)
+ self.debug(2,"Negotiated new blksize at %i" % self.blksize)
+ self.last_packet = self.l3/TFTP_OACK()/TFTP_Options(options=opt)
+ self.send(self.last_packet)
+
+
+
+
+ @ATMT.condition(RECEIVED_RRQ)
+ def file_in_store(self):
+ if self.data is not None:
+ self.blknb = len(self.data)/self.blksize+1
+ raise self.SEND_FILE()
+
+ @ATMT.condition(RECEIVED_RRQ)
+ def file_not_found(self):
+ if self.data is None:
+ raise self.WAIT_RRQ()
+ @ATMT.action(file_not_found)
+ def send_error(self):
+ self.send(self.l3/TFTP_ERROR(errorcode=1, errormsg=TFTP_Error_Codes[1]))
+
+ @ATMT.state()
+ def SEND_FILE(self):
+ self.send(self.l3/TFTP_DATA(block=self.blk)/self.data[(self.blk-1)*self.blksize:self.blk*self.blksize])
+
+ @ATMT.timeout(SEND_FILE, 3)
+ def timeout_waiting_ack(self):
+ raise self.SEND_FILE()
+
+ @ATMT.receive_condition(SEND_FILE)
+ def received_ack(self, pkt):
+ if TFTP_ACK in pkt and pkt[TFTP_ACK].block == self.blk:
+ raise self.RECEIVED_ACK()
+ @ATMT.state()
+ def RECEIVED_ACK(self):
+ self.blk += 1
+
+ @ATMT.condition(RECEIVED_ACK)
+ def no_more_data(self):
+ if self.blk > self.blknb:
+ if self.serve_one:
+ raise self.END()
+ raise self.WAIT_RRQ()
+ @ATMT.condition(RECEIVED_ACK, prio=2)
+ def data_remaining(self):
+ raise self.SEND_FILE()
+
+ @ATMT.state(final=1)
+ def END(self):
+ split_bottom_up(UDP, TFTP, dport=self.my_tid)
+
+
+
+
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/vrrp.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/vrrp.py
new file mode 100644
index 00000000..e2818381
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/vrrp.py
@@ -0,0 +1,39 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## Copyright (C) 6WIND <olivier.matz@6wind.com>
+## This program is published under a GPLv2 license
+
+"""
+VRRP (Virtual Router Redundancy Protocol).
+"""
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.inet import IP
+
+IPPROTO_VRRP=112
+
+# RFC 3768 - Virtual Router Redundancy Protocol (VRRP)
+class VRRP(Packet):
+ fields_desc = [
+ BitField("version" , 2, 4),
+ BitField("type" , 1, 4),
+ ByteField("vrid", 1),
+ ByteField("priority", 100),
+ FieldLenField("ipcount", None, count_of="addrlist", fmt="B"),
+ ByteField("authtype", 0),
+ ByteField("adv", 1),
+ XShortField("chksum", None),
+ FieldListField("addrlist", [], IPField("", "0.0.0.0"),
+ count_from = lambda pkt: pkt.ipcount),
+ IntField("auth1", 0),
+ IntField("auth2", 0) ]
+
+ def post_build(self, p, pay):
+ if self.chksum is None:
+ ck = checksum(p)
+ p = p[:6]+bytes([(ck>>8),(ck&0xff)])+p[8:]
+ return p
+
+bind_layers( IP, VRRP, proto=IPPROTO_VRRP)
diff --git a/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/x509.py b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/x509.py
new file mode 100644
index 00000000..18aaa5e3
--- /dev/null
+++ b/scripts/external_libs/scapy-2.3.1/python3/scapy/layers/x509.py
@@ -0,0 +1,108 @@
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+"""
+X.509 certificates.
+"""
+
+from scapy.asn1packet import *
+from scapy.asn1fields import *
+
+##########
+## X509 ##
+##########
+
+######[ ASN1 class ]######
+
+class ASN1_Class_X509(ASN1_Class_UNIVERSAL):
+ name="X509"
+ CONT0 = 0xa0
+ CONT1 = 0xa1
+ CONT2 = 0xa2
+ CONT3 = 0xa3
+
+class ASN1_X509_CONT0(ASN1_SEQUENCE):
+ tag = ASN1_Class_X509.CONT0
+
+class ASN1_X509_CONT1(ASN1_SEQUENCE):
+ tag = ASN1_Class_X509.CONT1
+
+class ASN1_X509_CONT2(ASN1_SEQUENCE):
+ tag = ASN1_Class_X509.CONT2
+
+class ASN1_X509_CONT3(ASN1_SEQUENCE):
+ tag = ASN1_Class_X509.CONT3
+
+######[ BER codecs ]#######
+
+class BERcodec_X509_CONT0(BERcodec_SEQUENCE):
+ tag = ASN1_Class_X509.CONT0
+
+class BERcodec_X509_CONT1(BERcodec_SEQUENCE):
+ tag = ASN1_Class_X509.CONT1
+
+class BERcodec_X509_CONT2(BERcodec_SEQUENCE):
+ tag = ASN1_Class_X509.CONT2
+
+class BERcodec_X509_CONT3(BERcodec_SEQUENCE):
+ tag = ASN1_Class_X509.CONT3
+
+######[ ASN1 fields ]######
+
+class ASN1F_X509_CONT0(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_X509.CONT0
+
+class ASN1F_X509_CONT1(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_X509.CONT1
+
+class ASN1F_X509_CONT2(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_X509.CONT2
+
+class ASN1F_X509_CONT3(ASN1F_SEQUENCE):
+ ASN1_tag = ASN1_Class_X509.CONT3
+
+######[ X509 packets ]######
+
+class X509RDN(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SET(
+ ASN1F_SEQUENCE( ASN1F_OID("oid","2.5.4.6"),
+ ASN1F_PRINTABLE_STRING("value","")
+ )
+ )
+
+class X509v3Ext(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_field("val",ASN1_NULL(0))
+
+
+class X509Cert(ASN1_Packet):
+ ASN1_codec = ASN1_Codecs.BER
+ ASN1_root = ASN1F_SEQUENCE(
+ ASN1F_SEQUENCE(
+ ASN1F_optionnal(ASN1F_X509_CONT0(ASN1F_INTEGER("version",3))),
+ ASN1F_INTEGER("sn",1),
+ ASN1F_SEQUENCE(ASN1F_OID("sign_algo","1.2.840.113549.1.1.5"),
+ ASN1F_field("sa_value",ASN1_NULL(0))),
+ ASN1F_SEQUENCE_OF("issuer",[],X509RDN),
+ ASN1F_SEQUENCE(ASN1F_UTC_TIME("not_before",ZuluTime(-600)), # ten minutes ago
+ ASN1F_UTC_TIME("not_after",ZuluTime(+86400))), # for 24h
+ ASN1F_SEQUENCE_OF("subject",[],X509RDN),
+ ASN1F_SEQUENCE(
+ ASN1F_SEQUENCE(ASN1F_OID("pubkey_algo","1.2.840.113549.1.1.1"),
+ ASN1F_field("pk_value",ASN1_NULL(0))),
+ ASN1F_BIT_STRING("pubkey","")
+ ),
+ ASN1F_optionnal(ASN1F_X509_CONT3(ASN1F_SEQUENCE_OF("x509v3ext",[],X509v3Ext))),
+
+ ),
+ ASN1F_SEQUENCE(ASN1F_OID("sign_algo2","1.2.840.113549.1.1.5"),
+ ASN1F_field("sa2_value",ASN1_NULL(0))),
+ ASN1F_BIT_STRING("signature","")
+ )
+
+
+
+