@netkitty/codec 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/LICENSE +21 -0
- package/README.md +352 -0
- package/README.zh-CN.md +342 -0
- package/dist/Codec.d.ts +133 -0
- package/dist/Codec.js +632 -0
- package/dist/PacketHeaders.d.ts +189 -0
- package/dist/PacketHeaders.js +384 -0
- package/dist/abstracts/BaseHeader.d.ts +325 -0
- package/dist/abstracts/BaseHeader.js +734 -0
- package/dist/errors/CodecSchemaValidateError.d.ts +4 -0
- package/dist/errors/CodecSchemaValidateError.js +11 -0
- package/dist/headers/ADSAMS.d.ts +33 -0
- package/dist/headers/ADSAMS.js +208 -0
- package/dist/headers/AH.d.ts +28 -0
- package/dist/headers/AH.js +137 -0
- package/dist/headers/AMQP.d.ts +31 -0
- package/dist/headers/AMQP.js +316 -0
- package/dist/headers/ARP.d.ts +26 -0
- package/dist/headers/ARP.js +243 -0
- package/dist/headers/BACnetIP.d.ts +27 -0
- package/dist/headers/BACnetIP.js +97 -0
- package/dist/headers/BFD.d.ts +28 -0
- package/dist/headers/BFD.js +155 -0
- package/dist/headers/BGP.d.ts +27 -0
- package/dist/headers/BGP.js +111 -0
- package/dist/headers/BSAPIP.d.ts +33 -0
- package/dist/headers/BSAPIP.js +78 -0
- package/dist/headers/Babel.d.ts +32 -0
- package/dist/headers/Babel.js +224 -0
- package/dist/headers/BitTorrent.d.ts +28 -0
- package/dist/headers/BitTorrent.js +72 -0
- package/dist/headers/C37118.d.ts +26 -0
- package/dist/headers/C37118.js +147 -0
- package/dist/headers/CAPWAP.d.ts +38 -0
- package/dist/headers/CAPWAP.js +275 -0
- package/dist/headers/CDP.d.ts +25 -0
- package/dist/headers/CDP.js +117 -0
- package/dist/headers/CMS.d.ts +33 -0
- package/dist/headers/CMS.js +238 -0
- package/dist/headers/COTP.d.ts +30 -0
- package/dist/headers/COTP.js +193 -0
- package/dist/headers/CassandraCQL.d.ts +28 -0
- package/dist/headers/CassandraCQL.js +117 -0
- package/dist/headers/CoAP.d.ts +29 -0
- package/dist/headers/CoAP.js +140 -0
- package/dist/headers/Codesys.d.ts +32 -0
- package/dist/headers/Codesys.js +119 -0
- package/dist/headers/Collectd.d.ts +29 -0
- package/dist/headers/Collectd.js +154 -0
- package/dist/headers/DCCP.d.ts +30 -0
- package/dist/headers/DCCP.js +204 -0
- package/dist/headers/DHCP.d.ts +26 -0
- package/dist/headers/DHCP.js +148 -0
- package/dist/headers/DHCPFailover.d.ts +30 -0
- package/dist/headers/DHCPFailover.js +104 -0
- package/dist/headers/DHCPv6.d.ts +25 -0
- package/dist/headers/DHCPv6.js +145 -0
- package/dist/headers/DNP3.d.ts +27 -0
- package/dist/headers/DNP3.js +150 -0
- package/dist/headers/DNS.d.ts +55 -0
- package/dist/headers/DNS.js +309 -0
- package/dist/headers/DTLS.d.ts +33 -0
- package/dist/headers/DTLS.js +142 -0
- package/dist/headers/Diameter.d.ts +34 -0
- package/dist/headers/Diameter.js +229 -0
- package/dist/headers/EAPOL.d.ts +32 -0
- package/dist/headers/EAPOL.js +135 -0
- package/dist/headers/EIGRP.d.ts +28 -0
- package/dist/headers/EIGRP.js +165 -0
- package/dist/headers/ENIP.d.ts +31 -0
- package/dist/headers/ENIP.js +164 -0
- package/dist/headers/ESP.d.ts +27 -0
- package/dist/headers/ESP.js +140 -0
- package/dist/headers/Elasticsearch.d.ts +30 -0
- package/dist/headers/Elasticsearch.js +125 -0
- package/dist/headers/EtherCAT.d.ts +35 -0
- package/dist/headers/EtherCAT.js +150 -0
- package/dist/headers/EthernetII.d.ts +28 -0
- package/dist/headers/EthernetII.js +117 -0
- package/dist/headers/FCoE.d.ts +38 -0
- package/dist/headers/FCoE.js +210 -0
- package/dist/headers/FTP.d.ts +34 -0
- package/dist/headers/FTP.js +158 -0
- package/dist/headers/Finger.d.ts +41 -0
- package/dist/headers/Finger.js +135 -0
- package/dist/headers/FoundationFieldbusHSE.d.ts +43 -0
- package/dist/headers/FoundationFieldbusHSE.js +163 -0
- package/dist/headers/GELF.d.ts +35 -0
- package/dist/headers/GELF.js +261 -0
- package/dist/headers/GENEVE.d.ts +26 -0
- package/dist/headers/GENEVE.js +209 -0
- package/dist/headers/GESRTP.d.ts +32 -0
- package/dist/headers/GESRTP.js +141 -0
- package/dist/headers/GLBP.d.ts +29 -0
- package/dist/headers/GLBP.js +159 -0
- package/dist/headers/GRE.d.ts +27 -0
- package/dist/headers/GRE.js +181 -0
- package/dist/headers/GTPU.d.ts +25 -0
- package/dist/headers/GTPU.js +203 -0
- package/dist/headers/GTPv2C.d.ts +30 -0
- package/dist/headers/GTPv2C.js +281 -0
- package/dist/headers/GitProtocol.d.ts +34 -0
- package/dist/headers/GitProtocol.js +141 -0
- package/dist/headers/Goose.d.ts +115 -0
- package/dist/headers/Goose.js +1067 -0
- package/dist/headers/Gopher.d.ts +43 -0
- package/dist/headers/Gopher.js +182 -0
- package/dist/headers/HARTIP.d.ts +30 -0
- package/dist/headers/HARTIP.js +145 -0
- package/dist/headers/HSR.d.ts +27 -0
- package/dist/headers/HSR.js +105 -0
- package/dist/headers/HSRP.d.ts +26 -0
- package/dist/headers/HSRP.js +173 -0
- package/dist/headers/HTTP.d.ts +32 -0
- package/dist/headers/HTTP.js +153 -0
- package/dist/headers/HTTP2.d.ts +34 -0
- package/dist/headers/HTTP2.js +190 -0
- package/dist/headers/IAX2.d.ts +33 -0
- package/dist/headers/IAX2.js +274 -0
- package/dist/headers/ICMP.d.ts +15 -0
- package/dist/headers/ICMP.js +148 -0
- package/dist/headers/ICMPv6.d.ts +15 -0
- package/dist/headers/ICMPv6.js +129 -0
- package/dist/headers/IEC104_I_Frame.d.ts +23 -0
- package/dist/headers/IEC104_I_Frame.js +6489 -0
- package/dist/headers/IEC104_S_Frame.d.ts +26 -0
- package/dist/headers/IEC104_S_Frame.js +135 -0
- package/dist/headers/IEC104_U_Frame.d.ts +27 -0
- package/dist/headers/IEC104_U_Frame.js +176 -0
- package/dist/headers/IEC61850SampledValues.d.ts +20 -0
- package/dist/headers/IEC61850SampledValues.js +420 -0
- package/dist/headers/IGMP.d.ts +31 -0
- package/dist/headers/IGMP.js +274 -0
- package/dist/headers/IMAP.d.ts +32 -0
- package/dist/headers/IMAP.js +185 -0
- package/dist/headers/IPFIX.d.ts +29 -0
- package/dist/headers/IPFIX.js +156 -0
- package/dist/headers/IPv4.d.ts +20 -0
- package/dist/headers/IPv4.js +370 -0
- package/dist/headers/IPv6.d.ts +29 -0
- package/dist/headers/IPv6.js +209 -0
- package/dist/headers/IPv6HopByHopOptions.d.ts +81 -0
- package/dist/headers/IPv6HopByHopOptions.js +495 -0
- package/dist/headers/IRC.d.ts +34 -0
- package/dist/headers/IRC.js +175 -0
- package/dist/headers/ISAKMP.d.ts +29 -0
- package/dist/headers/ISAKMP.js +197 -0
- package/dist/headers/ISCSI.d.ts +39 -0
- package/dist/headers/ISCSI.js +289 -0
- package/dist/headers/ISIS.d.ts +25 -0
- package/dist/headers/ISIS.js +79 -0
- package/dist/headers/ISOSession.d.ts +27 -0
- package/dist/headers/ISOSession.js +343 -0
- package/dist/headers/Ident.d.ts +42 -0
- package/dist/headers/Ident.js +184 -0
- package/dist/headers/KNXnetIP.d.ts +30 -0
- package/dist/headers/KNXnetIP.js +135 -0
- package/dist/headers/Kafka.d.ts +35 -0
- package/dist/headers/Kafka.js +128 -0
- package/dist/headers/Kerberos.d.ts +30 -0
- package/dist/headers/Kerberos.js +217 -0
- package/dist/headers/L2TP.d.ts +26 -0
- package/dist/headers/L2TP.js +297 -0
- package/dist/headers/LACP.d.ts +31 -0
- package/dist/headers/LACP.js +151 -0
- package/dist/headers/LDAP.d.ts +31 -0
- package/dist/headers/LDAP.js +226 -0
- package/dist/headers/LDP.d.ts +31 -0
- package/dist/headers/LDP.js +138 -0
- package/dist/headers/LISP.d.ts +30 -0
- package/dist/headers/LISP.js +103 -0
- package/dist/headers/LLC.d.ts +27 -0
- package/dist/headers/LLC.js +81 -0
- package/dist/headers/LLDP.d.ts +26 -0
- package/dist/headers/LLDP.js +126 -0
- package/dist/headers/LLMNR.d.ts +23 -0
- package/dist/headers/LLMNR.js +40 -0
- package/dist/headers/LPD.d.ts +31 -0
- package/dist/headers/LPD.js +159 -0
- package/dist/headers/MACsec.d.ts +34 -0
- package/dist/headers/MACsec.js +178 -0
- package/dist/headers/MDNS.d.ts +26 -0
- package/dist/headers/MDNS.js +45 -0
- package/dist/headers/MGCP.d.ts +30 -0
- package/dist/headers/MGCP.js +155 -0
- package/dist/headers/MMS.d.ts +29 -0
- package/dist/headers/MMS.js +243 -0
- package/dist/headers/MPLS.d.ts +31 -0
- package/dist/headers/MPLS.js +145 -0
- package/dist/headers/MQTT.d.ts +30 -0
- package/dist/headers/MQTT.js +173 -0
- package/dist/headers/MQTTSN.d.ts +34 -0
- package/dist/headers/MQTTSN.js +177 -0
- package/dist/headers/MarkerProtocol.d.ts +32 -0
- package/dist/headers/MarkerProtocol.js +153 -0
- package/dist/headers/Megaco.d.ts +32 -0
- package/dist/headers/Megaco.js +144 -0
- package/dist/headers/Memcached.d.ts +44 -0
- package/dist/headers/Memcached.js +285 -0
- package/dist/headers/ModbusTCP.d.ts +25 -0
- package/dist/headers/ModbusTCP.js +99 -0
- package/dist/headers/ModbusUDP.d.ts +26 -0
- package/dist/headers/ModbusUDP.js +100 -0
- package/dist/headers/MongoDB.d.ts +33 -0
- package/dist/headers/MongoDB.js +143 -0
- package/dist/headers/MySQL.d.ts +30 -0
- package/dist/headers/MySQL.js +114 -0
- package/dist/headers/NATS.d.ts +29 -0
- package/dist/headers/NATS.js +135 -0
- package/dist/headers/NBDS.d.ts +34 -0
- package/dist/headers/NBDS.js +176 -0
- package/dist/headers/NBNS.d.ts +34 -0
- package/dist/headers/NBNS.js +78 -0
- package/dist/headers/NBSS.d.ts +36 -0
- package/dist/headers/NBSS.js +137 -0
- package/dist/headers/NFS.d.ts +36 -0
- package/dist/headers/NFS.js +273 -0
- package/dist/headers/NHRP.d.ts +32 -0
- package/dist/headers/NHRP.js +154 -0
- package/dist/headers/NNTP.d.ts +35 -0
- package/dist/headers/NNTP.js +162 -0
- package/dist/headers/NTP.d.ts +18 -0
- package/dist/headers/NTP.js +73 -0
- package/dist/headers/NetFlowV5.d.ts +28 -0
- package/dist/headers/NetFlowV5.js +205 -0
- package/dist/headers/OLSR.d.ts +31 -0
- package/dist/headers/OLSR.js +213 -0
- package/dist/headers/OPCUA.d.ts +33 -0
- package/dist/headers/OPCUA.js +165 -0
- package/dist/headers/OPCUAPubSub.d.ts +33 -0
- package/dist/headers/OPCUAPubSub.js +144 -0
- package/dist/headers/OSPF.d.ts +31 -0
- package/dist/headers/OSPF.js +365 -0
- package/dist/headers/OmronFINS.d.ts +31 -0
- package/dist/headers/OmronFINS.js +90 -0
- package/dist/headers/OpenFlow.d.ts +30 -0
- package/dist/headers/OpenFlow.js +113 -0
- package/dist/headers/OpenVPN.d.ts +35 -0
- package/dist/headers/OpenVPN.js +214 -0
- package/dist/headers/PCWorx.d.ts +35 -0
- package/dist/headers/PCWorx.js +115 -0
- package/dist/headers/PIM.d.ts +27 -0
- package/dist/headers/PIM.js +129 -0
- package/dist/headers/POP3.d.ts +31 -0
- package/dist/headers/POP3.js +152 -0
- package/dist/headers/POWERLINK.d.ts +28 -0
- package/dist/headers/POWERLINK.js +116 -0
- package/dist/headers/PPPoEDiscovery.d.ts +29 -0
- package/dist/headers/PPPoEDiscovery.js +198 -0
- package/dist/headers/PPPoESession.d.ts +28 -0
- package/dist/headers/PPPoESession.js +125 -0
- package/dist/headers/PPTP.d.ts +30 -0
- package/dist/headers/PPTP.js +122 -0
- package/dist/headers/PROFINETRT.d.ts +28 -0
- package/dist/headers/PROFINETRT.js +74 -0
- package/dist/headers/PTP.d.ts +34 -0
- package/dist/headers/PTP.js +213 -0
- package/dist/headers/PostgreSQL.d.ts +40 -0
- package/dist/headers/PostgreSQL.js +236 -0
- package/dist/headers/QUIC.d.ts +34 -0
- package/dist/headers/QUIC.js +308 -0
- package/dist/headers/RADIUS.d.ts +24 -0
- package/dist/headers/RADIUS.js +138 -0
- package/dist/headers/RDP.d.ts +27 -0
- package/dist/headers/RDP.js +93 -0
- package/dist/headers/RFB.d.ts +39 -0
- package/dist/headers/RFB.js +151 -0
- package/dist/headers/RGoose.d.ts +72 -0
- package/dist/headers/RGoose.js +340 -0
- package/dist/headers/RIP.d.ts +29 -0
- package/dist/headers/RIP.js +133 -0
- package/dist/headers/RIPng.d.ts +26 -0
- package/dist/headers/RIPng.js +140 -0
- package/dist/headers/RMCP.d.ts +26 -0
- package/dist/headers/RMCP.js +155 -0
- package/dist/headers/RSVP.d.ts +31 -0
- package/dist/headers/RSVP.js +263 -0
- package/dist/headers/RTCP.d.ts +34 -0
- package/dist/headers/RTCP.js +217 -0
- package/dist/headers/RTP.d.ts +33 -0
- package/dist/headers/RTP.js +291 -0
- package/dist/headers/RTPS.d.ts +33 -0
- package/dist/headers/RTPS.js +182 -0
- package/dist/headers/RTSP.d.ts +36 -0
- package/dist/headers/RTSP.js +184 -0
- package/dist/headers/RawData.d.ts +17 -0
- package/dist/headers/RawData.js +43 -0
- package/dist/headers/Redis.d.ts +32 -0
- package/dist/headers/Redis.js +202 -0
- package/dist/headers/Rlogin.d.ts +42 -0
- package/dist/headers/Rlogin.js +139 -0
- package/dist/headers/Rsync.d.ts +28 -0
- package/dist/headers/Rsync.js +117 -0
- package/dist/headers/S7comm.d.ts +36 -0
- package/dist/headers/S7comm.js +244 -0
- package/dist/headers/SCTP.d.ts +35 -0
- package/dist/headers/SCTP.js +174 -0
- package/dist/headers/SFlow.d.ts +29 -0
- package/dist/headers/SFlow.js +242 -0
- package/dist/headers/SIP.d.ts +27 -0
- package/dist/headers/SIP.js +146 -0
- package/dist/headers/SLMP.d.ts +36 -0
- package/dist/headers/SLMP.js +154 -0
- package/dist/headers/SLP.d.ts +30 -0
- package/dist/headers/SLP.js +207 -0
- package/dist/headers/SLPv1.d.ts +32 -0
- package/dist/headers/SLPv1.js +138 -0
- package/dist/headers/SMB1.d.ts +37 -0
- package/dist/headers/SMB1.js +200 -0
- package/dist/headers/SMB2.d.ts +36 -0
- package/dist/headers/SMB2.js +203 -0
- package/dist/headers/SMPP.d.ts +33 -0
- package/dist/headers/SMPP.js +119 -0
- package/dist/headers/SMTP.d.ts +33 -0
- package/dist/headers/SMTP.js +157 -0
- package/dist/headers/SNAP.d.ts +22 -0
- package/dist/headers/SNAP.js +68 -0
- package/dist/headers/SNMP.d.ts +28 -0
- package/dist/headers/SNMP.js +302 -0
- package/dist/headers/SOCKS4.d.ts +42 -0
- package/dist/headers/SOCKS4.js +302 -0
- package/dist/headers/SOCKS5.d.ts +45 -0
- package/dist/headers/SOCKS5.js +223 -0
- package/dist/headers/SSDP.d.ts +27 -0
- package/dist/headers/SSDP.js +161 -0
- package/dist/headers/SSH.d.ts +44 -0
- package/dist/headers/SSH.js +274 -0
- package/dist/headers/STOMP.d.ts +48 -0
- package/dist/headers/STOMP.js +177 -0
- package/dist/headers/STP.d.ts +26 -0
- package/dist/headers/STP.js +150 -0
- package/dist/headers/STUN.d.ts +25 -0
- package/dist/headers/STUN.js +183 -0
- package/dist/headers/SercosIII.d.ts +43 -0
- package/dist/headers/SercosIII.js +199 -0
- package/dist/headers/Skinny.d.ts +32 -0
- package/dist/headers/Skinny.js +139 -0
- package/dist/headers/StatsD.d.ts +27 -0
- package/dist/headers/StatsD.js +134 -0
- package/dist/headers/SunRPC.d.ts +34 -0
- package/dist/headers/SunRPC.js +268 -0
- package/dist/headers/Syslog.d.ts +21 -0
- package/dist/headers/Syslog.js +91 -0
- package/dist/headers/TCP.d.ts +19 -0
- package/dist/headers/TCP.js +905 -0
- package/dist/headers/TFTP.d.ts +28 -0
- package/dist/headers/TFTP.js +224 -0
- package/dist/headers/TLS_Alert.d.ts +24 -0
- package/dist/headers/TLS_Alert.js +639 -0
- package/dist/headers/TLS_ApplicationData.d.ts +24 -0
- package/dist/headers/TLS_ApplicationData.js +170 -0
- package/dist/headers/TLS_ChangeCipherSpec.d.ts +23 -0
- package/dist/headers/TLS_ChangeCipherSpec.js +168 -0
- package/dist/headers/TLS_Handshake.d.ts +65 -0
- package/dist/headers/TLS_Handshake.js +860 -0
- package/dist/headers/TLS_Heartbeat.d.ts +27 -0
- package/dist/headers/TLS_Heartbeat.js +247 -0
- package/dist/headers/TPKT.d.ts +26 -0
- package/dist/headers/TPKT.js +99 -0
- package/dist/headers/TacacsPlus.d.ts +27 -0
- package/dist/headers/TacacsPlus.js +133 -0
- package/dist/headers/Telnet.d.ts +40 -0
- package/dist/headers/Telnet.js +193 -0
- package/dist/headers/Teredo.d.ts +40 -0
- package/dist/headers/Teredo.js +251 -0
- package/dist/headers/TimeProtocol.d.ts +25 -0
- package/dist/headers/TimeProtocol.js +53 -0
- package/dist/headers/UDP.d.ts +19 -0
- package/dist/headers/UDP.js +171 -0
- package/dist/headers/VLAN_802dot1Q.d.ts +24 -0
- package/dist/headers/VLAN_802dot1Q.js +96 -0
- package/dist/headers/VRRP.d.ts +26 -0
- package/dist/headers/VRRP.js +309 -0
- package/dist/headers/VXLAN.d.ts +24 -0
- package/dist/headers/VXLAN.js +75 -0
- package/dist/headers/WCCP.d.ts +29 -0
- package/dist/headers/WCCP.js +117 -0
- package/dist/headers/WHOIS.d.ts +37 -0
- package/dist/headers/WHOIS.js +126 -0
- package/dist/headers/WSDiscovery.d.ts +29 -0
- package/dist/headers/WSDiscovery.js +118 -0
- package/dist/headers/WakeOnLAN.d.ts +30 -0
- package/dist/headers/WakeOnLAN.js +126 -0
- package/dist/headers/WebSocket.d.ts +26 -0
- package/dist/headers/WebSocket.js +173 -0
- package/dist/headers/WireGuard.d.ts +38 -0
- package/dist/headers/WireGuard.js +216 -0
- package/dist/headers/XMPP.d.ts +37 -0
- package/dist/headers/XMPP.js +149 -0
- package/dist/headers/Zabbix.d.ts +35 -0
- package/dist/headers/Zabbix.js +153 -0
- package/dist/headers/cms/AcsiPdu.d.ts +45 -0
- package/dist/headers/cms/AcsiPdu.js +112 -0
- package/dist/headers/cms/PerDecoder.d.ts +68 -0
- package/dist/headers/cms/PerDecoder.js +211 -0
- package/dist/headers/cms/PerReader.d.ts +64 -0
- package/dist/headers/cms/PerReader.js +155 -0
- package/dist/helper/BufferToHex.d.ts +5 -0
- package/dist/helper/BufferToHex.js +10 -0
- package/dist/helper/BufferToIP.d.ts +12 -0
- package/dist/helper/BufferToIP.js +23 -0
- package/dist/helper/BufferToNumber.d.ts +18 -0
- package/dist/helper/BufferToNumber.js +47 -0
- package/dist/helper/HexToBuffer.d.ts +7 -0
- package/dist/helper/HexToBuffer.js +27 -0
- package/dist/helper/HexToNumber.d.ts +18 -0
- package/dist/helper/HexToNumber.js +48 -0
- package/dist/helper/IPToBuffer.d.ts +12 -0
- package/dist/helper/IPToBuffer.js +34 -0
- package/dist/helper/NumberToBERBuffer.d.ts +18 -0
- package/dist/helper/NumberToBERBuffer.js +31 -0
- package/dist/helper/NumberToBERHex.d.ts +18 -0
- package/dist/helper/NumberToBERHex.js +52 -0
- package/dist/helper/NumberToBuffer.d.ts +18 -0
- package/dist/helper/NumberToBuffer.js +38 -0
- package/dist/helper/NumberToHex.d.ts +18 -0
- package/dist/helper/NumberToHex.js +35 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +113 -0
- package/dist/lib/FlexibleObject.d.ts +27 -0
- package/dist/lib/FlexibleObject.js +113 -0
- package/dist/lib/GetBERIntegerLengthFromBuffer.d.ts +6 -0
- package/dist/lib/GetBERIntegerLengthFromBuffer.js +16 -0
- package/dist/lib/ProcessPacketPostHandlers.d.ts +13 -0
- package/dist/lib/ProcessPacketPostHandlers.js +53 -0
- package/dist/lib/SortPostHandlers.d.ts +7 -0
- package/dist/lib/SortPostHandlers.js +11 -0
- package/dist/lib/StringContentEncodingEnum.d.ts +10 -0
- package/dist/lib/StringContentEncodingEnum.js +14 -0
- package/dist/schema/ProtocolFieldJSONSchema.d.ts +35 -0
- package/dist/schema/ProtocolFieldJSONSchema.js +2 -0
- package/dist/schema/ProtocolFieldJSONSchemaDefinition.d.ts +2 -0
- package/dist/schema/ProtocolFieldJSONSchemaDefinition.js +2 -0
- package/dist/schema/ProtocolJSONSchema.d.ts +32 -0
- package/dist/schema/ProtocolJSONSchema.js +2 -0
- package/dist/types/CodecData.d.ts +7 -0
- package/dist/types/CodecData.js +2 -0
- package/dist/types/CodecDecodeResult.d.ts +10 -0
- package/dist/types/CodecDecodeResult.js +2 -0
- package/dist/types/CodecEncodeInput.d.ts +2 -0
- package/dist/types/CodecEncodeInput.js +2 -0
- package/dist/types/CodecEncodeResult.d.ts +5 -0
- package/dist/types/CodecEncodeResult.js +2 -0
- package/dist/types/CodecErrorInfo.d.ts +5 -0
- package/dist/types/CodecErrorInfo.js +2 -0
- package/dist/types/CodecModule.d.ts +2 -0
- package/dist/types/CodecModule.js +2 -0
- package/dist/types/CodecModuleConstructor.d.ts +2 -0
- package/dist/types/CodecModuleConstructor.js +2 -0
- package/dist/types/CodecSchema.d.ts +6 -0
- package/dist/types/CodecSchema.js +2 -0
- package/dist/types/DemuxProducer.d.ts +23 -0
- package/dist/types/DemuxProducer.js +2 -0
- package/dist/types/Dissection.d.ts +23 -0
- package/dist/types/Dissection.js +2 -0
- package/dist/types/HeaderTreeNode.d.ts +4 -0
- package/dist/types/HeaderTreeNode.js +2 -0
- package/dist/types/LayerGraph.d.ts +32 -0
- package/dist/types/LayerGraph.js +2 -0
- package/dist/types/PostHandlerItem.d.ts +4 -0
- package/dist/types/PostHandlerItem.js +2 -0
- package/package.json +141 -0
package/dist/Codec.js
ADDED
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.Codec = void 0;
|
|
37
|
+
const FlexibleObject_1 = require("./lib/FlexibleObject");
|
|
38
|
+
const ProcessPacketPostHandlers_1 = require("./lib/ProcessPacketPostHandlers");
|
|
39
|
+
const RawData_1 = require("./headers/RawData");
|
|
40
|
+
const packetHeaders = __importStar(require("./PacketHeaders"));
|
|
41
|
+
/**
|
|
42
|
+
* The schema-driven packet codec: the entry point a consumer uses to turn bytes into a
|
|
43
|
+
* layered field tree and back.
|
|
44
|
+
*
|
|
45
|
+
* `decode(bytes)` walks the packet layer by layer, selecting each next header by an O(1)
|
|
46
|
+
* dispatch table keyed on the previous layer's demux value (`ethertype:`/`ipproto:`/
|
|
47
|
+
* `tcpport:`…), falling back to a content-heuristic chain for headers that must inspect
|
|
48
|
+
* their own bytes (TLS, IEC104, tunnels), and finally to `RawData` — so decode never
|
|
49
|
+
* throws and always yields a best-effort result plus a field-path-addressed error list.
|
|
50
|
+
* `encode(layers)` looks each layer up by protocol id and re-emits it in the given order.
|
|
51
|
+
* Cross-layer fixups (lengths, checksums) run as post-handlers afterwards. Read-only
|
|
52
|
+
* projections over the same decode are exposed via `dissect()`, `summary()`,
|
|
53
|
+
* `allowedNextLayers()`, `childDiscriminator()` and `checkConsistency()`.
|
|
54
|
+
*/
|
|
55
|
+
class Codec {
|
|
56
|
+
#codecModuleConstructors = [];
|
|
57
|
+
#codecSchemas = [];
|
|
58
|
+
/**
|
|
59
|
+
* Dispatch table: demux key (e.g. 'ethertype:0800', 'ipproto:6') → codec candidates.
|
|
60
|
+
* Built once at construction for O(1) next-layer selection during decode.
|
|
61
|
+
*/
|
|
62
|
+
#dispatchTable = new Map();
|
|
63
|
+
/**
|
|
64
|
+
* Content-heuristic codecs: headers without demux keys that must inspect
|
|
65
|
+
* their own bytes to match (TLS, IEC104, ethernet tunnels, and any custom
|
|
66
|
+
* codec that did not declare matchKeys). Tried linearly only when the
|
|
67
|
+
* dispatch table misses. Kept in registration order.
|
|
68
|
+
*/
|
|
69
|
+
#heuristicCodecs = [];
|
|
70
|
+
/**
|
|
71
|
+
* Range demux table: namespace → sorted list of {lo, hi, codec} for matchKeys like
|
|
72
|
+
* 'tcpport:6000-6063'. Checked when an exact bucket lookup for that namespace's value misses, so a
|
|
73
|
+
* protocol can claim a port range without expanding it into thousands of exact keys.
|
|
74
|
+
*/
|
|
75
|
+
#rangeTable = new Map();
|
|
76
|
+
/**
|
|
77
|
+
* Encode lookup: PROTOCOL_ID → codec constructor. Built once alongside the dispatch table so
|
|
78
|
+
* #encode resolves each input layer's constructor in O(1) instead of scanning HEADER_CODECS with a
|
|
79
|
+
* `.find` reading the `PROTOCOL_ID` getter — which constructs a throwaway instance (and, for the
|
|
80
|
+
* unmigrated headers, rebuilds SCHEMA) per candidate, i.e. ~O(headers) redundant constructions per
|
|
81
|
+
* encoded layer. First registration wins, preserving the previous `.find` first-match semantics.
|
|
82
|
+
*/
|
|
83
|
+
#codecConstructorById = new Map();
|
|
84
|
+
/**
|
|
85
|
+
* The RawData catch-all. Not part of the dispatch table or heuristic list;
|
|
86
|
+
* used explicitly as the final fallback so decode never fails.
|
|
87
|
+
*/
|
|
88
|
+
#rawDataCodec = RawData_1.RawData;
|
|
89
|
+
get HEADER_CODECS() {
|
|
90
|
+
return this.#codecModuleConstructors;
|
|
91
|
+
}
|
|
92
|
+
get CODEC_SCHEMAS() {
|
|
93
|
+
return this.#codecSchemas;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Build a codec over the built-in protocol headers, optionally extended with custom ones.
|
|
97
|
+
* Each custom codec whose `PROTOCOL_ID` matches a built-in replaces it in place; the rest
|
|
98
|
+
* are appended. The dispatch table and heuristic chain are then built from the final set.
|
|
99
|
+
* @param codecModuleConstructors custom header codecs to override built-ins or add new protocols
|
|
100
|
+
*/
|
|
101
|
+
constructor(codecModuleConstructors = []) {
|
|
102
|
+
this.#codecModuleConstructors = this.loadHeaderCodecs();
|
|
103
|
+
if (codecModuleConstructors) {
|
|
104
|
+
const replaced = [];
|
|
105
|
+
codecModuleConstructors.forEach((codecModuleConstructor) => {
|
|
106
|
+
const id = codecModuleConstructor.PROTOCOL_ID;
|
|
107
|
+
this.#codecModuleConstructors.forEach((HEADER_CODEC, index, array) => {
|
|
108
|
+
if (HEADER_CODEC.PROTOCOL_ID === id) {
|
|
109
|
+
array[index] = codecModuleConstructor;
|
|
110
|
+
replaced.push(codecModuleConstructor);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
codecModuleConstructors
|
|
115
|
+
.filter((codecModuleConstructor) => !replaced.includes(codecModuleConstructor))
|
|
116
|
+
.forEach((codecModuleConstructor) => this.#codecModuleConstructors.push(codecModuleConstructor));
|
|
117
|
+
}
|
|
118
|
+
this.#codecSchemas = this.loadCodecSchemas();
|
|
119
|
+
this.buildDispatchTable();
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Load codec schemas
|
|
123
|
+
* @protected
|
|
124
|
+
*/
|
|
125
|
+
loadCodecSchemas() {
|
|
126
|
+
return this.HEADER_CODECS.map((codecModuleConstructor) => ({
|
|
127
|
+
id: codecModuleConstructor.PROTOCOL_ID,
|
|
128
|
+
name: codecModuleConstructor.PROTOCOL_NAME,
|
|
129
|
+
schema: codecModuleConstructor.PROTOCOL_SCHEMA
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Load header codecs
|
|
134
|
+
* @protected
|
|
135
|
+
*/
|
|
136
|
+
loadHeaderCodecs() {
|
|
137
|
+
return [...Object.values(packetHeaders)];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Build the dispatch table and heuristic list from the registered codecs.
|
|
141
|
+
* Called once after all codecs (built-in + custom overrides/additions) are
|
|
142
|
+
* assembled. RawData is pulled out as the explicit fallback.
|
|
143
|
+
* @protected
|
|
144
|
+
*/
|
|
145
|
+
buildDispatchTable() {
|
|
146
|
+
this.#dispatchTable.clear();
|
|
147
|
+
this.#heuristicCodecs.length = 0;
|
|
148
|
+
this.#rangeTable.clear();
|
|
149
|
+
this.#codecConstructorById.clear();
|
|
150
|
+
for (const codecModuleConstructor of this.HEADER_CODECS) {
|
|
151
|
+
//Read PROTOCOL_ID once (the getter builds a throwaway instance) and register it for O(1)
|
|
152
|
+
//encode lookup; keep the first registration so this matches the old `.find` first-match.
|
|
153
|
+
const protocolId = codecModuleConstructor.PROTOCOL_ID;
|
|
154
|
+
if (!this.#codecConstructorById.has(protocolId))
|
|
155
|
+
this.#codecConstructorById.set(protocolId, codecModuleConstructor);
|
|
156
|
+
if (protocolId === RawData_1.RawData.PROTOCOL_ID) {
|
|
157
|
+
this.#rawDataCodec = codecModuleConstructor;
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const matchKeys = codecModuleConstructor.MATCH_KEYS;
|
|
161
|
+
const keyed = !!(matchKeys && matchKeys.length);
|
|
162
|
+
if (keyed) {
|
|
163
|
+
for (const matchKey of matchKeys) {
|
|
164
|
+
const range = this.#parseRangeKey(matchKey);
|
|
165
|
+
if (range) {
|
|
166
|
+
const list = this.#rangeTable.get(range.namespace);
|
|
167
|
+
const entry = { lo: range.lo, hi: range.hi, codecModuleConstructor: codecModuleConstructor };
|
|
168
|
+
if (list)
|
|
169
|
+
list.push(entry);
|
|
170
|
+
else
|
|
171
|
+
this.#rangeTable.set(range.namespace, [entry]);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
const bucket = this.#dispatchTable.get(matchKey);
|
|
175
|
+
if (bucket)
|
|
176
|
+
bucket.push(codecModuleConstructor);
|
|
177
|
+
else
|
|
178
|
+
this.#dispatchTable.set(matchKey, [codecModuleConstructor]);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
//Also list in the heuristic fallback when unkeyed, OR when a keyed codec opts in — so a
|
|
182
|
+
//content-signed protocol on its well-known port takes the O(1) bucket yet still matches on
|
|
183
|
+
//any other port. A codec may therefore appear in both a bucket and the heuristic chain.
|
|
184
|
+
if (!keyed || codecModuleConstructor.HEURISTIC_FALLBACK) {
|
|
185
|
+
this.#heuristicCodecs.push(codecModuleConstructor);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
//Deterministic ordering: higher matchPriority is tried first within each bucket and within the
|
|
189
|
+
//heuristic chain; Array.sort is stable in Node, so ties keep registration order (all default 0
|
|
190
|
+
//→ order unchanged, so existing behavior is byte-identical).
|
|
191
|
+
for (const bucket of this.#dispatchTable.values())
|
|
192
|
+
this.#sortByPriority(bucket);
|
|
193
|
+
for (const ranges of this.#rangeTable.values())
|
|
194
|
+
ranges.sort((a, b) => b.codecModuleConstructor.MATCH_PRIORITY - a.codecModuleConstructor.MATCH_PRIORITY);
|
|
195
|
+
this.#sortByPriority(this.#heuristicCodecs);
|
|
196
|
+
}
|
|
197
|
+
#sortByPriority(codecModuleConstructors) {
|
|
198
|
+
codecModuleConstructors.sort((a, b) => b.MATCH_PRIORITY - a.MATCH_PRIORITY);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Parse a range matchKey 'namespace:LO-HI' (decimal, LO<=HI) into its parts, or null if it is a
|
|
202
|
+
* plain exact key. Only integer ranges are supported (ports).
|
|
203
|
+
* @private
|
|
204
|
+
*/
|
|
205
|
+
#parseRangeKey(matchKey) {
|
|
206
|
+
const match = matchKey.match(/^([^:]+):(\d+)-(\d+)$/);
|
|
207
|
+
if (!match)
|
|
208
|
+
return null;
|
|
209
|
+
const lo = Number(match[2]);
|
|
210
|
+
const hi = Number(match[3]);
|
|
211
|
+
if (lo > hi)
|
|
212
|
+
return null;
|
|
213
|
+
return { namespace: match[1], lo: lo, hi: hi };
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Derive the demux keys exposed by the previously decoded layer.
|
|
217
|
+
* The layer order is decided entirely at runtime from these values, so a
|
|
218
|
+
* packet with or without a given header (e.g. an IPv6 packet with or
|
|
219
|
+
* without a Hop-by-Hop header) is handled purely by what its next-header
|
|
220
|
+
* fields actually say — the table itself encodes no layer ordering.
|
|
221
|
+
*
|
|
222
|
+
* etherType → 'ethertype:<value>' namespace.
|
|
223
|
+
* protocol AND nxt → shared 'ipproto:<value>' namespace, so a header
|
|
224
|
+
* registered under 'ipproto:6' (TCP) is reachable above both IPv4
|
|
225
|
+
* (protocol) and IPv6 (nxt).
|
|
226
|
+
* @param prevCodecModule
|
|
227
|
+
* @protected
|
|
228
|
+
*/
|
|
229
|
+
computeDemuxKeys(prevCodecModule) {
|
|
230
|
+
if (!prevCodecModule)
|
|
231
|
+
return [];
|
|
232
|
+
//Read the declaration off the already-constructed prev instance (not the static getter, which
|
|
233
|
+
//would build a fresh instance + SCHEMA per decoded layer on the hot path).
|
|
234
|
+
const producers = prevCodecModule.demuxProducers;
|
|
235
|
+
const instance = prevCodecModule.instance;
|
|
236
|
+
const keys = [];
|
|
237
|
+
for (const producer of producers) {
|
|
238
|
+
const raw = instance[producer.field].getValue();
|
|
239
|
+
if (raw === undefined || raw === null)
|
|
240
|
+
continue;
|
|
241
|
+
keys.push(`${producer.namespace}:${this.#normalizeDemux(raw, producer.kind)}`);
|
|
242
|
+
}
|
|
243
|
+
return keys;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Normalize a demux value into its dispatch-key form by the field's STORAGE representation (never
|
|
247
|
+
* by an output radix). uint → decimal string (protocol/nxt/ports are numbers); string → identity
|
|
248
|
+
* (etherType already stores a lower-case fixed-width hex string; case-sensitive maps kept verbatim);
|
|
249
|
+
* guid/bytes → lower-cased. Must produce exactly the string a matchKeys entry uses.
|
|
250
|
+
* @private
|
|
251
|
+
*/
|
|
252
|
+
#normalizeDemux(raw, kind) {
|
|
253
|
+
switch (kind) {
|
|
254
|
+
case 'uint':
|
|
255
|
+
return String(raw);
|
|
256
|
+
case 'guid':
|
|
257
|
+
case 'bytes':
|
|
258
|
+
return String(raw).toLowerCase();
|
|
259
|
+
case 'string':
|
|
260
|
+
default:
|
|
261
|
+
return String(raw);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Select the codec for the next layer: dispatch table → content-heuristic
|
|
266
|
+
* list → RawData. Never returns undefined; RawData always matches unknown
|
|
267
|
+
* or malformed data, so decode cannot fail.
|
|
268
|
+
* @param codecData
|
|
269
|
+
* @param codecModules
|
|
270
|
+
* @protected
|
|
271
|
+
*/
|
|
272
|
+
selectCodec(codecData, codecModules, rootLinktype) {
|
|
273
|
+
const prevCodecModule = codecModules[codecModules.length - 1];
|
|
274
|
+
//Root layer: when a link type is supplied (a pcap DLT value), dispatch the first layer by a
|
|
275
|
+
//'linktype:<dlt>' key so a non-Ethernet link (802.11+radiotap, etc.) selects the right root.
|
|
276
|
+
//Without one, the root falls to the heuristic list (Ethernet matches when there is no parent),
|
|
277
|
+
//so the default decode(packet) behaviour is unchanged.
|
|
278
|
+
const demuxKeys = (codecModules.length === 0 && rootLinktype !== undefined && rootLinktype !== null)
|
|
279
|
+
? [`linktype:${rootLinktype}`]
|
|
280
|
+
: this.computeDemuxKeys(prevCodecModule);
|
|
281
|
+
//1. Dispatch table: O(1) lookup by the previous layer's demux value. Every candidate is
|
|
282
|
+
//confirmed by match(), singleton buckets included — a header's own guard is never skipped, so
|
|
283
|
+
//a demux key that is ambiguous across parents (e.g. 'ipproto:0' produced by both an IPv4
|
|
284
|
+
//protocol=0 and an IPv6 next-header=0) still routes correctly, because IPv6 Hop-by-Hop's
|
|
285
|
+
//match() rejects a non-IPv6 parent. Transport headers accept their demux value from both IPv4
|
|
286
|
+
//(protocol) and IPv6 (nxt); see TCP/UDP match().
|
|
287
|
+
for (const matchKey of demuxKeys) {
|
|
288
|
+
const bucket = this.#dispatchTable.get(matchKey);
|
|
289
|
+
if (bucket) {
|
|
290
|
+
for (const codecModuleConstructor of bucket) {
|
|
291
|
+
if (codecModuleConstructor.MATCH(codecData, codecModules))
|
|
292
|
+
return codecModuleConstructor;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
//Range table: a codec claiming e.g. 'tcpport:6000-6063' matches any value in [lo,hi].
|
|
296
|
+
if (this.#rangeTable.size > 0) {
|
|
297
|
+
const colon = matchKey.indexOf(':');
|
|
298
|
+
const ranges = colon > 0 ? this.#rangeTable.get(matchKey.substring(0, colon)) : undefined;
|
|
299
|
+
if (ranges) {
|
|
300
|
+
const value = Number(matchKey.substring(colon + 1));
|
|
301
|
+
if (Number.isInteger(value)) {
|
|
302
|
+
for (const range of ranges) {
|
|
303
|
+
if (value >= range.lo && value <= range.hi && range.codecModuleConstructor.MATCH(codecData, codecModules))
|
|
304
|
+
return range.codecModuleConstructor;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
//2. Content-heuristic codecs (tunnels, TCP-payload protocols, undeclared customs).
|
|
311
|
+
for (const codecModuleConstructor of this.#heuristicCodecs) {
|
|
312
|
+
if (codecModuleConstructor.MATCH(codecData, codecModules))
|
|
313
|
+
return codecModuleConstructor;
|
|
314
|
+
}
|
|
315
|
+
//3. RawData fallback: always matches, so unknown/malformed data still decodes.
|
|
316
|
+
return this.#rawDataCodec;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Internal encode headers to packet
|
|
320
|
+
* @param inputs
|
|
321
|
+
* @param errors
|
|
322
|
+
* @private
|
|
323
|
+
*/
|
|
324
|
+
async #encode(inputs, errors = []) {
|
|
325
|
+
const codecData = {
|
|
326
|
+
packet: Buffer.from([]),
|
|
327
|
+
startPos: 0,
|
|
328
|
+
postHandlers: []
|
|
329
|
+
};
|
|
330
|
+
const codecModules = [];
|
|
331
|
+
for (const input of inputs) {
|
|
332
|
+
const codecModuleConstructor = this.#codecConstructorById.get(input.id);
|
|
333
|
+
if (!codecModuleConstructor) {
|
|
334
|
+
errors.push({ id: input.id, path: '', message: `Unknown protocol id: ${input.id}` });
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
const codecModule = codecModuleConstructor.CREATE_INSTANCE(codecData, codecModules);
|
|
338
|
+
codecModule.instance = new FlexibleObject_1.FlexibleObject(codecModule.validate(input.data));
|
|
339
|
+
await codecModule.encode();
|
|
340
|
+
codecModule.errors.forEach((errorInfo) => errors.push(errorInfo));
|
|
341
|
+
codecData.startPos = codecModule.endPos;
|
|
342
|
+
codecModules.push(codecModule);
|
|
343
|
+
}
|
|
344
|
+
return codecData;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Internal decode packet
|
|
348
|
+
* @param codecData
|
|
349
|
+
* @param codecModules
|
|
350
|
+
* @private
|
|
351
|
+
*/
|
|
352
|
+
async #decode(codecData, codecModules = [], collectRanges = false, rootLinktype) {
|
|
353
|
+
//rootLinktype only steers the first (root) layer; deeper layers demux off their parent.
|
|
354
|
+
const codecModuleConstructor = this.selectCodec(codecData, codecModules, codecModules.length === 0 ? rootLinktype : undefined);
|
|
355
|
+
const codecModule = codecModuleConstructor.CREATE_INSTANCE(codecData, codecModules);
|
|
356
|
+
//Dissect pass: record each field's byte span. Off for normal decode, so the hot path is untouched.
|
|
357
|
+
if (collectRanges)
|
|
358
|
+
codecModule.enableByteRangeTracking();
|
|
359
|
+
await codecModule.decode();
|
|
360
|
+
codecData.startPos = codecModule.endPos;
|
|
361
|
+
codecModules.push(codecModule);
|
|
362
|
+
if (codecData.startPos >= codecData.packet.length)
|
|
363
|
+
return;
|
|
364
|
+
return this.#decode(codecData, codecModules, collectRanges, rootLinktype);
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Decode packet
|
|
368
|
+
* @param packet
|
|
369
|
+
* @param linktype optional pcap link-layer type (DLT) to select the root layer (e.g. 1 = Ethernet,
|
|
370
|
+
* 127 = radiotap). Omit to use the default Ethernet-first root — existing callers are unaffected.
|
|
371
|
+
*/
|
|
372
|
+
async decode(packet, linktype) {
|
|
373
|
+
const codecData = {
|
|
374
|
+
packet: packet,
|
|
375
|
+
startPos: 0,
|
|
376
|
+
postHandlers: []
|
|
377
|
+
};
|
|
378
|
+
const codecModules = [];
|
|
379
|
+
await this.#decode(codecData, codecModules, false, linktype);
|
|
380
|
+
const postDecodeHandlers = (0, ProcessPacketPostHandlers_1.ProcessPacketDecodePostHandlers)(codecData.postHandlers);
|
|
381
|
+
let postDecodeHandler = postDecodeHandlers.shift();
|
|
382
|
+
while (postDecodeHandler) {
|
|
383
|
+
await postDecodeHandler.handler();
|
|
384
|
+
postDecodeHandler = postDecodeHandlers.shift();
|
|
385
|
+
}
|
|
386
|
+
return codecModules.map((codecModule) => ({
|
|
387
|
+
id: codecModule.id,
|
|
388
|
+
name: codecModule.name,
|
|
389
|
+
nickname: codecModule.nickname,
|
|
390
|
+
protocol: codecModule.isProtocol,
|
|
391
|
+
errors: codecModule.errors,
|
|
392
|
+
data: codecModule.instance.getValue()
|
|
393
|
+
}));
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Encode packet
|
|
397
|
+
* @param inputs
|
|
398
|
+
*/
|
|
399
|
+
async encode(inputs) {
|
|
400
|
+
const errors = [];
|
|
401
|
+
const codecData = await this.#encode(inputs, errors);
|
|
402
|
+
const postEncodeHandlers = (0, ProcessPacketPostHandlers_1.ProcessPacketEncodePostHandlers)(codecData.postHandlers);
|
|
403
|
+
let postEncodeHandler = postEncodeHandlers.shift();
|
|
404
|
+
while (postEncodeHandler) {
|
|
405
|
+
await postEncodeHandler.handler();
|
|
406
|
+
postEncodeHandler = postEncodeHandlers.shift();
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
packet: codecData.packetLength === undefined ? codecData.packet : codecData.packet.subarray(0, codecData.packetLength),
|
|
410
|
+
errors: errors
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Producer fields a layer's schema declares (etherType / protocol / nxt) — the fields whose
|
|
415
|
+
* value decode uses to pick the next layer. Basis for walking the parent→child graph forward.
|
|
416
|
+
* @param layerId
|
|
417
|
+
* @private
|
|
418
|
+
*/
|
|
419
|
+
#producersOf(layerId) {
|
|
420
|
+
const codecModuleConstructor = this.HEADER_CODECS.find((codec) => codec.PROTOCOL_ID === layerId);
|
|
421
|
+
return codecModuleConstructor ? codecModuleConstructor.DEMUX_PRODUCERS : [];
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Editor helper (read-only projection over the same demux graph decode uses): the layers that
|
|
425
|
+
* may follow `parentLayerId`, each tagged with the {field,value} to set on the parent so decode
|
|
426
|
+
* would route to it. Derived by reversing the dispatch table over the parent's producer fields.
|
|
427
|
+
* RawData is always appended as the custom/fallback layer that may follow anything.
|
|
428
|
+
* @param parentLayerId
|
|
429
|
+
*/
|
|
430
|
+
allowedNextLayers(parentLayerId) {
|
|
431
|
+
const result = [];
|
|
432
|
+
const seen = new Set();
|
|
433
|
+
for (const producer of this.#producersOf(parentLayerId)) {
|
|
434
|
+
const prefix = `${producer.namespace}:`;
|
|
435
|
+
for (const [key, constructors] of this.#dispatchTable) {
|
|
436
|
+
if (!key.startsWith(prefix))
|
|
437
|
+
continue;
|
|
438
|
+
const raw = key.substring(prefix.length);
|
|
439
|
+
const value = producer.kind === 'uint' ? Number(raw) : raw;
|
|
440
|
+
for (const codecModuleConstructor of constructors) {
|
|
441
|
+
//Dedup by protocol id: a parent with two producers in one namespace (TCP's src+dst
|
|
442
|
+
//port) must not list the same child twice. The first producer encountered wins the
|
|
443
|
+
//discriminator hint (refining src-vs-dst direction is a later step).
|
|
444
|
+
if (seen.has(codecModuleConstructor.PROTOCOL_ID))
|
|
445
|
+
continue;
|
|
446
|
+
seen.add(codecModuleConstructor.PROTOCOL_ID);
|
|
447
|
+
result.push({ id: codecModuleConstructor.PROTOCOL_ID, name: codecModuleConstructor.PROTOCOL_NAME, discriminator: { field: producer.field, value: value } });
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
//Range-keyed children in this namespace: hint the low end of the range as the discriminator.
|
|
451
|
+
const ranges = this.#rangeTable.get(producer.namespace);
|
|
452
|
+
if (ranges) {
|
|
453
|
+
for (const range of ranges) {
|
|
454
|
+
if (seen.has(range.codecModuleConstructor.PROTOCOL_ID))
|
|
455
|
+
continue;
|
|
456
|
+
seen.add(range.codecModuleConstructor.PROTOCOL_ID);
|
|
457
|
+
result.push({ id: range.codecModuleConstructor.PROTOCOL_ID, name: range.codecModuleConstructor.PROTOCOL_NAME, discriminator: { field: producer.field, value: range.lo } });
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
result.push({ id: this.#rawDataCodec.PROTOCOL_ID, name: this.#rawDataCodec.PROTOCOL_NAME, discriminator: null });
|
|
462
|
+
return result;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* The {field,value} to set on `parentLayerId` so `childLayerId` follows it — used to auto-fill
|
|
466
|
+
* the parent discriminator when a child is added, and to suggest a fix for a consistency issue.
|
|
467
|
+
* Null when the child is not reachable from that parent via the demux graph (RawData, or a
|
|
468
|
+
* content-heuristic child such as TLS/IEC104 whose match is port/content based).
|
|
469
|
+
* @param parentLayerId
|
|
470
|
+
* @param childLayerId
|
|
471
|
+
*/
|
|
472
|
+
childDiscriminator(parentLayerId, childLayerId) {
|
|
473
|
+
for (const next of this.allowedNextLayers(parentLayerId)) {
|
|
474
|
+
if (next.id === childLayerId && next.discriminator)
|
|
475
|
+
return next.discriminator;
|
|
476
|
+
}
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Editor helper: report parent layers whose discriminator field does not point at the child that
|
|
481
|
+
* actually follows (e.g. eth.etherType says IPv6 but the next layer is IPv4). This is advisory
|
|
482
|
+
* only — encode never blocks on it, since a deliberately-inconsistent packet is a valid crafted
|
|
483
|
+
* packet. Only demux-based relationships are checked; content-heuristic children (TLS/IEC104) are
|
|
484
|
+
* not flagged. RawData may follow anything and is never flagged.
|
|
485
|
+
* @param decoded
|
|
486
|
+
*/
|
|
487
|
+
checkConsistency(decoded) {
|
|
488
|
+
const issues = [];
|
|
489
|
+
for (let i = 0; i < decoded.length - 1; i++) {
|
|
490
|
+
const parent = decoded[i];
|
|
491
|
+
const child = decoded[i + 1];
|
|
492
|
+
if (child.id === this.#rawDataCodec.PROTOCOL_ID)
|
|
493
|
+
continue;
|
|
494
|
+
//A content-heuristic child (no matchKeys, or heuristicFallback dual) is legitimately
|
|
495
|
+
//reachable off its well-known demux value (e.g. TLS on a non-443 port). Never flag it as
|
|
496
|
+
//inconsistent with the parent's discriminator — it is matched by content, not by the key.
|
|
497
|
+
if (this.#heuristicCodecs.some((codecModuleConstructor) => codecModuleConstructor.PROTOCOL_ID === child.id))
|
|
498
|
+
continue;
|
|
499
|
+
//A parent may expose several producers in one namespace (TCP's src+dst port). The child is
|
|
500
|
+
//consistent if ANY of them routes to it; only flag when NONE do. Report the first producer
|
|
501
|
+
//that actually carried a value as the representative.
|
|
502
|
+
const producers = this.#producersOf(parent.id);
|
|
503
|
+
let representative = undefined;
|
|
504
|
+
let reachable = false;
|
|
505
|
+
for (const producer of producers) {
|
|
506
|
+
const actual = parent.data[producer.field];
|
|
507
|
+
if (actual === undefined || actual === null)
|
|
508
|
+
continue;
|
|
509
|
+
if (!representative)
|
|
510
|
+
representative = { producer: producer, actual: actual };
|
|
511
|
+
const bucket = this.#dispatchTable.get(`${producer.namespace}:${this.#normalizeDemux(actual, producer.kind)}`);
|
|
512
|
+
if (bucket && bucket.some((codecModuleConstructor) => codecModuleConstructor.PROTOCOL_ID === child.id)) {
|
|
513
|
+
reachable = true;
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
const ranges = this.#rangeTable.get(producer.namespace);
|
|
517
|
+
if (ranges && Number.isInteger(Number(actual)) && ranges.some((range) => Number(actual) >= range.lo && Number(actual) <= range.hi && range.codecModuleConstructor.PROTOCOL_ID === child.id)) {
|
|
518
|
+
reachable = true;
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (reachable || !representative)
|
|
523
|
+
continue;
|
|
524
|
+
issues.push({
|
|
525
|
+
index: i,
|
|
526
|
+
parentId: parent.id,
|
|
527
|
+
childId: child.id,
|
|
528
|
+
field: representative.producer.field,
|
|
529
|
+
actual: representative.actual,
|
|
530
|
+
suggestion: this.childDiscriminator(parent.id, child.id),
|
|
531
|
+
message: `${parent.id}.${representative.producer.field}=${representative.actual} 与下一层 '${child.id}' 不符`
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
return issues;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Wireshark-style dissection: decode the packet with byte-range tracking on, then project each
|
|
538
|
+
* layer into a field tree carrying the value, the schema label, the exact packet bytes the field
|
|
539
|
+
* occupies, and an error/ok severity. A read-only view over the SAME decode — not a second
|
|
540
|
+
* parser. Normal decode() is untouched (ranges are collected only here).
|
|
541
|
+
* @param packet
|
|
542
|
+
*/
|
|
543
|
+
async dissect(packet) {
|
|
544
|
+
const codecData = { packet: packet, startPos: 0, postHandlers: [] };
|
|
545
|
+
const codecModules = [];
|
|
546
|
+
await this.#decode(codecData, codecModules, true);
|
|
547
|
+
const postDecodeHandlers = (0, ProcessPacketPostHandlers_1.ProcessPacketDecodePostHandlers)(codecData.postHandlers);
|
|
548
|
+
let postDecodeHandler = postDecodeHandlers.shift();
|
|
549
|
+
while (postDecodeHandler) {
|
|
550
|
+
await postDecodeHandler.handler();
|
|
551
|
+
postDecodeHandler = postDecodeHandlers.shift();
|
|
552
|
+
}
|
|
553
|
+
return codecModules.map((codecModule) => {
|
|
554
|
+
const schema = this.#codecSchemas.find((codecSchema) => codecSchema.id === codecModule.id);
|
|
555
|
+
const ranges = codecModule.getByteRanges() ? codecModule.getByteRanges() : new Map();
|
|
556
|
+
const errorPaths = new Set(codecModule.errors.map((e) => e.path));
|
|
557
|
+
return {
|
|
558
|
+
id: codecModule.id,
|
|
559
|
+
name: codecModule.name,
|
|
560
|
+
errors: codecModule.errors,
|
|
561
|
+
fields: this.#dissectFields(codecModule.instance.getValue(), schema ? schema.schema : undefined, '', ranges, errorPaths, packet)
|
|
562
|
+
};
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Recursively project a decoded value tree + its schema (for labels) + the collected byte ranges
|
|
567
|
+
* into dissection fields. Scalar leaves carry their byte span; objects/arrays nest as children.
|
|
568
|
+
* @private
|
|
569
|
+
*/
|
|
570
|
+
#dissectFields(data, schema, pathPrefix, ranges, errorPaths, packet) {
|
|
571
|
+
const fields = [];
|
|
572
|
+
if (data === null || typeof data !== 'object')
|
|
573
|
+
return fields;
|
|
574
|
+
const properties = schema ? schema.properties : undefined;
|
|
575
|
+
for (const key of Object.keys(data)) {
|
|
576
|
+
const node = properties ? properties[key] : undefined;
|
|
577
|
+
const value = data[key];
|
|
578
|
+
const path = pathPrefix ? `${pathPrefix}.${key}` : key;
|
|
579
|
+
const range = ranges.get(path);
|
|
580
|
+
const field = { name: key, severity: errorPaths.has(path) ? 'error' : 'ok' };
|
|
581
|
+
if (node && node.label)
|
|
582
|
+
field.label = node.label;
|
|
583
|
+
if (range) {
|
|
584
|
+
field.offset = range.offset;
|
|
585
|
+
field.length = range.length;
|
|
586
|
+
field.rawBytes = packet.subarray(range.offset, range.offset + range.length).toString('hex');
|
|
587
|
+
}
|
|
588
|
+
if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
|
|
589
|
+
field.children = this.#dissectFields(value, node, path, ranges, errorPaths, packet);
|
|
590
|
+
}
|
|
591
|
+
else if (Array.isArray(value)) {
|
|
592
|
+
field.children = value.map((item, index) => {
|
|
593
|
+
if (item !== null && typeof item === 'object') {
|
|
594
|
+
return { name: `${index}`, severity: 'ok', children: this.#dissectFields(item, node ? node.items : undefined, `${path}.${index}`, ranges, errorPaths, packet) };
|
|
595
|
+
}
|
|
596
|
+
return { name: `${index}`, severity: 'ok', value: item };
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
else {
|
|
600
|
+
field.value = value;
|
|
601
|
+
}
|
|
602
|
+
fields.push(field);
|
|
603
|
+
}
|
|
604
|
+
return fields;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* One-line human summary of a decoded packet (Wireshark's Info column). The innermost layer that
|
|
608
|
+
* declares a `summary` template in its schema wins (the most specific layer describes the packet);
|
|
609
|
+
* the template's ${dotted.field} placeholders are filled from that layer's decoded data. Falls back
|
|
610
|
+
* to the innermost non-raw layer's name when no template is declared. Read-only projection.
|
|
611
|
+
* @param decoded
|
|
612
|
+
*/
|
|
613
|
+
summary(decoded) {
|
|
614
|
+
for (let i = decoded.length - 1; i >= 0; i--) {
|
|
615
|
+
const schema = this.#codecSchemas.find((codecSchema) => codecSchema.id === decoded[i].id)?.schema;
|
|
616
|
+
if (schema && schema.summary)
|
|
617
|
+
return this.#renderSummary(schema.summary, decoded[i].data);
|
|
618
|
+
}
|
|
619
|
+
for (let i = decoded.length - 1; i >= 0; i--) {
|
|
620
|
+
if (decoded[i].id !== this.#rawDataCodec.PROTOCOL_ID)
|
|
621
|
+
return decoded[i].name;
|
|
622
|
+
}
|
|
623
|
+
return decoded.length ? decoded[decoded.length - 1].name : '';
|
|
624
|
+
}
|
|
625
|
+
#renderSummary(template, data) {
|
|
626
|
+
return template.replace(/\$\{([^}]+)\}/g, (_match, path) => {
|
|
627
|
+
const value = path.split('.').reduce((object, key) => (object == null ? undefined : object[key]), data);
|
|
628
|
+
return value === undefined || value === null ? '' : String(value);
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
exports.Codec = Codec;
|