1#!/usr/bin/env python3 2# 3# Copyright (c) 2019, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29import datetime 30import sys 31import time 32from typing import Any, Union 33 34from pyshark.packet.fields import LayerFieldsContainer, LayerField 35from pyshark.packet.packet import Packet as RawPacket 36 37from pktverify.addrs import EthAddr, ExtAddr, Ipv6Addr 38from pktverify.bytes import Bytes 39from pktverify.consts import VALID_LAYER_NAMES 40from pktverify.null_field import nullField 41 42 43def _auto(v: Union[LayerFieldsContainer, LayerField]): 44 """parse the layer field automatically according to its format""" 45 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 or v.get_default_value() is not None, v.fields 46 dv = v.get_default_value() 47 rv = v.raw_value 48 49 if dv.startswith('0x'): 50 return int(dv, 16) 51 52 try: 53 if dv == rv: 54 return int(dv) 55 elif int(dv) == int(rv, 16): 56 return int(dv) 57 except (ValueError, TypeError): 58 pass 59 60 if rv is None: 61 try: 62 return int(dv) 63 except (ValueError, TypeError): 64 pass 65 66 if ':' in dv and '::' not in dv and dv.replace(':', '') == rv: # '88:00', '8800' 67 return int(rv, 16) 68 69 # timestamp: 'Jan 1, 1970 08:00:00.000000000 CST', '0000000000000000' 70 # convert to seconds from 1970, ignore the nanosecond for now since 71 # there are integer seconds applied in the test cases 72 try: 73 time_str = datetime.datetime.strptime(dv, "%b %d, %Y %H:%M:%S.%f000 %Z") 74 time_in_sec = time.mktime(time_str.utctimetuple()) 75 return int(time_in_sec) 76 except (ValueError, TypeError): 77 pass 78 79 try: 80 int(rv, 16) 81 return int(dv) 82 except Exception: 83 pass 84 85 raise ValueError((v, v.get_default_value(), v.raw_value)) 86 87 88def _payload(v: Union[LayerFieldsContainer, LayerField]) -> bytearray: 89 """parse the layer field as a bytearray""" 90 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 91 hex_value = v.raw_value 92 assert len(hex_value) % 2 == 0 93 s = bytearray() 94 for i in range(0, len(hex_value), 2): 95 s.append(int(hex_value[i:i + 2], 16)) 96 97 return s 98 99 100def _hex(v: Union[LayerFieldsContainer, LayerField]) -> int: 101 """parse the layer field as a hex string""" 102 # split v into octets and reverse the order 103 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 104 return int(v.get_default_value(), 16) 105 106 107def _raw_hex(v: Union[LayerFieldsContainer, LayerField]) -> int: 108 """parse the layer field as a raw hex string""" 109 # split v into octets and reverse the order 110 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 111 iv = v.hex_value 112 113 try: 114 int(v.get_default_value()) 115 assert int(v.get_default_value()) == iv, (v.get_default_value(), v.raw_value) 116 except ValueError: 117 pass 118 119 try: 120 int(v.get_default_value(), 16) 121 assert int(v.get_default_value(), 16) == iv, (v.get_default_value(), v.raw_value) 122 except ValueError: 123 pass 124 125 return iv 126 127 128def _raw_hex_rev(v: Union[LayerFieldsContainer, LayerField]) -> int: 129 """parse the layer field as a reversed raw hex string""" 130 # split v into octets and reverse the order 131 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 132 rv = v.raw_value 133 octets = [rv[i:i + 2] for i in range(0, len(rv), 2)] 134 135 iv = int(''.join(reversed(octets)), 16) 136 137 try: 138 int(v.get_default_value()) 139 assert int(v.get_default_value()) == iv, (v.get_default_value(), v.raw_value) 140 except ValueError: 141 pass 142 143 try: 144 int(v.get_default_value(), 16) 145 assert int(v.get_default_value(), 16) == iv, (v.get_default_value(), v.raw_value) 146 except ValueError: 147 pass 148 149 return iv 150 151 152def _dec(v: Union[LayerFieldsContainer, LayerField]) -> int: 153 """parse the layer field as a decimal""" 154 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 155 return int(v.get_default_value()) 156 157 158def _float(v: Union[LayerFieldsContainer, LayerField]) -> float: 159 """parse the layer field as a float""" 160 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 161 return float(v.get_default_value()) 162 163 164def _str(v: Union[LayerFieldsContainer, LayerField]) -> str: 165 """parse the layer field as a string""" 166 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 167 return str(v.get_default_value()) 168 169 170def _bytes(v: Union[LayerFieldsContainer, LayerField]) -> Bytes: 171 """parse the layer field as raw bytes""" 172 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 173 return Bytes(v.raw_value) 174 175 176def _ext_addr(v: Union[LayerFieldsContainer, LayerField]) -> ExtAddr: 177 """parse the layer field as an extended address""" 178 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 179 return ExtAddr(v.get_default_value()) 180 181 182def _ipv6_addr(v: Union[LayerFieldsContainer, LayerField]) -> Ipv6Addr: 183 """parse the layer field as an IPv6 address""" 184 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 185 return Ipv6Addr(v.get_default_value()) 186 187 188def _eth_addr(v: Union[LayerFieldsContainer, LayerField]) -> EthAddr: 189 """parse the layer field as an Ethernet MAC address""" 190 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1, v.fields 191 return EthAddr(v.get_default_value()) 192 193 194def _routerid_set(v: Union[LayerFieldsContainer, LayerField]) -> set: 195 """parse the layer field as a set of router ids 196 197 Notes: the router ID mask in wireshark is a 198 hexadecimal string separated by ':' 199 """ 200 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 201 202 try: 203 ridmask = str(v.get_default_value()) 204 assert isinstance(ridmask, str), ridmask 205 ridmask_int = int(ridmask.replace(':', ''), base=16) 206 rid_set = set() 207 count = 0 208 while ridmask_int: 209 count += 1 210 if ridmask_int & 1: 211 rid_set.add(64 - count) 212 ridmask_int = ridmask_int >> 1 213 except ValueError: 214 pass 215 216 return rid_set 217 218 219class _first(object): 220 """parse the first layer field""" 221 222 def __init__(self, sub_parse): 223 self._sub_parse = sub_parse 224 225 def __call__(self, v: Union[LayerFieldsContainer, LayerField]): 226 return self._sub_parse(v.fields[0]) 227 228 229class _list(object): 230 """parse all layer fields into a list""" 231 232 def __init__(self, sub_parse): 233 self._sub_parse = sub_parse 234 235 def __call__(self, v: Union[LayerFieldsContainer, LayerField]): 236 return [self._sub_parse(f) for f in v.fields] 237 238 239_LAYER_FIELDS = { 240 # WPAN 241 'wpan.fcf': _raw_hex_rev, 242 'wpan.cmd': _auto, 243 'wpan.security': _auto, 244 'wpan.frame_type': _auto, 245 'wpan.pending': _auto, 246 'wpan.ack_request': _auto, 247 'wpan.pan_id_compression': _auto, 248 'wpan.seqno_suppression': _auto, 249 'wpan.ie_present': _auto, 250 'wpan.dst_addr_mode': _auto, 251 'wpan.version': _auto, 252 'wpan.src_addr_mode': _auto, 253 'wpan.dst_pan': _auto, 254 'wpan.seq_no': _auto, 255 'wpan.src16': _auto, 256 'wpan.dst16': _auto, 257 'wpan.src64': _ext_addr, 258 'wpan.dst64': _ext_addr, 259 'wpan.fcs': _raw_hex_rev, 260 'wpan.fcs_ok': _auto, 261 'wpan.frame_length': _dec, 262 'wpan.key_number': _auto, 263 'wpan.aux_sec.sec_suite': _auto, 264 'wpan.aux_sec.security_control_field': _auto, 265 'wpan.aux_sec.sec_level': _auto, 266 'wpan.aux_sec.key_id_mode': _auto, 267 'wpan.aux_sec.frame_counter_suppression': _auto, 268 'wpan.aux_sec.asn_in_nonce': _auto, 269 'wpan.aux_sec.reserved': _auto, 270 'wpan.aux_sec.frame_counter': _auto, 271 'wpan.aux_sec.key_source': _auto, 272 'wpan.aux_sec.key_index': _auto, 273 'wpan.aux_sec.hdr': _str, 274 'wpan.mic': _auto, 275 'wpan.channel': _auto, 276 'wpan.header_ie.id': _list(_auto), 277 'wpan.header_ie.csl.period': _auto, 278 'wpan.payload_ie.vendor.oui': _auto, 279 280 # MLE 281 'mle.cmd': _auto, 282 'mle.sec_suite': _hex, 283 'mle.tlv.type': _list(_dec), 284 'mle.tlv.len': _list(_dec), 285 'mle.tlv.mode.receiver_on_idle': _auto, 286 'mle.tlv.mode.reserved1': _auto, 287 'mle.tlv.mode.reserved2': _auto, 288 'mle.tlv.mode.device_type_bit': _auto, 289 'mle.tlv.mode.network_data': _auto, 290 'mle.tlv.challenge': _bytes, 291 'mle.tlv.scan_mask.r': _auto, 292 'mle.tlv.scan_mask.e': _auto, 293 'mle.tlv.version': _auto, 294 'mle.tlv.source_addr': _auto, 295 'mle.tlv.active_tstamp': _auto, 296 'mle.tlv.pending_tstamp': _auto, 297 'mle.tlv.leader_data.partition_id': _auto, 298 'mle.tlv.leader_data.weighting': _auto, 299 'mle.tlv.leader_data.data_version': _auto, 300 'mle.tlv.leader_data.stable_data_version': _auto, 301 'mle.tlv.leader_data.router_id': _auto, 302 'mle.tlv.route64.nbr_out': _list(_auto), 303 'mle.tlv.route64.nbr_in': _list(_auto), 304 'mle.tlv.route64.id_seq': _auto, 305 'mle.tlv.route64.id_mask': _routerid_set, 306 'mle.tlv.route64.cost': _list(_auto), 307 'mle.tlv.response': _bytes, 308 'mle.tlv.mle_frm_cntr': _auto, 309 'mle.tlv.ll_frm_cntr': _auto, 310 'mle.tlv.link_margin': _auto, 311 'mle.tlv.conn.sed_dgram_cnt': _auto, 312 'mle.tlv.conn.sed_buf_size': _auto, 313 'mle.tlv.conn.lq3': _auto, 314 'mle.tlv.conn.lq2': _auto, 315 'mle.tlv.conn.lq1': _auto, 316 'mle.tlv.conn.leader_cost': _auto, 317 'mle.tlv.conn.id_seq': _auto, 318 'mle.tlv.conn.flags.pp': _auto, 319 'mle.tlv.conn.active_rtrs': _auto, 320 'mle.tlv.timeout': _auto, 321 'mle.tlv.addr16': _auto, 322 'mle.tlv.channel': _auto, 323 'mle.tlv.addr_reg_iid': _list(_auto), 324 'mle.tlv.link_enh_ack_flags': _auto, 325 'mle.tlv.link_forward_series': _list(_auto), 326 'mle.tlv.link_requested_type_id_flags': _list(_hex), 327 'mle.tlv.link_sub_tlv': _list(_auto), 328 'mle.tlv.link_status_sub_tlv': _auto, 329 'mle.tlv.query_id': _auto, 330 'mle.tlv.metric_type_id_flags.type': _list(_hex), 331 'mle.tlv.metric_type_id_flags.metric': _list(_hex), 332 'mle.tlv.metric_type_id_flags.l': _list(_hex), 333 'mle.tlv.link_requested_type_id_flags': _bytes, 334 335 # IP 336 'ip.version': _auto, 337 'ip.src': _str, 338 'ip.src_host': _str, 339 'ip.dst': _str, 340 'ip.dst_host': _str, 341 'ip.ttl': _auto, 342 'ip.proto': _auto, 343 'ip.len': _auto, 344 'ip.id': _auto, 345 'ip.host': _list(_str), 346 'ip.hdr_len': _dec, 347 'ip.frag_offset': _auto, 348 'ip.flags.rb': _auto, 349 'ip.flags.mf': _auto, 350 'ip.flags.df': _auto, 351 'ip.dsfield.ecn': _auto, 352 'ip.dsfield.dscp': _auto, 353 'ip.checksum.status': _auto, 354 'ip.addr': _list(_str), 355 'ip.options.routeralert': _bytes, 356 'ip.opt.type.number': _auto, 357 'ip.opt.type.copy': _auto, 358 'ip.opt.type.class': _auto, 359 'ip.opt.ra': _auto, 360 'ip.opt.len': _auto, 361 # UDP 362 'udp.stream': _auto, 363 'udp.srcport': _auto, 364 'udp.dstport': _auto, 365 'udp.length': _auto, 366 'udp.port': _list(_dec), 367 'udp.checksum.status': _auto, 368 369 # IPv6 370 'ipv6.version': _auto, 371 'ipv6.src': _ipv6_addr, 372 'ipv6.src_host': _ipv6_addr, 373 'ipv6.dst': _ipv6_addr, 374 'ipv6.dst_host': _ipv6_addr, 375 'ipv6.addr': _list(_ipv6_addr), 376 'ipv6.tclass.dscp': _auto, 377 'ipv6.tclass.ecn': _auto, 378 'ipv6.flow': _auto, 379 'ipv6.hlim': _auto, 380 'ipv6.nxt': _auto, 381 'ipv6.hopopts.len': _auto, 382 'ipv6.hopopts.nxt': _auto, 383 'ipv6.hopopts.len_oct': _dec, 384 'ipv6.host': _list(_ipv6_addr), 385 'ipv6.plen': _auto, 386 'ipv6.opt.type.rest': _list(_auto), 387 'ipv6.opt.type.change': _list(_auto), 388 'ipv6.opt.type.action': _list(_auto), 389 'ipv6.opt.router_alert': _auto, 390 'ipv6.opt.padn': _str, 391 'ipv6.opt.length': _list(_auto), 392 'ipv6.opt.mpl.seed_id': _bytes, 393 'ipv6.opt.mpl.sequence': _auto, 394 'ipv6.opt.mpl.flag.v': _auto, 395 'ipv6.opt.mpl.flag.s': _auto, 396 'ipv6.opt.mpl.flag.rsv': _auto, 397 'ipv6.opt.mpl.flag.m': _auto, 398 399 # Eth 400 'eth.src': _eth_addr, 401 'eth.src_resolved': _eth_addr, 402 'eth.dst': _eth_addr, 403 'eth.dst_resolved': _eth_addr, 404 'eth.type': _auto, 405 'eth.addr': _list(_eth_addr), 406 'eth.addr_resolved': _list(_eth_addr), 407 'eth.ig': _list(_auto), 408 'eth.lg': _list(_auto), 409 # 6LOWPAN 410 '6lowpan.src': _ipv6_addr, 411 '6lowpan.dst': _ipv6_addr, 412 '6lowpan.udp.src': _auto, 413 '6lowpan.udp.dst': _auto, 414 '6lowpan.udp.checksum': _auto, 415 '6lowpan.frag.offset': _auto, 416 '6lowpan.frag.tag': _auto, 417 '6lowpan.frag.size': _auto, 418 '6lowpan.pattern': _list(_auto), 419 '6lowpan.hops': _auto, 420 '6lowpan.padding': _auto, 421 '6lowpan.next': _auto, 422 '6lowpan.flow': _auto, 423 '6lowpan.ecn': _auto, 424 '6lowpan.iphc.tf': _auto, 425 '6lowpan.iphc.m': _auto, 426 '6lowpan.iphc.nh': _auto, 427 '6lowpan.iphc.hlim': _auto, 428 '6lowpan.iphc.cid': _auto, 429 '6lowpan.iphc.sac': _auto, 430 '6lowpan.iphc.sam': _auto, 431 '6lowpan.iphc.dac': _auto, 432 '6lowpan.iphc.dam': _auto, 433 '6lowpan.iphc.sci': _auto, 434 '6lowpan.iphc.dci': _auto, 435 '6lowpan.iphc.sctx.prefix': _ipv6_addr, 436 '6lowpan.iphc.dctx.prefix': _ipv6_addr, 437 '6lowpan.mesh.v': _auto, 438 '6lowpan.nhc.pattern': _list(_auto), 439 '6lowpan.nhc.udp.checksum': _auto, 440 '6lowpan.nhc.udp.ports': _auto, 441 '6lowpan.nhc.ext.nh': _auto, 442 '6lowpan.nhc.ext.length': _auto, 443 '6lowpan.nhc.ext.eid': _auto, 444 '6lowpan.reassembled.length': _auto, 445 '6lowpan.fragments': _str, 446 '6lowpan.fragment.count': _auto, 447 '6lowpan.mesh.orig16': _auto, 448 '6lowpan.mesh.hops8': _auto, 449 '6lowpan.mesh.hops': _auto, 450 '6lowpan.mesh.f': _auto, 451 '6lowpan.mesh.dest16': _auto, 452 453 # ICMPv6 454 'icmpv6.type': _first(_auto), 455 'icmpv6.code': _first(_auto), 456 'icmpv6.checksum': _first(_auto), 457 'icmpv6.reserved': _raw_hex, 458 'icmpv6.resptime': _float, 459 'icmpv6.resp_to': _auto, 460 'icmpv6.mldr.nb_mcast_records': _auto, 461 'icmpv6.nd.ra.cur_hop_limit': _auto, 462 'icmpv6.nd.ns.target_address': _ipv6_addr, 463 'icmpv6.nd.na.target_address': _ipv6_addr, 464 'icmpv6.nd.na.flag.s': _auto, 465 'icmpv6.nd.na.flag.o': _auto, 466 'icmpv6.nd.na.flag.r': _auto, 467 'icmpv6.nd.na.flag.rsv': _auto, 468 'icmpv6.mldr.mar.record_type': _list(_auto), 469 'icmpv6.mldr.mar.aux_data_len': _list(_auto), 470 'icmpv6.mldr.mar.nb_sources': _list(_auto), 471 'icmpv6.mldr.mar.multicast_address': _list(_ipv6_addr), 472 'icmpv6.opt.type': _list(_auto), 473 'icmpv6.opt.nonce': _bytes, 474 'icmpv6.opt.linkaddr': _eth_addr, 475 'icmpv6.opt.src_linkaddr': _eth_addr, 476 'icmpv6.opt.target_linkaddr': _eth_addr, 477 'icmpv6.opt.route_lifetime': _auto, 478 'icmpv6.opt.route_info.flag.route_preference': _auto, 479 'icmpv6.opt.route_info.flag.reserved': _auto, 480 'icmpv6.opt.prefix': _list(_ipv6_addr), 481 'icmpv6.opt.length': _list(_auto), 482 'icmpv6.opt.reserved': _str, 483 'icmpv6.nd.ra.router_lifetime': _auto, 484 'icmpv6.nd.ra.retrans_timer': _auto, 485 'icmpv6.nd.ra.reachable_time': _auto, 486 'icmpv6.nd.ra.flag.rsv': _auto, 487 'icmpv6.nd.ra.flag.prf': _auto, 488 'icmpv6.nd.ra.flag.p': _auto, 489 'icmpv6.nd.ra.flag.o': _auto, 490 'icmpv6.nd.ra.flag.m': _auto, 491 'icmpv6.nd.ra.flag.h': _auto, 492 'icmpv6.echo.sequence_number': _auto, 493 'icmpv6.echo.identifier': _auto, 494 'icmpv6.data.len': _auto, 495 496 # COAP 497 'coap.code': _auto, 498 'coap.version': _auto, 499 'coap.type': _auto, 500 'coap.mid': _auto, 501 'coap.token_len': _auto, 502 'coap.token': _auto, 503 'coap.opt.uri_path': _list(_str), 504 'coap.opt.name': _list(_str), 505 'coap.opt.length': _list(_auto), 506 'coap.opt.uri_path_recon': _str, 507 'coap.payload': _payload, 508 'coap.payload_length': _auto, 509 'coap.payload_desc': _str, 510 'coap.opt.end_marker': _auto, 511 'coap.opt.desc': _list(_str), 512 'coap.opt.delta': _list(_auto), 513 'coap.response_to': _auto, 514 'coap.response_time': _float, 515 # COAP TLVS 516 'coap.tlv.type': _list(_auto), 517 'coap.tlv.status': _auto, 518 'coap.tlv.target_eid': _ipv6_addr, 519 'coap.tlv.ml_eid': _ext_addr, 520 'coap.tlv.last_transaction_time': _auto, 521 'coap.tlv.rloc16': _auto, 522 'coap.tlv.net_name': _str, 523 'coap.tlv.ext_mac_addr': _ext_addr, 524 'coap.tlv.router_mask_assigned': _auto, 525 'coap.tlv.router_mask_id_seq': _auto, 526 527 # dtls 528 'dtls.handshake.type': _list(_auto), 529 'dtls.handshake.cookie': _auto, 530 'dtls.record.content_type': _list(_auto), 531 'dtls.alert_message.desc': _auto, 532 533 # thread beacon 534 'thread_bcn.protocol': _auto, 535 'thread_bcn.version': _auto, 536 'thread_bcn.network_name': _str, 537 'thread_bcn.epid': _ext_addr, 538 539 # thread_address 540 'thread_address.tlv.len': _list(_auto), 541 'thread_address.tlv.type': _list(_auto), 542 'thread_address.tlv.status': _auto, 543 'thread_address.tlv.target_eid': _ipv6_addr, 544 'thread_address.tlv.ext_mac_addr': _ext_addr, 545 'thread_address.tlv.router_mask_id_seq': _auto, 546 'thread_address.tlv.router_mask_assigned': _bytes, 547 'thread_address.tlv.rloc16': _hex, 548 'thread_address.tlv.target_eid': _ipv6_addr, 549 'thread_address.tlv.ml_eid': _ext_addr, 550 551 # thread bl 552 'thread_bl.tlv.type': _list(_auto), 553 'thread_bl.tlv.len': _list(_auto), 554 'thread_bl.tlv.target_eid': _ipv6_addr, 555 'thread_bl.tlv.ml_eid': _ext_addr, 556 'thread_bl.tlv.last_transaction_time': _auto, 557 'thread_bl.tlv.timeout': _auto, 558 # THEAD NM 559 'thread_nm.tlv.type': _list(_auto), 560 'thread_nm.tlv.ml_eid': _ext_addr, 561 'thread_nm.tlv.target_eid': _ipv6_addr, 562 'thread_nm.tlv.status': _auto, 563 'thread_nm.tlv.timeout': _auto, 564 # thread_meshcop is not a real layer 565 'thread_meshcop.len_size_mismatch': _str, 566 'thread_meshcop.tlv.type': _list(_auto), 567 'thread_meshcop.tlv.len8': _list(_auto), 568 'thread_meshcop.tlv.net_name': _list(_str), # from thread_bl 569 'thread_meshcop.tlv.commissioner_id': _str, 570 'thread_meshcop.tlv.commissioner_sess_id': _auto, # from mle 571 "thread_meshcop.tlv.channel_page": _auto, # from ble 572 "thread_meshcop.tlv.channel": _list(_auto), # from ble 573 "thread_meshcop.tlv.chan_mask": _str, # from ble 574 'thread_meshcop.tlv.chan_mask_page': _auto, 575 'thread_meshcop.tlv.chan_mask_len': _auto, 576 'thread_meshcop.tlv.chan_mask_mask': _bytes, 577 'thread_meshcop.tlv.discovery_req_ver': _auto, 578 'thread_meshcop.tlv.discovery_rsp_ver': _auto, 579 'thread_meshcop.tlv.discovery_rsp_n': _auto, 580 'thread_meshcop.tlv.energy_list': _list(_auto), 581 'thread_meshcop.tlv.pan_id': _list(_auto), 582 'thread_meshcop.tlv.xpan_id': _bytes, 583 'thread_meshcop.tlv.ml_prefix': _bytes, 584 'thread_meshcop.tlv.master_key': _bytes, 585 'thread_meshcop.tlv.pskc': _bytes, 586 'thread_meshcop.tlv.sec_policy_rot': _auto, 587 'thread_meshcop.tlv.sec_policy_o': _auto, 588 'thread_meshcop.tlv.sec_policy_n': _auto, 589 'thread_meshcop.tlv.sec_policy_r': _auto, 590 'thread_meshcop.tlv.sec_policy_c': _auto, 591 'thread_meshcop.tlv.sec_policy_b': _auto, 592 'thread_meshcop.tlv.state': _auto, 593 'thread_meshcop.tlv.steering_data': _bytes, 594 'thread_meshcop.tlv.unknown': _bytes, 595 'thread_meshcop.tlv.udp_port': _list(_auto), 596 'thread_meshcop.tlv.ba_locator': _auto, 597 'thread_meshcop.tlv.jr_locator': _auto, 598 'thread_meshcop.tlv.active_tstamp': _auto, 599 'thread_meshcop.tlv.pending_tstamp': _auto, 600 'thread_meshcop.tlv.delay_timer': _auto, 601 'thread_meshcop.tlv.ipv6_addr': _list(_ipv6_addr), 602 603 # THREAD NWD 604 'thread_nwd.tlv.type': _list(_auto), 605 'thread_nwd.tlv.len': _list(_auto), 606 'thread_nwd.tlv.stable': _list(_auto), 607 'thread_nwd.tlv.service.t': _auto, 608 'thread_nwd.tlv.service.s_id': _auto, 609 'thread_nwd.tlv.service.s_data_len': _auto, 610 'thread_nwd.tlv.service.s_data.seqno': _auto, 611 'thread_nwd.tlv.service.s_data.rrdelay': _auto, 612 'thread_nwd.tlv.service.s_data.mlrtimeout': _auto, 613 'thread_nwd.tlv.server_16': _list(_auto), 614 'thread_nwd.tlv.border_router_16': _list(_auto), 615 'thread_nwd.tlv.sub_tlvs': _list(_str), 616 # TODO: support thread_nwd.tlv.prefix.length and thread_nwd.tlv.prefix.domain_id 617 'thread_nwd.tlv.prefix': _list(_ipv6_addr), 618 'thread_nwd.tlv.border_router.pref': _auto, 619 'thread_nwd.tlv.border_router.flag.s': _list(_auto), 620 'thread_nwd.tlv.border_router.flag.r': _list(_auto), 621 'thread_nwd.tlv.border_router.flag.p': _list(_auto), 622 'thread_nwd.tlv.border_router.flag.o': _list(_auto), 623 'thread_nwd.tlv.border_router.flag.n': _list(_auto), 624 'thread_nwd.tlv.border_router.flag.dp': _list(_auto), 625 'thread_nwd.tlv.border_router.flag.d': _list(_auto), 626 'thread_nwd.tlv.border_router.flag.c': _list(_auto), 627 'thread_nwd.tlv.6co.flag.reserved': _auto, 628 'thread_nwd.tlv.6co.flag.cid': _auto, 629 'thread_nwd.tlv.6co.flag.c': _list(_auto), 630 'thread_nwd.tlv.6co.context_length': _auto, 631 632 # Thread Diagnostic 633 'thread_diagnostic.tlv.type': _list(_auto), 634 'thread_diagnostic.tlv.len8': _list(_auto), 635 'thread_diagnostic.tlv.general': _list(_str), 636 637 # DNS 638 'dns.resp.ttl': _auto, 639 'dns.flags.response': _auto, 640} 641 642_layer_containers = set() 643 644for key in _LAYER_FIELDS: 645 assert key.strip() == key and ' ' not in key, key 646 secs = key.split('.') 647 assert len(secs) >= 2 648 assert secs[0] in VALID_LAYER_NAMES, secs[0] 649 for i in range(len(secs) - 2): 650 path = secs[0] + '.' + '.'.join(secs[1:i + 2]) 651 assert path not in _LAYER_FIELDS, '%s can not be both field and path' % path 652 _layer_containers.add(path) 653 654 655def is_layer_field(uri: str) -> bool: 656 """ 657 Returns if the URI is a valid layer field. 658 659 :param uri: The layer field URI. 660 """ 661 return uri in _LAYER_FIELDS 662 663 664def is_layer_field_container(uri: str) -> bool: 665 """ 666 Returns if the URI is a valid layer field container. 667 668 :param uri: The layer field container URI. 669 """ 670 return uri in _layer_containers 671 672 673def get_layer_field(packet: RawPacket, field_uri: str) -> Any: 674 """ 675 Get a given layer field from the packet. 676 677 :param packet: The packet. 678 :param field_uri: The layer field URI. 679 680 :return: The specified layer field. 681 """ 682 assert isinstance(packet, RawPacket) 683 secs = field_uri.split('.') 684 layer_depth = 0 685 layer_name = secs[0] 686 if layer_name.endswith('inner'): 687 layer_name = layer_name[:-len('inner')] 688 field_uri = '.'.join([layer_name] + secs[1:]) 689 layer_depth = 1 690 691 if is_layer_field(field_uri): 692 candidate_layers = _get_candidate_layers(packet, layer_name) 693 for layers in candidate_layers: 694 if layer_depth >= len(layers): 695 continue 696 layer = layers[layer_depth] 697 v = layer.get_field(field_uri) 698 if v is not None: 699 try: 700 v = _LAYER_FIELDS[field_uri](v) 701 print("[%s = %r] " % (field_uri, v), file=sys.stderr) 702 return v 703 except Exception as ex: 704 raise ValueError('can not parse field %s = %r' % (field_uri, 705 (v.get_default_value(), v.raw_value))) from ex 706 707 print("[%s = %s] " % (field_uri, "null"), file=sys.stderr) 708 return nullField 709 710 elif is_layer_field_container(field_uri): 711 from pktverify.layer_fields_container import LayerFieldsContainer 712 return LayerFieldsContainer(packet, field_uri) 713 else: 714 raise NotImplementedError('Field %s is not valid, please add it to `_LAYER_FIELDS`' % field_uri) 715 716 717def check_layer_field_exists(packet, field_uri): 718 """ 719 Check if a given layer field URI exists in the packet. 720 721 :param packet: The packet to check. 722 :param field_uri: The layer field URI. 723 :return: Whether the layer field URI exists in the packet. 724 """ 725 assert isinstance(packet, RawPacket) 726 secs = field_uri.split('.') 727 layer_name = secs[0] 728 729 if not is_layer_field(field_uri) and not is_layer_field_container(field_uri): 730 raise NotImplementedError('%s is neither a field or field container' % field_uri) 731 732 candidate_layers = _get_candidate_layers(packet, layer_name) 733 for layers in candidate_layers: 734 for layer in layers: 735 for k, v in layer._all_fields.items(): 736 if k == field_uri or k.startswith(field_uri + '.'): 737 return True 738 739 return False 740 741 742def _get_candidate_layers(packet, layer_name): 743 if layer_name == 'thread_meshcop': 744 candidate_layer_names = ['thread_meshcop', 'mle', 'coap', 'thread_bl', 'thread_nm'] 745 elif layer_name == 'thread_nwd': 746 candidate_layer_names = ['mle', 'thread_address', 'thread_diagnostic'] 747 elif layer_name == 'wpan': 748 candidate_layer_names = ['wpan', 'mle'] 749 elif layer_name == 'ip': 750 candidate_layer_names = ['ip', 'ipv6'] 751 elif layer_name == 'thread_bcn': 752 candidate_layer_names = ['thread_bcn'] 753 else: 754 candidate_layer_names = [layer_name] 755 756 layers = [] 757 for ln in candidate_layer_names: 758 if hasattr(packet, ln): 759 layers.append(packet.get_multiple_layers(ln)) 760 761 return layers 762