mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-07-08 09:38:10 -07:00
lib: refactor gsmtap/gsmtap_parser into a single module
This'll allow us to break out more specific GSMTAP parsing into submodules more easily.
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
use crate::diag::Message;
|
||||
use crate::diag::diaglog::{Timestamp, LogBody, Nas4GMessageDirection};
|
||||
use crate::gsmtap::{GsmtapHeader, GsmtapMessage, GsmtapType, LteNasSubtype, LteRrcSubtype};
|
||||
|
||||
use log::error;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GsmtapParserError {
|
||||
#[error("Invalid LteRrcOtaMessage ext header version {0}")]
|
||||
InvalidLteRrcOtaExtHeaderVersion(u8),
|
||||
#[error("Invalid LteRrcOtaMessage header/PDU number combination: {0}/{1}")]
|
||||
InvalidLteRrcOtaHeaderPduNum(u8, u8),
|
||||
}
|
||||
|
||||
pub fn parse(msg: Message) -> Result<Option<(Timestamp, GsmtapMessage)>, GsmtapParserError> {
|
||||
if let Message::Log {
|
||||
timestamp, body, ..
|
||||
} = msg
|
||||
{
|
||||
match log_to_gsmtap(body)? {
|
||||
Some(msg) => Ok(Some((timestamp, msg))),
|
||||
None => Ok(None),
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn log_to_gsmtap(value: LogBody) -> Result<Option<GsmtapMessage>, GsmtapParserError> {
|
||||
match value {
|
||||
LogBody::LteRrcOtaMessage {
|
||||
ext_header_version,
|
||||
packet,
|
||||
} => {
|
||||
let gsmtap_type = match ext_header_version {
|
||||
0x02 | 0x03 | 0x04 | 0x06 | 0x07 | 0x08 | 0x0d | 0x16 => match packet.get_pdu_num()
|
||||
{
|
||||
1 => GsmtapType::LteRrc(LteRrcSubtype::BcchBch),
|
||||
2 => GsmtapType::LteRrc(LteRrcSubtype::BcchDlSch),
|
||||
3 => GsmtapType::LteRrc(LteRrcSubtype::MCCH),
|
||||
4 => GsmtapType::LteRrc(LteRrcSubtype::PCCH),
|
||||
5 => GsmtapType::LteRrc(LteRrcSubtype::DlCcch),
|
||||
6 => GsmtapType::LteRrc(LteRrcSubtype::DlDcch),
|
||||
7 => GsmtapType::LteRrc(LteRrcSubtype::UlCcch),
|
||||
8 => GsmtapType::LteRrc(LteRrcSubtype::UlDcch),
|
||||
pdu => {
|
||||
return Err(GsmtapParserError::InvalidLteRrcOtaHeaderPduNum(
|
||||
ext_header_version,
|
||||
pdu,
|
||||
));
|
||||
}
|
||||
},
|
||||
0x09 | 0x0c => match packet.get_pdu_num() {
|
||||
8 => GsmtapType::LteRrc(LteRrcSubtype::BcchBch),
|
||||
9 => GsmtapType::LteRrc(LteRrcSubtype::BcchDlSch),
|
||||
10 => GsmtapType::LteRrc(LteRrcSubtype::MCCH),
|
||||
11 => GsmtapType::LteRrc(LteRrcSubtype::PCCH),
|
||||
12 => GsmtapType::LteRrc(LteRrcSubtype::DlCcch),
|
||||
13 => GsmtapType::LteRrc(LteRrcSubtype::DlDcch),
|
||||
14 => GsmtapType::LteRrc(LteRrcSubtype::UlCcch),
|
||||
15 => GsmtapType::LteRrc(LteRrcSubtype::UlDcch),
|
||||
pdu => {
|
||||
return Err(GsmtapParserError::InvalidLteRrcOtaHeaderPduNum(
|
||||
ext_header_version,
|
||||
pdu,
|
||||
));
|
||||
}
|
||||
},
|
||||
0x0e..=0x10 => match packet.get_pdu_num() {
|
||||
1 => GsmtapType::LteRrc(LteRrcSubtype::BcchBch),
|
||||
2 => GsmtapType::LteRrc(LteRrcSubtype::BcchDlSch),
|
||||
4 => GsmtapType::LteRrc(LteRrcSubtype::MCCH),
|
||||
5 => GsmtapType::LteRrc(LteRrcSubtype::PCCH),
|
||||
6 => GsmtapType::LteRrc(LteRrcSubtype::DlCcch),
|
||||
7 => GsmtapType::LteRrc(LteRrcSubtype::DlDcch),
|
||||
8 => GsmtapType::LteRrc(LteRrcSubtype::UlCcch),
|
||||
9 => GsmtapType::LteRrc(LteRrcSubtype::UlDcch),
|
||||
pdu => {
|
||||
return Err(GsmtapParserError::InvalidLteRrcOtaHeaderPduNum(
|
||||
ext_header_version,
|
||||
pdu,
|
||||
));
|
||||
}
|
||||
},
|
||||
0x13 | 0x1a | 0x1b => match packet.get_pdu_num() {
|
||||
1 => GsmtapType::LteRrc(LteRrcSubtype::BcchBch),
|
||||
3 => GsmtapType::LteRrc(LteRrcSubtype::BcchDlSch),
|
||||
6 => GsmtapType::LteRrc(LteRrcSubtype::MCCH),
|
||||
7 => GsmtapType::LteRrc(LteRrcSubtype::PCCH),
|
||||
8 => GsmtapType::LteRrc(LteRrcSubtype::DlCcch),
|
||||
9 => GsmtapType::LteRrc(LteRrcSubtype::DlDcch),
|
||||
10 => GsmtapType::LteRrc(LteRrcSubtype::UlCcch),
|
||||
11 => GsmtapType::LteRrc(LteRrcSubtype::UlDcch),
|
||||
45 => GsmtapType::LteRrc(LteRrcSubtype::BcchBchNb),
|
||||
46 => GsmtapType::LteRrc(LteRrcSubtype::BcchDlSchNb),
|
||||
47 => GsmtapType::LteRrc(LteRrcSubtype::PcchNb),
|
||||
48 => GsmtapType::LteRrc(LteRrcSubtype::DlCcchNb),
|
||||
49 => GsmtapType::LteRrc(LteRrcSubtype::DlDcchNb),
|
||||
50 => GsmtapType::LteRrc(LteRrcSubtype::UlCcchNb),
|
||||
52 => GsmtapType::LteRrc(LteRrcSubtype::UlDcchNb),
|
||||
pdu => {
|
||||
return Err(GsmtapParserError::InvalidLteRrcOtaHeaderPduNum(
|
||||
ext_header_version,
|
||||
pdu,
|
||||
));
|
||||
}
|
||||
},
|
||||
0x14 | 0x18 | 0x19 => match packet.get_pdu_num() {
|
||||
1 => GsmtapType::LteRrc(LteRrcSubtype::BcchBch),
|
||||
2 => GsmtapType::LteRrc(LteRrcSubtype::BcchDlSch),
|
||||
4 => GsmtapType::LteRrc(LteRrcSubtype::MCCH),
|
||||
5 => GsmtapType::LteRrc(LteRrcSubtype::PCCH),
|
||||
6 => GsmtapType::LteRrc(LteRrcSubtype::DlCcch),
|
||||
7 => GsmtapType::LteRrc(LteRrcSubtype::DlDcch),
|
||||
8 => GsmtapType::LteRrc(LteRrcSubtype::UlCcch),
|
||||
9 => GsmtapType::LteRrc(LteRrcSubtype::UlDcch),
|
||||
54 => GsmtapType::LteRrc(LteRrcSubtype::BcchBchNb),
|
||||
55 => GsmtapType::LteRrc(LteRrcSubtype::BcchDlSchNb),
|
||||
56 => GsmtapType::LteRrc(LteRrcSubtype::PcchNb),
|
||||
57 => GsmtapType::LteRrc(LteRrcSubtype::DlCcchNb),
|
||||
58 => GsmtapType::LteRrc(LteRrcSubtype::DlDcchNb),
|
||||
59 => GsmtapType::LteRrc(LteRrcSubtype::UlCcchNb),
|
||||
61 => GsmtapType::LteRrc(LteRrcSubtype::UlDcchNb),
|
||||
pdu => {
|
||||
return Err(GsmtapParserError::InvalidLteRrcOtaHeaderPduNum(
|
||||
ext_header_version,
|
||||
pdu,
|
||||
));
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(GsmtapParserError::InvalidLteRrcOtaExtHeaderVersion(
|
||||
ext_header_version,
|
||||
));
|
||||
}
|
||||
};
|
||||
let mut header = GsmtapHeader::new(gsmtap_type);
|
||||
header.arfcn = (packet.get_earfcn() as u16) & 0x3FFF;
|
||||
header.frame_number = packet.get_sfn();
|
||||
header.subslot = packet.get_subfn();
|
||||
Ok(Some(GsmtapMessage {
|
||||
header,
|
||||
payload: packet.take_payload(),
|
||||
}))
|
||||
}
|
||||
LogBody::Nas4GMessage { msg, direction, .. } => {
|
||||
// currently we only handle "plain" (i.e. non-secure) NAS messages
|
||||
let mut header = GsmtapHeader::new(GsmtapType::LteNas(LteNasSubtype::Plain));
|
||||
header.uplink = matches!(direction, Nas4GMessageDirection::Uplink);
|
||||
Ok(Some(GsmtapMessage {
|
||||
header,
|
||||
payload: msg,
|
||||
}))
|
||||
}
|
||||
_ => {
|
||||
error!("gsmtap_sink: ignoring unhandled log type: {value:?}");
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use deku::DekuContainerWrite;
|
||||
|
||||
#[test]
|
||||
fn test_arfcn_exceeding_14_bits_does_not_panic() {
|
||||
let mut header = GsmtapHeader::new(GsmtapType::LteRrc(LteRrcSubtype::DlDcch));
|
||||
// EARFCN 54540 (band 46) exceeds 14-bit max of 16383
|
||||
let large_earfcn: u32 = 54540;
|
||||
header.arfcn = (large_earfcn as u16) & 0x3FFF;
|
||||
let msg = GsmtapMessage {
|
||||
header,
|
||||
payload: vec![0x00],
|
||||
};
|
||||
// This would panic before the fix with "bit size of input is larger than bit requested size"
|
||||
assert!(msg.to_bytes().is_ok());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user