|
15 | 15 | # along with Scapy. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 |
|
17 | 17 | ## Copyright (C) 2009 Adline Stephane <adline.stephane@gmail.com> |
18 | | -## |
| 18 | +## Copyright 2018 Gabriel Potter <gabriel@potter.fr> |
19 | 19 |
|
20 | 20 | # Partial support of RFC3971 |
21 | | -# scapy.contrib.description = SEND (ICMPv6) |
| 21 | +# scapy.contrib.description = Secure Neighbor Discovery (SEND) (ICMPv6) |
22 | 22 | # scapy.contrib.status = loads |
23 | 23 |
|
24 | 24 | from __future__ import absolute_import |
25 | 25 | import socket |
26 | 26 |
|
27 | 27 | from scapy.packet import * |
28 | 28 | from scapy.fields import * |
29 | | -from scapy.layers.inet6 import icmp6typescls, _ICMPv6NDGuessPayload, Net6 |
30 | | - |
31 | | -send_icmp6typescls = { 11: "ICMPv6NDOptCGA", |
32 | | - 12: "ICMPv6NDOptRsaSig", |
33 | | - 13: "ICMPv6NDOptTmstp", |
34 | | - 14: "ICMPv6NDOptNonce" |
35 | | - } |
36 | | -icmp6typescls.update(send_icmp6typescls) |
37 | | - |
38 | | -class HashField(Field): |
39 | | - def __init__(self, name, default): |
40 | | - Field.__init__(self, name, default, "16s") |
41 | | - def h2i(self, pkt, x): |
42 | | - if isinstance(x, str): |
43 | | - try: |
44 | | - x = in6_ptop(x) |
45 | | - except socket.error: |
46 | | - x = Net6(x) |
47 | | - elif isinstance(x, list): |
48 | | - x = [Net6(e) for e in x] |
49 | | - return x |
50 | | - def i2m(self, pkt, x): |
51 | | - return inet_pton(socket.AF_INET6, x) |
52 | | - def m2i(self, pkt, x): |
53 | | - return inet_ntop(socket.AF_INET6, x) |
54 | | - def any2i(self, pkt, x): |
55 | | - return self.h2i(pkt,x) |
56 | | - def i2repr(self, pkt, x): |
57 | | - return self.i2h(pkt, x) # No specific information to return |
| 29 | +from scapy.layers.x509 import X509_SubjectPublicKeyInfo |
| 30 | +from scapy.layers.inet6 import icmp6ndoptscls, _ICMPv6NDGuessPayload |
58 | 31 |
|
59 | 32 | class ICMPv6NDOptNonce(_ICMPv6NDGuessPayload, Packet): |
60 | 33 | name = "ICMPv6NDOptNonce" |
61 | 34 | fields_desc = [ ByteField("type",14), |
62 | | - FieldLenField("len",None,length_of="data",fmt="B", adjust = lambda pkt,x: (x)/8), |
63 | | - StrLenField("nonce","", length_from = lambda pkt: pkt.len*8-2) ] |
| 35 | + FieldLenField("len", None, length_of="nonce", fmt="B", adjust = lambda pkt,x: int(round((x+2)/8.))), |
| 36 | + StrLenField("nonce", "", length_from = lambda pkt: pkt.len*8-2) ] |
64 | 37 |
|
65 | 38 | class ICMPv6NDOptTmstp(_ICMPv6NDGuessPayload, Packet): |
66 | 39 | name = "ICMPv6NDOptTmstp" |
67 | 40 | fields_desc = [ ByteField("type",13), |
68 | | - ByteField("len",2), |
| 41 | + ByteField("len", 2), |
69 | 42 | BitField("reserved",0, 48), |
70 | | - LongField("timestamp", None) ] |
| 43 | + UTCTimeField("timestamp", None) ] |
71 | 44 |
|
72 | 45 | class ICMPv6NDOptRsaSig(_ICMPv6NDGuessPayload, Packet): |
73 | 46 | name = "ICMPv6NDOptRsaSig" |
74 | 47 | fields_desc = [ ByteField("type",12), |
75 | | - FieldLenField("len",None,length_of="data",fmt="B", adjust = lambda pkt,x: (x)/8), |
| 48 | + FieldLenField("len", None, length_of="signature_pad", fmt="B", adjust = lambda pkt,x: (x+20)//8), |
76 | 49 | ShortField("reserved",0), |
77 | | - HashField("key_hash",None), |
| 50 | + StrFixedLenField("key_hash", "", length=16), |
78 | 51 | StrLenField("signature_pad", "", length_from = lambda pkt: pkt.len*8-20) ] |
79 | 52 |
|
| 53 | +class CGA_Params(Packet): |
| 54 | + name = "CGA Parameters data structure" |
| 55 | + fields_desc = [ StrFixedLenField("modifier", RandBin(size=16), length=16), |
| 56 | + StrFixedLenField("subprefix", "", length=8), |
| 57 | + ByteField("cc", 0), |
| 58 | + PacketField("pubkey", X509_SubjectPublicKeyInfo(), |
| 59 | + X509_SubjectPublicKeyInfo) ] |
| 60 | + |
80 | 61 | class ICMPv6NDOptCGA(_ICMPv6NDGuessPayload, Packet): |
81 | 62 | name = "ICMPv6NDOptCGA" |
82 | 63 | fields_desc = [ ByteField("type",11), |
83 | | - FieldLenField("len",None,length_of="data",fmt="B", adjust = lambda pkt,x: (x)/8), |
84 | | - ByteField("padlength",0), |
| 64 | + FieldLenField("len", None, length_of="CGA_PARAMS", fmt="B", adjust = lambda pkt,x: (x+pkt.padlength+4)//8), |
| 65 | + FieldLenField("padlength", 0, length_of="padding", fmt="B"), |
85 | 66 | ByteField("reserved",0), |
86 | | - StrLenField("CGA_PARAMS", "", length_from = lambda pkt: pkt.len*8 - pkt.padlength - 4), |
87 | | - StrLenField("padding", None, length_from = lambda pkt: pkt.padlength) ] |
| 67 | + PacketLenField("CGA_PARAMS", "", CGA_Params, length_from = lambda pkt: pkt.len*8 - pkt.padlength - 4), |
| 68 | + StrLenField("padding", "", length_from = lambda pkt: pkt.padlength) ] |
| 69 | + |
| 70 | + def post_build(self, p, pay): |
| 71 | + l_ = len(self.CGA_PARAMS) |
| 72 | + l = -(4+l_) % 8 # Pad to 8 bytes |
| 73 | + p = p[:1] + chb((4+l_+l)//8) + chb(l) + p[3:4+l_] + b"\x00" * l + pay |
| 74 | + return p |
88 | 75 |
|
89 | | -if __name__ == "__main__": |
90 | | - from scapy.all import * |
91 | | - interact(mydict=globals(), mybanner="SEND add-on") |
| 76 | +send_icmp6ndoptscls = { 11: ICMPv6NDOptCGA, |
| 77 | + 12: ICMPv6NDOptRsaSig, |
| 78 | + 13: ICMPv6NDOptTmstp, |
| 79 | + 14: ICMPv6NDOptNonce |
| 80 | + } |
| 81 | +icmp6ndoptscls.update(send_icmp6ndoptscls) |
0 commit comments