• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# SPDX-License-Identifier: GPL-2.0-or-later
2# This file is part of Scapy
3# See https://scapy.net/ for more information
4# Copyright (C) 2009 Adline Stephane <adline.stephane@gmail.com>
5# Copyright     2018 Gabriel Potter <gabriel[]potter[]fr>
6
7"""
8Secure Neighbor Discovery (SEND) - RFC3971
9"""
10
11# scapy.contrib.description = Secure Neighbor Discovery (SEND) (ICMPv6)
12# scapy.contrib.status = loads
13
14
15from scapy.packet import Packet
16from scapy.fields import BitField, ByteField, FieldLenField, PacketField, \
17    PacketLenField, ShortField, StrFixedLenField, StrLenField, UTCTimeField
18from scapy.layers.x509 import X509_SubjectPublicKeyInfo
19from scapy.layers.inet6 import icmp6ndoptscls, _ICMPv6NDGuessPayload
20from scapy.compat import chb
21from scapy.volatile import RandBin
22
23
24class ICMPv6NDOptNonce(_ICMPv6NDGuessPayload, Packet):
25    name = "ICMPv6NDOptNonce"
26    fields_desc = [ByteField("type", 14),
27                   FieldLenField("len", None, length_of="nonce", fmt="B", adjust=lambda pkt, x: int(round((x + 2) / 8.))),  # noqa: E501
28                   StrLenField("nonce", "", length_from=lambda pkt: pkt.len * 8 - 2)]  # noqa: E501
29
30
31class ICMPv6NDOptTmstp(_ICMPv6NDGuessPayload, Packet):
32    name = "ICMPv6NDOptTmstp"
33    fields_desc = [ByteField("type", 13),
34                   ByteField("len", 2),
35                   BitField("reserved", 0, 48),
36                   UTCTimeField("timestamp", None)]
37
38
39class ICMPv6NDOptRsaSig(_ICMPv6NDGuessPayload, Packet):
40    name = "ICMPv6NDOptRsaSig"
41    fields_desc = [ByteField("type", 12),
42                   FieldLenField("len", None, length_of="signature_pad", fmt="B", adjust=lambda pkt, x: (x + 20) // 8),  # noqa: E501
43                   ShortField("reserved", 0),
44                   StrFixedLenField("key_hash", "", length=16),
45                   StrLenField("signature_pad", "", length_from=lambda pkt: pkt.len * 8 - 20)]  # noqa: E501
46
47
48class CGA_Params(Packet):
49    name = "CGA Parameters data structure"
50    fields_desc = [StrFixedLenField("modifier", RandBin(size=16), length=16),
51                   StrFixedLenField("subprefix", "", length=8),
52                   ByteField("cc", 0),
53                   PacketField("pubkey", X509_SubjectPublicKeyInfo(),
54                               X509_SubjectPublicKeyInfo)]
55
56
57class ICMPv6NDOptCGA(_ICMPv6NDGuessPayload, Packet):
58    name = "ICMPv6NDOptCGA"
59    fields_desc = [ByteField("type", 11),
60                   FieldLenField("len", None, length_of="CGA_PARAMS", fmt="B", adjust=lambda pkt, x: (x + pkt.padlength + 4) // 8),  # noqa: E501
61                   FieldLenField("padlength", 0, length_of="padding", fmt="B"),
62                   ByteField("reserved", 0),
63                   PacketLenField("CGA_PARAMS", "", CGA_Params, length_from=lambda pkt: pkt.len * 8 - pkt.padlength - 4),  # noqa: E501
64                   StrLenField("padding", "", length_from=lambda pkt: pkt.padlength)]  # noqa: E501
65
66    def post_build(self, p, pay):
67        l_ = len(self.CGA_PARAMS)
68        tmp_len = -(4 + l_) % 8  # Pad to 8 bytes
69        p = p[:1] + chb((4 + l_ + tmp_len) // 8) + chb(tmp_len) + p[3:4 + l_]
70        p += b"\x00" * tmp_len + pay
71        return p
72
73
74send_icmp6ndoptscls = {11: ICMPv6NDOptCGA,
75                       12: ICMPv6NDOptRsaSig,
76                       13: ICMPv6NDOptTmstp,
77                       14: ICMPv6NDOptNonce
78                       }
79icmp6ndoptscls.update(send_icmp6ndoptscls)
80