Skip to content

Commit

Permalink
Parse DLT network-trace prefix for SOME/IP messages
Browse files Browse the repository at this point in the history
  • Loading branch information
kruss committed Oct 30, 2024
1 parent dfe317c commit a7c6283
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 7 deletions.
1 change: 1 addition & 0 deletions application/apps/indexer/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions application/apps/indexer/parsers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ lazy_static.workspace = true
log.workspace = true
regex.workspace = true
memchr = "2.4"
nom = "7.1"
serde = { workspace = true , features = ["derive"] }
thiserror.workspace = true
rand.workspace = true
Expand Down
7 changes: 6 additions & 1 deletion application/apps/indexer/parsers/src/dlt/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,12 @@ impl<'a> fmt::Display for FormattableMessage<'a> {
if let Some(slice) = slices.get(1) {
match SomeipParser::parse_message(self.fibex_someip_metadata, slice, None) {
Ok((_, message)) => {
return write!(f, "SOME/IP {:?}", message);
let prefix = slices.first().map_or_else(String::default, |s| {
SomeipParser::parse_prefix(s)
.ok()
.map_or_else(String::default, |p| format!("{} ", p.1))
});
return write!(f, "SOME/IP {}{:?}", prefix, message);
}
Err(error) => {
return write!(f, "SOME/IP '{}' {:02X?}", error, slice);
Expand Down
14 changes: 14 additions & 0 deletions application/apps/indexer/parsers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ pub enum Error {
Eof,
}

impl nom::error::ParseError<&[u8]> for Error {
fn from_error_kind(input: &[u8], kind: nom::error::ErrorKind) -> Self {
Error::Parse(format!(
"Nom error: {:?} ({} bytes left)",
kind,
input.len()
))
}

fn append(_: &[u8], _: nom::error::ErrorKind, other: Self) -> Self {
other
}
}

#[derive(Debug)]
pub enum ParseYield<T> {
Message(T),
Expand Down
121 changes: 121 additions & 0 deletions application/apps/indexer/parsers/src/someip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{
fmt::{self, Display},
io::Write,
iter,
net::Ipv4Addr,
path::PathBuf,
sync::Mutex,
};
Expand All @@ -17,6 +18,13 @@ use someip_payload::{
som::{SOMParser, SOMType},
};

use nom::{
combinator::map,
number::streaming::{be_u16, be_u32, be_u8},
sequence::tuple,
IResult,
};

use lazy_static::lazy_static;
use log::{debug, error};
use regex::Regex;
Expand Down Expand Up @@ -192,6 +200,44 @@ impl SomeipParser {
}
}

/// Parses a DLT Network-Trace prefix for a SOME/IP message from the given input.
///
/// A valid prefix will consist of:
/// - 4 bytes as IPv4 address
/// - 2 bytes as udp/tcp port
/// - 1 byte as protocol type (0 = local, 1 = tcp, 2 = udp)
/// - 1 byte as message direction (0 = incoming, 1 = outgoing)
/// - 1, 2 or 4 bytes as instance-id
pub(crate) fn parse_prefix(input: &[u8]) -> IResult<&[u8], std::string::String, Error> {
map(
tuple((be_u32, be_u16, be_u8, be_u8, Self::parse_instance)),
|(address, port, proto, direction, instance)| {
format!(
"{}:{}{} INST:{}{}",
Ipv4Addr::from(address),
port,
Direction::try_from(direction)
.ok()
.map_or_else(String::default, |s| format!(" {}", s)),
instance,
Proto::try_from(proto)
.ok()
.map_or_else(String::default, |s| format!(" {}", s))
)
},
)(input)
}

pub(crate) fn parse_instance(input: &[u8]) -> IResult<&[u8], usize, Error> {
match input.len() {
1 => map(be_u8, |i| i as usize)(input),
2 => map(be_u16, |i| i as usize)(input),
4 => map(be_u32, |i| i as usize)(input),
_ => Err(nom::Err::Error(Error::Incomplete)),
}
}

/// Parses a SOME/IP message (header and payload) from the given input.
pub(crate) fn parse_message(
fibex_metadata: Option<&FibexMetadata>,
input: &[u8],
Expand Down Expand Up @@ -272,6 +318,61 @@ impl SomeipParser {
}
}

enum Proto {
Local,
Tcp,
Udp,
}

impl Display for Proto {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Proto::Local => write!(f, "LOCAL"),
Proto::Tcp => write!(f, "TCP"),
Proto::Udp => write!(f, "UDP"),
}
}
}

impl TryFrom<u8> for Proto {
type Error = ();

fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Proto::Local),
1 => Ok(Proto::Tcp),
2 => Ok(Proto::Udp),
_ => Err(()),
}
}
}

