|
12 | 12 |
|
13 | 13 | from scapy.packet import Packet, bind_layers, Raw
|
14 | 14 | from scapy.fields import ByteEnumField, ByteField, XByteField, \
|
15 |
| - ShortField, XShortField, XLongField, BitField, XBitField, FCSField |
| 15 | + ShortField, XIntField, XShortField, XLongField, BitField, \ |
| 16 | + XBitField, FCSField |
16 | 17 | from scapy.layers.inet import IP, UDP
|
17 | 18 | from scapy.layers.l2 import Ether
|
18 | 19 | from scapy.compat import raw
|
19 | 20 | from scapy.error import warning
|
20 | 21 | from zlib import crc32
|
21 | 22 | import struct
|
22 |
| -from scapy.compat import Tuple |
| 23 | +from scapy.compat import ( |
| 24 | + Optional, |
| 25 | + Tuple, |
| 26 | + Type, |
| 27 | +) |
23 | 28 |
|
24 | 29 | _transports = {
|
25 | 30 | 'RC': 0x00,
|
|
28 | 33 | 'UD': 0x60,
|
29 | 34 | }
|
30 | 35 |
|
| 36 | +OP_MASK = 0x1f |
| 37 | +TRANSPORT_MASK = 0xe0 |
| 38 | + |
| 39 | + |
| 40 | +def transport(opcode): |
| 41 | + # type: (int) -> int |
| 42 | + return opcode & TRANSPORT_MASK |
| 43 | + |
| 44 | + |
| 45 | +def op(opcode): |
| 46 | + # type: (int) -> int |
| 47 | + return opcode & OP_MASK |
| 48 | + |
| 49 | + |
31 | 50 | _ops = {
|
32 | 51 | 'SEND_FIRST': 0x00,
|
33 | 52 | 'SEND_MIDDLE': 0x01,
|
|
54 | 73 |
|
55 | 74 |
|
56 | 75 | CNP_OPCODE = 0x81
|
| 76 | +UD_SEND_ONLY = _transports['UD'] | _ops['SEND_ONLY'] |
| 77 | +UD_SEND_ONLY_IMM = _transports['UD'] | _ops['SEND_ONLY_WITH_IMMEDIATE'] |
57 | 78 |
|
58 | 79 |
|
59 | 80 | def opcode(transport, op):
|
@@ -129,7 +150,7 @@ def opcode(transport, op):
|
129 | 150 | class BTH(Packet):
|
130 | 151 | name = "BTH"
|
131 | 152 | fields_desc = [
|
132 |
| - ByteEnumField("opcode", 0, _bth_opcodes), |
| 153 | + ByteEnumField("opcode", None, _bth_opcodes), |
133 | 154 | BitField("solicited", 0, 1),
|
134 | 155 | BitField("migreq", 0, 1),
|
135 | 156 | BitField("padcount", 0, 2),
|
@@ -188,10 +209,34 @@ def compute_icrc(self, p):
|
188 | 209 | def post_build(self, p, pay):
|
189 | 210 | # type: (bytes, bytes) -> bytes
|
190 | 211 | p += pay
|
| 212 | + if self.opcode is None: |
| 213 | + opcode = self.guess_opcode() or 0 |
| 214 | + p = struct.pack('B', opcode) + p[1:] |
191 | 215 | if self.icrc is None:
|
192 | 216 | p = p[:-4] + self.compute_icrc(p)
|
193 | 217 | return p
|
194 | 218 |
|
| 219 | + def guess_opcode(self): |
| 220 | + # type: () -> Optional[int] |
| 221 | + 'Guess the opcode based on the following layers.' |
| 222 | + if isinstance(self.payload, DETH): |
| 223 | + if isinstance(self.payload.payload, ImmDt): |
| 224 | + return UD_SEND_ONLY_IMM |
| 225 | + return UD_SEND_ONLY |
| 226 | + |
| 227 | + def guess_payload_class(self, payload): |
| 228 | + # type: (bytes) -> Type[Packet] |
| 229 | + opcode = self.opcode |
| 230 | + if transport(opcode) == _transports['RC'] or \ |
| 231 | + transport(opcode) == _transports['UC']: |
| 232 | + cur_op = op(opcode) |
| 233 | + if cur_op in (_ops['SEND_LAST_WITH_IMMEDIATE'], |
| 234 | + _ops['SEND_ONLY_WITH_IMMEDIATE']): |
| 235 | + return ImmDt |
| 236 | + if transport(self.opcode) == _transports['UD']: |
| 237 | + return DETH |
| 238 | + return Packet.guess_payload_class(self, payload) |
| 239 | + |
195 | 240 |
|
196 | 241 | class CNPPadding(Packet):
|
197 | 242 | name = "CNPPadding"
|
@@ -228,6 +273,30 @@ class AETH(Packet):
|
228 | 273 | ]
|
229 | 274 |
|
230 | 275 |
|
| 276 | +class DETH(Packet): |
| 277 | + name = "Datagram Extended Transport Header" |
| 278 | + fields_desc = [ |
| 279 | + XIntField("qkey", 0), |
| 280 | + XByteField("reserved", 0), |
| 281 | + XBitField("sqp", 0, 24) |
| 282 | + ] |
| 283 | + |
| 284 | + def guess_payload_class(self, payload): |
| 285 | + # type: (bytes) -> Type[Packet] |
| 286 | + bth = self.underlayer |
| 287 | + if isinstance(bth, BTH): |
| 288 | + if bth.opcode == opcode('UD', 'SEND_ONLY_WITH_IMMEDIATE')[0]: |
| 289 | + return ImmDt |
| 290 | + return Packet.guess_payload_class(self, payload) |
| 291 | + |
| 292 | + |
| 293 | +class ImmDt(Packet): |
| 294 | + name = "Immediate Data Extended Transport Header" |
| 295 | + fields_desc = [ |
| 296 | + XIntField("imm", 0) |
| 297 | + ] |
| 298 | + |
| 299 | + |
231 | 300 | bind_layers(BTH, CNPPadding, opcode=CNP_OPCODE)
|
232 | 301 |
|
233 | 302 | bind_layers(Ether, GRH, type=0x8915)
|
|
0 commit comments