|
2 | 2 | # This file is part of Scapy |
3 | 3 | # See https://scapy.net/ for more information |
4 | 4 |
|
5 | | -# scapy.contrib.description = ICMP Extensions |
6 | | -# scapy.contrib.status = loads |
7 | | - |
8 | | -import struct |
9 | | - |
10 | | -import scapy |
11 | | -from scapy.compat import chb |
12 | | -from scapy.packet import Packet, bind_layers |
13 | | -from scapy.fields import BitField, ByteField, ConditionalField, \ |
14 | | - FieldLenField, IPField, IntField, PacketListField, ShortField, \ |
15 | | - StrLenField |
16 | | -from scapy.layers.inet import IP, ICMP, checksum |
17 | | -from scapy.layers.inet6 import IP6Field |
18 | | -from scapy.error import warning |
19 | | -from scapy.contrib.mpls import MPLS |
20 | | -from scapy.config import conf |
21 | | - |
22 | | - |
23 | | -class ICMPExtensionObject(Packet): |
24 | | - name = 'ICMP Extension Object' |
25 | | - fields_desc = [ShortField('len', None), |
26 | | - ByteField('classnum', 0), |
27 | | - ByteField('classtype', 0)] |
28 | | - |
29 | | - def post_build(self, p, pay): |
30 | | - if self.len is None: |
31 | | - tmp_len = len(p) + len(pay) |
32 | | - p = struct.pack('!H', tmp_len) + p[2:] |
33 | | - return p + pay |
34 | | - |
35 | | - |
36 | | -class ICMPExtensionHeader(Packet): |
37 | | - name = 'ICMP Extension Header (RFC4884)' |
38 | | - fields_desc = [BitField('version', 2, 4), |
39 | | - BitField('reserved', 0, 12), |
40 | | - BitField('chksum', None, 16)] |
41 | | - |
42 | | - _min_ieo_len = len(ICMPExtensionObject()) |
43 | | - |
44 | | - def post_build(self, p, pay): |
45 | | - if self.chksum is None: |
46 | | - ck = checksum(p) |
47 | | - p = p[:2] + chb(ck >> 8) + chb(ck & 0xff) + p[4:] |
48 | | - return p + pay |
49 | | - |
50 | | - def guess_payload_class(self, payload): |
51 | | - if len(payload) < self._min_ieo_len: |
52 | | - return Packet.guess_payload_class(self, payload) |
53 | | - |
54 | | - # Look at fields of the generic ICMPExtensionObject to determine which |
55 | | - # bound extension type to use. |
56 | | - ieo = ICMPExtensionObject(payload) |
57 | | - if ieo.len < self._min_ieo_len: |
58 | | - return Packet.guess_payload_class(self, payload) |
59 | | - |
60 | | - for fval, cls in self.payload_guess: |
61 | | - if all(hasattr(ieo, k) and v == ieo.getfieldval(k) |
62 | | - for k, v in fval.items()): |
63 | | - return cls |
64 | | - return ICMPExtensionObject |
65 | | - |
66 | | - |
67 | | -def ICMPExtension_post_dissection(self, pkt): |
68 | | - # RFC4884 section 5.2 says if the ICMP packet length |
69 | | - # is >144 then ICMP extensions start at byte 137. |
70 | | - |
71 | | - lastlayer = pkt.lastlayer() |
72 | | - if not isinstance(lastlayer, conf.padding_layer): |
73 | | - return |
74 | | - |
75 | | - if IP in pkt: |
76 | | - if (ICMP in pkt and |
77 | | - pkt[ICMP].type in [3, 11, 12] and |
78 | | - pkt.len > 144): |
79 | | - bytes = pkt[ICMP].build()[136:] |
80 | | - else: |
81 | | - return |
82 | | - elif scapy.layers.inet6.IPv6 in pkt: |
83 | | - if ((scapy.layers.inet6.ICMPv6TimeExceeded in pkt or |
84 | | - scapy.layers.inet6.ICMPv6DestUnreach in pkt) and |
85 | | - pkt.plen > 144): |
86 | | - bytes = pkt[scapy.layers.inet6.ICMPv6TimeExceeded].build()[136:] |
87 | | - else: |
88 | | - return |
89 | | - else: |
90 | | - return |
91 | | - |
92 | | - # validate checksum |
93 | | - ieh = ICMPExtensionHeader(bytes) |
94 | | - if checksum(ieh.build()): |
95 | | - return # failed |
96 | | - |
97 | | - lastlayer.load = lastlayer.load[:-len(ieh)] |
98 | | - lastlayer.add_payload(ieh) |
99 | | - |
100 | | - |
101 | | -class ICMPExtensionMPLS(ICMPExtensionObject): |
102 | | - name = 'ICMP Extension Object - MPLS (RFC4950)' |
103 | | - |
104 | | - fields_desc = [ShortField('len', None), |
105 | | - ByteField('classnum', 1), |
106 | | - ByteField('classtype', 1), |
107 | | - PacketListField('stack', [], MPLS, |
108 | | - length_from=lambda pkt: pkt.len - 4)] |
109 | | - |
110 | | - |
111 | | -class ICMPExtensionInterfaceInformation(ICMPExtensionObject): |
112 | | - name = 'ICMP Extension Object - Interface Information Object (RFC5837)' |
113 | | - |
114 | | - fields_desc = [ShortField('len', None), |
115 | | - ByteField('classnum', 2), |
116 | | - BitField('interface_role', 0, 2), |
117 | | - BitField('reserved', 0, 2), |
118 | | - BitField('has_ifindex', 0, 1), |
119 | | - BitField('has_ipaddr', 0, 1), |
120 | | - BitField('has_ifname', 0, 1), |
121 | | - BitField('has_mtu', 0, 1), |
122 | | - |
123 | | - ConditionalField( |
124 | | - IntField('ifindex', None), |
125 | | - lambda pkt: pkt.has_ifindex == 1), |
126 | | - |
127 | | - ConditionalField( |
128 | | - ShortField('afi', None), |
129 | | - lambda pkt: pkt.has_ipaddr == 1), |
130 | | - ConditionalField( |
131 | | - ShortField('reserved2', 0), |
132 | | - lambda pkt: pkt.has_ipaddr == 1), |
133 | | - ConditionalField( |
134 | | - IPField('ip4', None), |
135 | | - lambda pkt: pkt.afi == 1), |
136 | | - ConditionalField( |
137 | | - IP6Field('ip6', None), |
138 | | - lambda pkt: pkt.afi == 2), |
139 | | - |
140 | | - ConditionalField( |
141 | | - FieldLenField('ifname_len', None, fmt='B', |
142 | | - length_of='ifname'), |
143 | | - lambda pkt: pkt.has_ifname == 1), |
144 | | - ConditionalField( |
145 | | - StrLenField('ifname', None, |
146 | | - length_from=lambda pkt: pkt.ifname_len), |
147 | | - lambda pkt: pkt.has_ifname == 1), |
148 | | - |
149 | | - ConditionalField( |
150 | | - IntField('mtu', None), |
151 | | - lambda pkt: pkt.has_mtu == 1)] |
152 | | - |
153 | | - def self_build(self, **kwargs): |
154 | | - if self.afi is None: |
155 | | - if self.ip4 is not None: |
156 | | - self.afi = 1 |
157 | | - elif self.ip6 is not None: |
158 | | - self.afi = 2 |
159 | | - |
160 | | - if self.has_ifindex and self.ifindex is None: |
161 | | - warning('has_ifindex set but ifindex is not set.') |
162 | | - if self.has_ipaddr and self.afi is None: |
163 | | - warning('has_ipaddr set but afi is not set.') |
164 | | - if self.has_ipaddr and self.ip4 is None and self.ip6 is None: |
165 | | - warning('has_ipaddr set but ip4 or ip6 is not set.') |
166 | | - if self.has_ifname and self.ifname is None: |
167 | | - warning('has_ifname set but ifname is not set.') |
168 | | - if self.has_mtu and self.mtu is None: |
169 | | - warning('has_mtu set but mtu is not set.') |
170 | | - |
171 | | - return ICMPExtensionObject.self_build(self, **kwargs) |
172 | | - |
173 | | - |
174 | | -# Add the post_dissection() method to the existing ICMPv4 and |
175 | | -# ICMPv6 error messages |
176 | | -scapy.layers.inet.ICMPerror.post_dissection = ICMPExtension_post_dissection |
177 | | -scapy.layers.inet.TCPerror.post_dissection = ICMPExtension_post_dissection |
178 | | -scapy.layers.inet.UDPerror.post_dissection = ICMPExtension_post_dissection |
179 | | - |
180 | | -scapy.layers.inet6.ICMPv6DestUnreach.post_dissection = ICMPExtension_post_dissection # noqa: E501 |
181 | | -scapy.layers.inet6.ICMPv6TimeExceeded.post_dissection = ICMPExtension_post_dissection # noqa: E501 |
182 | | - |
183 | | - |
184 | | -# ICMPExtensionHeader looks at fields from the upper layer object when |
185 | | -# determining which upper layer to use. |
186 | | -bind_layers(ICMPExtensionHeader, ICMPExtensionMPLS, classnum=1, classtype=1) |
187 | | -bind_layers(ICMPExtensionHeader, ICMPExtensionInterfaceInformation, classnum=2) |
| 5 | +# scapy.contrib.description = ICMP Extensions (deprecated) |
| 6 | +# scapy.contrib.status = deprecated |
| 7 | + |
| 8 | +__all__ = [ |
| 9 | + "ICMPExtensionObject", |
| 10 | + "ICMPExtensionHeader", |
| 11 | + "ICMPExtensionInterfaceInformation", |
| 12 | + "ICMPExtensionMPLS", |
| 13 | +] |
| 14 | + |
| 15 | +import warnings |
| 16 | + |
| 17 | +from scapy.layers.inet import ( |
| 18 | + ICMPExtension_Object as ICMPExtensionObject, |
| 19 | + ICMPExtension_Header as ICMPExtensionHeader, |
| 20 | + ICMPExtension_InterfaceInformation as ICMPExtensionInterfaceInformation, |
| 21 | +) |
| 22 | +from scapy.contrib.mpls import ( |
| 23 | + ICMPExtension_MPLS as ICMPExtensionMPLS, |
| 24 | +) |
| 25 | + |
| 26 | +warnings.warn( |
| 27 | + "scapy.contrib.icmp_extensions is deprecated. Behavior has changed ! " |
| 28 | + "Use scapy.layers.inet", |
| 29 | + DeprecationWarning |
| 30 | +) |
0 commit comments