enum Direction {
Incoming,
Outgoing,
}

impl Display for Direction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Direction::Incoming => write!(f, "<<"),
Direction::Outgoing => write!(f, ">>"),
}
}
}

impl TryFrom<u8> for Direction {
type Error = ();

fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Direction::Incoming),
1 => Ok(Direction::Outgoing),
_ => Err(()),
}
}
}

unsafe impl Send for SomeipParser {}
unsafe impl Sync for SomeipParser {}

Expand Down Expand Up @@ -1015,4 +1116,24 @@ mod test {
assert!(meta_data.get_service(213, 1).is_none());
assert!(meta_data.get_service(321, 1).is_some());
}

#[test]
fn test_parse_prefix() {
let input = [0x7F, 0x00, 0x00, 0x01, 0x30, 0x39, 0x01, 0x00, 0x01];
let result = SomeipParser::parse_prefix(&input).expect("prefix");
assert_eq!("127.0.0.1:12345 << INST:1 TCP", result.1);

let input = [0x7F, 0x00, 0x00, 0x01, 0x30, 0x39, 0x02, 0x01, 0x00, 0x01];
let result = SomeipParser::parse_prefix(&input).expect("prefix");
assert_eq!("127.0.0.1:12345 >> INST:1 UDP", result.1);

let input = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01,
];
let result = SomeipParser::parse_prefix(&input).expect("prefix");
assert_eq!("0.0.0.0:0 INST:1", result.1);

