use alloc::string::String;
use alloc::vec::Vec;
use core::net::IpAddr;
use winnow::ModalResult as PResult;
use winnow::combinator::{alt, cut_err, opt};
use winnow::prelude::*;
use crate::ast::*;
use crate::lexer::Token;
use super::{
Stream, l2, l3, l4, l7, parse_hex_payload, parse_mac, parse_string_lit, parse_u8, parse_u16,
parse_u32, snmp, tag,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum ParsedField<'a> {
SrcPort(u16, (usize, usize)),
DstPort(u16, (usize, usize)),
Seq(u32, (usize, usize)),
AckNum(u32, (usize, usize)),
Win(u16, (usize, usize)),
Payload(String, (usize, usize)),
HexPayload(Vec<u8>, (usize, usize)),
Community(&'a str, (usize, usize)),
User(&'a str, (usize, usize)),
SysUpTime(u32, (usize, usize)),
PduType(SnmpPduType, (usize, usize)),
Wait(u64, (usize, usize)),
Oid(&'a str, (usize, usize)),
Flag(TcpFlag, (usize, usize)),
Enterprise(&'a str, (usize, usize)),
AgentIp(IpAddr, (usize, usize)),
GenTrap(u32, (usize, usize)),
SpecTrap(u32, (usize, usize)),
EngineId(&'a str, (usize, usize)),
EngineBoots(u32, (usize, usize)),
EngineTime(u32, (usize, usize)),
ContextName(&'a str, (usize, usize)),
Auth(SnmpAuthType, &'a str, (usize, usize)),
Priv(SnmpPrivType, &'a str, (usize, usize)),
VarBind(VarBindAst<'a>, (usize, usize)),
NonRepeaters(u32, (usize, usize)),
MaxRepetitions(u32, (usize, usize)),
ReqId(u32, (usize, usize)),
Vlan(u32, (usize, usize)),
Dscp(u32, (usize, usize)),
Ecn(u32, (usize, usize)),
Ttl(u32, (usize, usize)),
FlowLabel(u32, (usize, usize)),
Protocol(Protocol, (usize, usize)),
Pcp(u8, (usize, usize)),
Dei(u8, (usize, usize)),
Qinq(u16, (usize, usize)),
InnerVlan(u16, (usize, usize)),
Mpls(u32, (usize, usize)),
Exp(u8, (usize, usize)),
Bos(u8, (usize, usize)),
MplsTtl(u8, (usize, usize)),
SrcMac([u8; 6], (usize, usize)),
DstMac([u8; 6], (usize, usize)),
EtherType(u16, (usize, usize)),
IpId(u16, (usize, usize)),
Df((usize, usize)),
Mf((usize, usize)),
FragOffset(u16, (usize, usize)),
Transport(TransportProto, (usize, usize)),
Urgent(u16, (usize, usize)),
Mss(u16, (usize, usize)),
Wscale(u8, (usize, usize)),
SackPerm((usize, usize)),
Tsval(u32, (usize, usize)),
Tsecr(u32, (usize, usize)),
Vtag(u32, (usize, usize)),
Stream(u16, (usize, usize)),
Ssn(u16, (usize, usize)),
Ppid(u32, (usize, usize)),
Chunk(String, (usize, usize)),
ArpOpcode(ArpOpcode, (usize, usize)),
Gratuitous((usize, usize)),
Sha([u8; 6], (usize, usize)),
Spa(IpAddr, (usize, usize)),
Tha([u8; 6], (usize, usize)),
Tpa(IpAddr, (usize, usize)),
ChassisId(&'a str, (usize, usize)),
PortIdVal(Option<&'a str>, Option<u16>, (usize, usize)),
SysName(&'a str, (usize, usize)),
SysDesc(&'a str, (usize, usize)),
RootId(&'a str, (usize, usize)),
BridgeId(&'a str, (usize, usize)),
Cost(u32, (usize, usize)),
MaxAge(u16, (usize, usize)),
HelloTime(u16, (usize, usize)),
ForwardDelay(u16, (usize, usize)),
Rstp((usize, usize)),
FlagsByte(u8, (usize, usize)),
ActorSys([u8; 6], (usize, usize)),
ActorKey(u16, (usize, usize)),
ActorPort(u16, (usize, usize)),
PartnerSys([u8; 6], (usize, usize)),
PartnerKey(u16, (usize, usize)),
PartnerPort(u16, (usize, usize)),
ActorState(u8, (usize, usize)),
PartnerState(u8, (usize, usize)),
VersionByte(u8, (usize, usize)),
EapolType(EapolType, (usize, usize)),
EapCode(u8, (usize, usize)),
EapId(u8, (usize, usize)),
EapMethod(u8, (usize, usize)),
Identity(&'a str, (usize, usize)),
IcmpTypeChoice(IcmpTypeChoice, (usize, usize)),
IcmpId(u16, (usize, usize)),
Gateway(IpAddr, (usize, usize)),
NdpType(NdpType, (usize, usize)),
TargetVal(Option<IpAddr>, Option<[u8; 6]>, (usize, usize)),
Slla([u8; 6], (usize, usize)),
Tlla([u8; 6], (usize, usize)),
RouterLifetime(u16, (usize, usize)),
IgmpType(IgmpType, (usize, usize)),
GroupVal(Option<IpAddr>, Option<u8>, (usize, usize)),
MaxResp(u8, (usize, usize)),
MldType(MldType, (usize, usize)),
MulticastAddr(IpAddr, (usize, usize)),
MaxRespDelay(u16, (usize, usize)),
GreKey(u32, (usize, usize)),
GreSeq(u32, (usize, usize)),
GreProto(u16, (usize, usize)),
ChecksumFlag((usize, usize)),
Vni(u32, (usize, usize)),
OptClass(u16, (usize, usize)),
OptType(u8, (usize, usize)),
ProtocolType(u16, (usize, usize)),
Spi(u32, (usize, usize)),
Iv(Vec<u8>, (usize, usize)),
Icv(Vec<u8>, (usize, usize)),
NextHeader(u8, (usize, usize)),
InitiatorSpi(u64, (usize, usize)),
ResponderSpi(u64, (usize, usize)),
IkeExchange(IkeExchange, (usize, usize)),
MsgId(u32, (usize, usize)),
NextPayload(u8, (usize, usize)),
WireguardType(WireguardType, (usize, usize)),
Sender(u32, (usize, usize)),
Receiver(u32, (usize, usize)),
Counter(u64, (usize, usize)),
OspfType(OspfType, (usize, usize)),
HelloWord((usize, usize)),
RouterId(IpAddr, (usize, usize)),
AreaId(u32, (usize, usize)),
HelloInterval(u16, (usize, usize)),
DeadInterval(u32, (usize, usize)),
PriorityVal(u16, (usize, usize)),
BgpType(BgpType, (usize, usize)),
Asn(u32, (usize, usize)),
HoldTime(u16, (usize, usize)),
BgpId(IpAddr, (usize, usize)),
PrefixVal(Option<IpAddr>, Option<&'a str>, (usize, usize)),
NextHop(IpAddr, (usize, usize)),
Metric(u32, (usize, usize)),
TagVal(Option<u16>, Option<&'a str>, (usize, usize)),
Vrid(u8, (usize, usize)),
AdvInt(u16, (usize, usize)),
Vip(IpAddr, (usize, usize)),
HsrpState(u8, (usize, usize)),
HelloTimeHsrp(u8, (usize, usize)),
PimJoinPrune((usize, usize)),
PimRegister((usize, usize)),
SourceIp(IpAddr, (usize, usize)),
Rp(IpAddr, (usize, usize)),
DrPriority(u32, (usize, usize)),
Diag(u8, (usize, usize)),
MyDisc(u32, (usize, usize)),
YourDisc(u32, (usize, usize)),
MinTx(u32, (usize, usize)),
MinRx(u32, (usize, usize)),
Mult(u8, (usize, usize)),
OpenflowType(OpenflowType, (usize, usize)),
Xid(u32, (usize, usize)),
Dpid(u64, (usize, usize)),
TableId(u8, (usize, usize)),
L7StringField(&'static str, &'a str, (usize, usize)),
L7U32Field(&'static str, u32, (usize, usize)),
L7U64Field(&'static str, u64, (usize, usize)),
L7IpField(&'static str, IpAddr, (usize, usize)),
L7MacField(&'static str, [u8; 6], (usize, usize)),
L7Flag(&'static str, (usize, usize)),
L7Header(&'a str, &'a str, (usize, usize)),
}
pub(crate) fn parse_wait<'i, 'a>(input: &mut Stream<'i, 'a>) -> PResult<ParsedField<'a>> {
let (_, wait_kw_span) = tag(Token::Wait).parse_next(input)?;
let val = cut_err(parse_u32).parse_next(input)?;
let suffix = cut_err(alt((
tag(Token::Ns).value(1_u64),
tag(Token::Us).value(1_000_u64),
tag(Token::Ms).value(1_000_000_u64),
tag(Token::Sec).value(1_000_000_000_u64),
tag(Token::Min).value(60_000_000_000_u64),
)))
.parse_next(input)?;
let end_offset = if let Some(last_tok) = input.first() {
last_tok.1.start
} else {
wait_kw_span.end
};
Ok(ParsedField::Wait(
val as u64 * suffix,
(wait_kw_span.start, end_offset - wait_kw_span.start),
))
}
pub(crate) fn parse_payload<'i, 'a>(input: &mut Stream<'i, 'a>) -> PResult<ParsedField<'a>> {
let ((_, s), v) = (tag(Token::Payload), cut_err(parse_string_lit)).parse_next(input)?;
Ok(ParsedField::Payload(v, (s.start, s.end - s.start)))
}
pub(crate) fn parse_hex_payload_field<'i, 'a>(input: &mut Stream<'i, 'a>) -> PResult<ParsedField<'a>> {
let ((_, s), v) = (tag(Token::HexPayload), cut_err(parse_hex_payload)).parse_next(input)?;
Ok(ParsedField::HexPayload(v, (s.start, s.end - s.start)))
}
pub(crate) fn parse_universal_field<'i, 'a>(
input: &mut Stream<'i, 'a>,
current_protocol: Option<&Protocol>,
) -> PResult<ParsedField<'a>> {
if matches!(
current_protocol,
Some(Protocol::Coap | Protocol::Dhcp | Protocol::Tftp | Protocol::Sip)
) && let Some((tok, _)) = input.first()
&& matches!(tok, Token::Ack | Token::Rst)
{
return Err(winnow::error::ErrMode::Backtrack(
winnow::error::ContextError::new(),
));
}
alt((
alt((
parse_wait,
parse_payload,
parse_hex_payload_field,
(tag(Token::SrcMac), cut_err(parse_mac))
.map(|((_, s), v)| ParsedField::SrcMac(v, (s.start, s.end - s.start))),
(tag(Token::DstMac), cut_err(parse_mac))
.map(|((_, s), v)| ParsedField::DstMac(v, (s.start, s.end - s.start))),
(tag(Token::EtherType), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::EtherType(v, (s.start, s.end - s.start))),
(tag(Token::Vlan), opt(parse_u32))
.map(|((_, s), v)| ParsedField::Vlan(v.unwrap_or(1), (s.start, s.end - s.start))),
(tag(Token::Pcp), cut_err(parse_u8))
.map(|((_, s), v)| ParsedField::Pcp(v, (s.start, s.end - s.start))),
(tag(Token::Dei), cut_err(parse_u8))
.map(|((_, s), v)| ParsedField::Dei(v, (s.start, s.end - s.start))),
)),
alt((
(tag(Token::Qinq), opt(parse_u16))
.map(|((_, s), v)| ParsedField::Qinq(v.unwrap_or(1), (s.start, s.end - s.start))),
(tag(Token::InnerVlan), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::InnerVlan(v, (s.start, s.end - s.start))),
(tag(Token::Mpls), opt(parse_u32))
.map(|((_, s), v)| ParsedField::Mpls(v.unwrap_or(0), (s.start, s.end - s.start))),
(tag(Token::Exp), cut_err(parse_u8))
.map(|((_, s), v)| ParsedField::Exp(v, (s.start, s.end - s.start))),
(tag(Token::Bos), cut_err(parse_u8))
.map(|((_, s), v)| ParsedField::Bos(v, (s.start, s.end - s.start))),
(tag(Token::MplsTtl), cut_err(parse_u8))
.map(|((_, s), v)| ParsedField::MplsTtl(v, (s.start, s.end - s.start))),
)),
alt((
(tag(Token::Dscp), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::Dscp(v, (s.start, s.end - s.start))),
(tag(Token::Ecn), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::Ecn(v, (s.start, s.end - s.start))),
(tag(Token::Ttl), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::Ttl(v, (s.start, s.end - s.start))),
(tag(Token::FlowLabel), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::FlowLabel(v, (s.start, s.end - s.start))),
(tag(Token::IpId), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::IpId(v, (s.start, s.end - s.start))),
tag(Token::Df).map(|(_, s)| ParsedField::Df((s.start, s.len()))),
tag(Token::Mf).map(|(_, s)| ParsedField::Mf((s.start, s.len()))),
(tag(Token::FragOffset), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::FragOffset(v, (s.start, s.end - s.start))),
(tag(Token::NextHeader), cut_err(parse_u8))
.map(|((_, s), v)| ParsedField::NextHeader(v, (s.start, s.end - s.start))),
)),
alt((
(tag(Token::SrcPort), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::SrcPort(v, (s.start, s.end - s.start))),
(tag(Token::DstPort), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::DstPort(v, (s.start, s.end - s.start))),
(
tag(Token::Transport),
cut_err(alt((
tag(Token::Tcp).value(TransportProto::Tcp),
tag(Token::Udp).value(TransportProto::Udp),
))),
)
.map(|((_, s), v)| ParsedField::Transport(v, (s.start, s.end - s.start))),
(tag(Token::Seq), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::Seq(v, (s.start, s.end - s.start))),
(tag(Token::AckNum), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::AckNum(v, (s.start, s.end - s.start))),
(tag(Token::Win), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::Win(v, (s.start, s.end - s.start))),
(tag(Token::Window), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::Win(v, (s.start, s.end - s.start))),
(tag(Token::Urgent), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::Urgent(v, (s.start, s.end - s.start))),
)),
alt((
(tag(Token::Mss), cut_err(parse_u16))
.map(|((_, s), v)| ParsedField::Mss(v, (s.start, s.end - s.start))),
(tag(Token::Wscale), cut_err(parse_u8))
.map(|((_, s), v)| ParsedField::Wscale(v, (s.start, s.end - s.start))),
tag(Token::SackPerm).map(|(_, s)| ParsedField::SackPerm((s.start, s.len()))),
(tag(Token::Tsval), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::Tsval(v, (s.start, s.end - s.start))),
(tag(Token::Tsecr), cut_err(parse_u32))
.map(|((_, s), v)| ParsedField::Tsecr(v, (s.start, s.end - s.start))),
)),
alt((
tag(Token::Syn).map(|(_, s)| ParsedField::Flag(TcpFlag::Syn, (s.start, s.len()))),
tag(Token::Ack).map(|(_, s)| ParsedField::Flag(TcpFlag::Ack, (s.start, s.len()))),
tag(Token::Fin).map(|(_, s)| ParsedField::Flag(TcpFlag::Fin, (s.start, s.len()))),
tag(Token::Rst).map(|(_, s)| ParsedField::Flag(TcpFlag::Rst, (s.start, s.len()))),
tag(Token::Psh).map(|(_, s)| ParsedField::Flag(TcpFlag::Psh, (s.start, s.len()))),
tag(Token::Urg).map(|(_, s)| ParsedField::Flag(TcpFlag::Urg, (s.start, s.len()))),
tag(Token::Ece).map(|(_, s)| ParsedField::Flag(TcpFlag::Ece, (s.start, s.len()))),
tag(Token::Cwr).map(|(_, s)| ParsedField::Flag(TcpFlag::Cwr, (s.start, s.len()))),
)),
))
.parse_next(input)
}
pub(crate) fn dispatch_protocol_field<'i, 'a>(
proto: &Protocol,
input: &mut Stream<'i, 'a>,
) -> PResult<ParsedField<'a>> {
match proto {
Protocol::Arp => l2::parse_arp_field(input),
Protocol::Vlan => l2::parse_vlan_field(input),
Protocol::Qinq => l2::parse_qinq_field(input),
Protocol::Mpls => l2::parse_mpls_field(input),
Protocol::Lldp => l2::parse_lldp_field(input),
Protocol::Stp => l2::parse_stp_field(input),
Protocol::Lacp => l2::parse_lacp_field(input),
Protocol::Eapol => l2::parse_eapol_field(input),
Protocol::Icmp => l3::parse_icmp_field(input),
Protocol::Ndp => l3::parse_ndp_field(input),
Protocol::Igmp => l3::parse_igmp_field(input),
Protocol::Mld => l3::parse_mld_field(input),
Protocol::Gre => l3::parse_gre_field(input),
Protocol::Vxlan => l3::parse_vxlan_field(input),
Protocol::Geneve => l3::parse_geneve_field(input),
Protocol::Ipsec => l3::parse_ipsec_field(input),
Protocol::Esp => alt((l3::parse_esp_field, l3::parse_ipsec_field)).parse_next(input),
Protocol::Ah => alt((l3::parse_ah_field, l3::parse_ipsec_field)).parse_next(input),
Protocol::Ikev2 => l3::parse_ikev2_field(input),
Protocol::Wireguard => l3::parse_wireguard_field(input),
Protocol::Ospf => l3::parse_ospf_field(input),
Protocol::Bgp => l3::parse_bgp_field(input),
Protocol::Rip => l3::parse_rip_field(input),
Protocol::Vrrp => l3::parse_vrrp_field(input),
Protocol::Hsrp => l3::parse_hsrp_field(input),
Protocol::Pim => l3::parse_pim_field(input),
Protocol::Bfd => l3::parse_bfd_field(input),
Protocol::Openflow => l3::parse_openflow_field(input),
Protocol::Tcp => l4::parse_tcp_field(input),
Protocol::Udp => l4::parse_udp_field(input),
Protocol::Sctp => l4::parse_sctp_field(input),
Protocol::Snmp1 | Protocol::Snmp2 | Protocol::Snmp3 => snmp::parse_snmp_field(input),
Protocol::Amqp => l7::parse_amqp_field(input),
Protocol::Bacnet => l7::parse_bacnet_field(input),
Protocol::Coap => l7::parse_coap_field(input),
Protocol::Dhcp => l7::parse_dhcp_field(input),
Protocol::Dnp3 => l7::parse_dnp3_field(input),
Protocol::Dns => l7::parse_dns_field(input),
Protocol::Ethernetip => l7::parse_ethernetip_field(input),
Protocol::Ftp => l7::parse_ftp_field(input),
Protocol::Grpc => l7::parse_grpc_field(input),
Protocol::Http => l7::parse_http_field(input),
Protocol::Http2 => l7::parse_http2_field(input),
Protocol::Imap => l7::parse_imap_field(input),
Protocol::Ipfix => l7::parse_ipfix_field(input),
Protocol::Kerberos => l7::parse_kerberos_field(input),
Protocol::Ldap => l7::parse_ldap_field(input),
Protocol::Mdns => l7::parse_mdns_field(input),
Protocol::Memcached => l7::parse_memcached_field(input),
Protocol::Modbus => l7::parse_modbus_field(input),
Protocol::Mqtt => l7::parse_mqtt_field(input),
Protocol::Mysql => l7::parse_mysql_field(input),
Protocol::Netflow => l7::parse_netflow_field(input),
Protocol::Nfs => l7::parse_nfs_field(input),
Protocol::Ntp => l7::parse_ntp_field(input),
Protocol::Opcua => l7::parse_opcua_field(input),
Protocol::Pop3 => l7::parse_pop3_field(input),
Protocol::Postgres => l7::parse_postgres_field(input),
Protocol::Ptp => l7::parse_ptp_field(input),
Protocol::Quic => l7::parse_quic_field(input),
Protocol::Radius => l7::parse_radius_field(input),
Protocol::Redis => l7::parse_redis_field(input),
Protocol::Rtp => l7::parse_rtp_field(input),
Protocol::Rtsp => l7::parse_rtsp_field(input),
Protocol::S7comm => l7::parse_s7comm_field(input),
Protocol::Sflow => l7::parse_sflow_field(input),
Protocol::Sip => l7::parse_sip_field(input),
Protocol::Smb => l7::parse_smb_field(input),
Protocol::Smtp => l7::parse_smtp_field(input),
Protocol::Ssdp => l7::parse_ssdp_field(input),
Protocol::Ssh => l7::parse_ssh_field(input),
Protocol::Stun => l7::parse_stun_field(input),
Protocol::Syslog => l7::parse_syslog_field(input),
Protocol::Tacacs => l7::parse_tacacs_field(input),
Protocol::Telnet => l7::parse_telnet_field(input),
Protocol::Tftp => l7::parse_tftp_field(input),
Protocol::Tls => l7::parse_tls_field(input),
Protocol::Websocket => l7::parse_websocket_field(input),
Protocol::Whois => l7::parse_whois_field(input),
}
}
pub(crate) fn parse_fallback_field<'i, 'a>(input: &mut Stream<'i, 'a>) -> PResult<ParsedField<'a>> {
alt((
l2::parse_l2_field,
l3::parse_l3_field,
l4::parse_l4_field,
snmp::parse_snmp_field,
l7::parse_l7_field,
))
.parse_next(input)
}