tramex_tools/interface/parser/
parser_gtpu.rs

1//! Parser for GTPU traces
2use super::ParsingError;
3use super::hex_extractor::extract_binary_from_lines;
4use crate::data::{AdditionalInfos, Trace};
5use crate::interface::association::TraceRelation;
6use std::str::FromStr;
7
8use crate::interface::{layer::Layer, types::Direction};
9
10use super::FileParser;
11
12#[derive(Debug, Clone)]
13/// Data structure to store the GTPU message type
14pub struct GTPUInfos {
15    /// Direction of the message (TO/FROM)
16    pub direction: Direction,
17
18    /// Message type (e.g., "G-PDU", "Echo Request")
19    pub message_type: String,
20
21    /// Connection info (e.g., "127.0.1.100:2152")
22    pub connection_info: Option<String>,
23}
24
25/// GTPU Parser
26pub struct GTPUParser;
27
28impl GTPUParser {
29    /// Function that parses the remaining lines of a log
30    fn parse_lines(lines: &[String]) -> Vec<String> {
31        lines.to_vec()
32    }
33}
34
35impl FileParser for GTPUParser {
36    fn parse_additional_infos(lines: &[String]) -> Result<AdditionalInfos, ParsingError> {
37        let line = &lines[0];
38        let parts: Vec<&str> = line.split_whitespace().collect();
39
40        // Example: "13:20:45.574 [GTPU] TO 127.0.1.100:2152 G-PDU TEID=0x5315caa3 QFI=1 SDU_len=1452: IP/TCP ..."
41        // Parts: ["13:20:45.574", "[GTPU]", "TO", "127.0.1.100:2152", "G-PDU", ...]
42        if parts.len() < 5 {
43            return Err(ParsingError::new(
44                "Could not find enough (5) parameters for GTPU".to_string(),
45                1,
46            ));
47        }
48
49        let direction_result = Direction::from_str(parts[2]);
50        let direction = match direction_result {
51            Ok(d) => d,
52            Err(_) => {
53                return Err(ParsingError::new(
54                    format!("The direction could not be parsed in the part {:?} of {}", parts[2], line),
55                    1,
56                ));
57            }
58        };
59
60        // Connection info is typically at parts[3] (IP:port)
61        let connection_info = if parts.len() > 3 && parts[3].contains(':') {
62            Some(parts[3].to_string())
63        } else {
64            None
65        };
66
67        // Message type is at parts[4] (e.g., "G-PDU")
68        let message_type = parts.get(4).unwrap_or(&"Unknown").to_string();
69
70        Ok(AdditionalInfos::GTPUInfos(GTPUInfos {
71            direction,
72            message_type,
73            connection_info,
74        }))
75    }
76
77    fn parse(lines: &[String]) -> Result<Trace, ParsingError> {
78        let additional_infos = match Self::parse_additional_infos(lines) {
79            Ok(m) => m,
80            Err(e) => {
81                return Err(e);
82            }
83        };
84
85        let text = Self::parse_lines(lines);
86
87        let binary = extract_binary_from_lines(lines);
88
89        // Parse timestamp from first line
90        let timestamp = if let Some(first_line) = lines.first() {
91            super::parse_timestamp(first_line)?
92        } else {
93            0
94        };
95
96        let trace = Trace {
97            timestamp,
98            layer: Layer::GTPU,
99            additional_infos,
100            text: Some(text),
101            binary,
102            relation: TraceRelation::default(),
103        };
104        Ok(trace)
105    }
106}