let input = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
assert!(SomeipParser::parse_prefix(&input).is_err())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ describe('Observe', function () {
expect(result.length).toEqual(6);
expect(result[0].content.split('\u0004')).toEqual([
'2024-02-20T13:17:26.713537000Z', 'ECU1', '1', '571', '204', '28138506', 'ECU1', 'APP1', 'C1', 'IPC',
'SOME/IP RPC SERV:123 METH:32773 LENG:16 CLID:0 SEID:58252 IVER:1 MSTP:2 RETC:0 [00, 00, 01, 88, 01, C3, C4, 1D]',
'SOME/IP 0.0.0.0:0 >> INST:1 RPC SERV:123 METH:32773 LENG:16 CLID:0 SEID:58252 IVER:1 MSTP:2 RETC:0 [00, 00, 01, 88, 01, C3, C4, 1D]',
]);
expect(result[5].content.split('\u0004')).toEqual([
'2024-02-20T13:17:26.713537000Z', 'ECU1', '1', '571', '209', '28138506', 'ECU1', 'APP1', 'C1', 'IPC',
Expand Down Expand Up @@ -692,23 +692,23 @@ describe('Observe', function () {
expect(result.length).toEqual(6);
expect(result[0].content.split('\u0004')).toEqual([
'2024-02-20T13:17:26.713537000Z', 'ECU1', '1', '571', '204', '28138506', 'ECU1', 'APP1', 'C1', 'IPC',
'SOME/IP RPC SERV:123 METH:32773 LENG:16 CLID:0 SEID:58252 IVER:1 MSTP:2 RETC:0 TestService::timeEvent {\u0006\ttimestamp (INT64) : 1683656786973,\u0006}',
'SOME/IP 0.0.0.0:0 >> INST:1 RPC SERV:123 METH:32773 LENG:16 CLID:0 SEID:58252 IVER:1 MSTP:2 RETC:0 TestService::timeEvent {\u0006\ttimestamp (INT64) : 1683656786973,\u0006}',
]);
expect(result[1].content.split('\u0004')).toEqual([
'2024-02-20T13:17:26.713537000Z', 'ECU1', '1', '571', '205', '28138506', 'ECU1', 'APP1', 'C1', 'IPC',
'SOME/IP RPC SERV:124 METH:32773 LENG:16 CLID:0 SEID:58252 IVER:1 MSTP:2 RETC:0 UnknownService [00, 00, 01, 88, 01, C3, C4, 1D]',
'SOME/IP 0.0.0.0:0 >> INST:1 RPC SERV:124 METH:32773 LENG:16 CLID:0 SEID:58252 IVER:1 MSTP:2 RETC:0 UnknownService [00, 00, 01, 88, 01, C3, C4, 1D]',
]);
expect(result[2].content.split('\u0004')).toEqual([
'2024-02-20T13:17:26.713537000Z', 'ECU1', '1', '571', '206', '28138506', 'ECU1', 'APP1', 'C1', 'IPC',
'SOME/IP RPC SERV:123 METH:32773 LENG:16 CLID:0 SEID:58252 IVER:3 MSTP:2 RETC:0 TestService<1?>::timeEvent {\u0006\ttimestamp (INT64) : 1683656786973,\u0006}',
'SOME/IP 0.0.0.0:0 >> INST:1 RPC SERV:123 METH:32773 LENG:16 CLID:0 SEID:58252 IVER:3 MSTP:2 RETC:0 TestService<1?>::timeEvent {\u0006\ttimestamp (INT64) : 1683656786973,\u0006}',
]);
expect(result[3].content.split('\u0004')).toEqual([
'2024-02-20T13:17:26.713537000Z', 'ECU1', '1', '571', '207', '28138506', 'ECU1', 'APP1', 'C1', 'IPC',
'SOME/IP RPC SERV:123 METH:32774 LENG:16 CLID:0 SEID:58252 IVER:1 MSTP:2 RETC:0 TestService::UnknownMethod [00, 00, 01, 88, 01, C3, C4, 1D]',
'SOME/IP 0.0.0.0:0 >> INST:1 RPC SERV:123 METH:32774 LENG:16 CLID:0 SEID:58252 IVER:1 MSTP:2 RETC:0 TestService::UnknownMethod [00, 00, 01, 88, 01, C3, C4, 1D]',
]);
expect(result[4].content.split('\u0004')).toEqual([
'2024-02-20T13:17:26.713537000Z', 'ECU1', '1', '571', '208', '28138506', 'ECU1', 'APP1', 'C1', 'IPC',
'SOME/IP RPC SERV:123 METH:32773 LENG:15 CLID:0 SEID:58252 IVER:1 MSTP:2 RETC:0 TestService::timeEvent \'SOME/IP Error: Parser exhausted at offset 0 for Object size 8\' [00, 00, 01, 88, 01, C3, C4]',
'SOME/IP 0.0.0.0:0 >> INST:1 RPC SERV:123 METH:32773 LENG:15 CLID:0 SEID:58252 IVER:1 MSTP:2 RETC:0 TestService::timeEvent \'SOME/IP Error: Parser exhausted at offset 0 for Object size 8\' [00, 00, 01, 88, 01, C3, C4]',
]);
expect(result[5].content.split('\u0004')).toEqual([
'2024-02-20T13:17:26.713537000Z', 'ECU1', '1', '571', '209', '28138506', 'ECU1', 'APP1', 'C1', 'IPC',
Expand Down

0 comments on commit a7c6283

Please sign in to comment.