From ba314c1508ae0e7a29af55d9ddf1c636b1d0ec3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Rx?= Date: Tue, 10 Dec 2024 16:25:27 +0100 Subject: [PATCH] less allocations in parse_svcb_ip (#41) --- src/decoders/dns.rs | 62 ++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/decoders/dns.rs b/src/decoders/dns.rs index a6b0334..7a02083 100644 --- a/src/decoders/dns.rs +++ b/src/decoders/dns.rs @@ -14,8 +14,8 @@ use byteorder::{BigEndian, WriteBytesExt}; use log::{error, warn}; use nom::{ bytes::complete::take, - combinator::{fail, map, map_parser, verify}, - multi::{fold_many0, many0}, + combinator::{fail, iterator, map, map_parser, verify}, + multi::fold_many0, number::complete::{be_u128, be_u16, be_u32, be_u8, le_u32}, sequence::tuple, IResult, @@ -227,46 +227,46 @@ fn parse_svcb_alpn(mut input: &[u8]) -> nom::IResult<&[u8], String> { } /// Parse the IPs -fn parse_svcb_ip(data: &[u8]) -> nom::IResult<&[u8], String> { +fn parse_svcb_ip(mut input: &[u8]) -> nom::IResult<&[u8], String> { const IPV4: u16 = 4; const IPV6: u16 = 6; - let mut dns_data = data; + let ipv4_parser = || map(be_u32, Ipv4Addr::from); + let ipv6_parser = || map(be_u128, Ipv6Addr::from); - let mut ipv4_addrs = vec![]; - let mut ipv6_addrs = vec![]; + let mut ipv4s = String::with_capacity(2 * 16); // let's reserve max space for 2 IPV4 addresses + let mut ipv6s = String::with_capacity(2 * 40); // let's reserve max space for 2 IPV6 addresses // IPs can either be IPv4 or/and IPv6 - while !dns_data.is_empty() { - let (remaining_dns_data, (ip_version, ip_size)) = - tuple((verify(be_u16, |val| *val == IPV4 || *val == IPV6), be_u16))(dns_data)?; - - let (remaining_dns_data, ip_data) = take(ip_size)(remaining_dns_data)?; - - dns_data = remaining_dns_data; + while !input.is_empty() { + let (i, ip_version) = verify(be_u16, |val| *val == IPV4 || *val == IPV6)(input)?; + let (i, ip_size) = be_u16(i)?; + let (i, ip_data) = take(ip_size)(i)?; + input = i; - // There can be multiple IPs - match ip_version { - IPV4 => { - let (_, mut addrs) = - many0(map(be_u32, |raw| Ipv4Addr::from(raw).to_string()))(ip_data)?; - ipv4_addrs.append(&mut addrs); + if ip_version == IPV4 { + let mut iter = iterator(ip_data, ipv4_parser()); + for ip in iter.into_iter() { + if !ipv4s.is_empty() { + ipv4s.push(','); + } + write!(ipv4s, "{}", ip).ok(); // ignore errors on write in String } - IPV6 => { - let (_, mut addrs) = - many0(map(be_u128, |raw| Ipv6Addr::from(raw).to_string()))(ip_data)?; - ipv6_addrs.append(&mut addrs); + iter.finish()?; + } else if ip_version == IPV6 { + let mut iter = iterator(ip_data, ipv6_parser()); + for ip in iter.into_iter() { + if !ipv6s.is_empty() { + ipv6s.push(','); + } + write!(ipv6s, "{}", ip).ok(); // ignore errors on write in String } - _ => {} - }; + iter.finish()?; + } } - let message = format!( - "ipv4 hint:{}, ipv6 hint:{}", - ipv4_addrs.join(","), - ipv6_addrs.join(",") - ); - Ok((dns_data, message)) + let message = format!("ipv4 hint:{ipv4s}, ipv6 hint:{ipv6s}"); + Ok((input, message)) } /// Get the MAC Address from the log data