Add no-NAS analyzer and no-diag UI alert - #1132
Conversation
4a36c2c to
4c2bb92
Compare
Fix #882 An alternative to #1107 where the no-NAS analyzer is stripped down, and the analyzer interface is kept minimal to not use system time. This simplifies code but prevents the analyzer from emitting alerts if there are no packets at all. Instead, we add a bespoke alerting component to the UI that compares packet timestamps with current system time. If the two are far apart, there is a warning in the UI. The warning goes away if we see packets again. Display or ntfy is not implemented.
4c2bb92 to
01880b9
Compare
bmw
left a comment
There was a problem hiding this comment.
i like this approach a lot!
after thinking about this more yesterday, i was feeling worried about changing rayhunter's status line on the device in response to not seeing any traffic as i thought it'd create confusing false positives if users happened to even temporarily go somewhere without any traffic. i think not doing that and instead displaying the warning prominently in the web UI where we can provide more context makes a lot of sense
i also tested this on my orbic with its sim card removed and the no-NAS analyzer successfully fired after 5 mins and 2 seconds
| row.events = self.update_timestamp(timestamp); | ||
| } | ||
|
|
||
| let (timestamp, gsmtap_msg) = match gsmtap_parser::parse(qmdl_message) { |
There was a problem hiding this comment.
| let (timestamp, gsmtap_msg) = match gsmtap_parser::parse(qmdl_message) { | |
| let (_, gsmtap_msg) = match gsmtap_parser::parse(qmdl_message) { |
GH's web UI isn't letting me write the multiline suggestion i want, but i think we should at least ignore the timestamp here and remove the row.packet_timestamp = Some(timestamp.to_datetime()); line below
in this or another PR, i also think it'd be nice to refactor gsmtap_parser::parse to stop returning the timestamp since we'll no longer be using it
There was a problem hiding this comment.
your refactor is fine, but i somehow previously missed the other calls to parse that were actually using the timestamp and not seeing any is what made me suggest the change in the first place. my bad. sorry for creating more work with questionable benefit here
| .collect() | ||
| } | ||
|
|
||
| fn update_timestamp(&mut self, timestamp: DateTime<FixedOffset>) -> Vec<Option<Event>> { |
There was a problem hiding this comment.
i think it'd be nice to append self.packet_num to any event strings here like we currently do in analyze_information_element
| packet_timestamp: Some(packet_timestamp), | ||
| skipped_message_reason: None, | ||
| events: Vec::new(), | ||
| events: self.update_timestamp(packet_timestamp), |
There was a problem hiding this comment.
one thing that's slightly awkward with this design is that since we call update_timestamp on every packet before calling analyze_information_element, a NAS message could cause the no-NAS analyzer to alert on the call to update_timestamp since it won't know it's a NAS message until analyze_information_element is called
i wanted to flag this, but i'll leave it up to you on whether or not you think it's worth doing something about. fwiw, i avoided this in my gist by only calling update_timestamp on skipped packets and also passing in the timestamp to analyze_information_element, but that requires additional refactoring and is a little annoying bc most analyzers wouldn't use a timestamp passed to analyze_information_element
There was a problem hiding this comment.
I intended to fix that by calling update_timestamp after analyze_information_element, but seems like it got lost somewhere. Pushed it now.
| None | ||
| } | ||
|
|
||
| fn update_timestamp(&mut self, timestamp: DateTime<FixedOffset>) -> Option<Event> { |
There was a problem hiding this comment.
do you want to do anything special if we see a big jump forward in time? if so and if it'd be useful, i can take a look at the captures sent to EFF and see how common this is and/or how big of jumps users are seeing
There was a problem hiding this comment.
I am now resetting the timestamps when there is a gap between packets of more than 5 mins. Will check later what this does on my captures
|
also, if you test this with some of your devices with the sim card inserted, does the no-NAS analyzer fire for you? i just tested this with my same orbic with an inactive sim card for about an hour and it never saw any NAS messages 🙁 |
|
I've addressed the review comments but still have to test this PR properly to check that it doesn't trigger anything on my captures. |
yep, here the no-NAS analyzer fired as well, using an orbic with verizon sim. i think this is expected, the orbic doesn't support the right LTE bands for EU at all. is it a problem that the analyzer fires in your scenario? I think that is actually what we want, identify dead sims. in my experience there are two kinds of inactive sims, some of them work, some of them are totally dead |
not necessarily, however, i wasn't under the impression my sim was dead, just inactive playing with it more, here's what i think happened. when i start my device with its sim and the no-NAS analyzer already enabled, it sees an if after this i stop the recording and start a new one, rayhunter doesn't see either of these messages, presumably bc my device doesn't try to reconnect to the tower that rejected it, so the no-NAS analyzer flags an event. i think i either restarted the recording like this in my previous testing or there was a race between rayhunter and the modem starting i don't personally think this is a deal breaker with this heuristic we're flagging as experimental, but it is a limitation with this heuristic i hadn't really realized yet. what do you think? think it's worth documenting in |
|
I would argue the no-NAS analyzer is right to flag that second recording, as it's going to be useless. How can you catch IMSI catchers if the device won't try to connect to anything after the initial attempt? |
|
maybe, but i imagine this is the normal behavior of devices and expect you'd see something similar with your tplink in this scenario too. alerting when everything is operating as it should feels bad/confusing to me personally. i also think the deviceshould attempt to attach to the tower again after some timeout or if another matching PLMN popped up. i'm not too worried about this point, but i did want to flag it similarly, as part of only calling one of feel free to take your time on this and i'm sorry for any false sense of urgency i created. i have more than 48 hours before i disappear on vacation for a bit |
is it possible to verify this? if the device isn't permanently disabled, i think this would call for a "temporary warning" that clears itself, similar to when we don't receive any qmdl msgs in a while |
…ions, simplify analyzer
…d messages (past recordings only)
probably through some combination of trawling the specs and letting a device in this state run for a long period of time. in my initial run where i saw this behavior tho it had been running for almost an hour with no NAS messages at all... i'm not sure if you still want to do more testing first, but i'd personally be fine with getting this merged and playing with it more later since it's marked as experimental and not on by default to that end and as a gentle nudge just in case you didn't notice yet, |
bmw
left a comment
There was a problem hiding this comment.
this lgtm!
feel free to merge when/as you wish
| } | ||
| }); | ||
| } | ||
| const events: Event[] = (row_json.events ?? []).map((event_json: any): Event | null => { |
There was a problem hiding this comment.
thanks for catching this! i unfortunately had missed it
Brings in EFForg/rayhunter up to b869b81 (eight commits): - The no-NAS detector and the no-diag alert (EFForg#1132). The detector is off by default, as upstream ships it. Analyzers now receive each packet's timestamp, and packets that produce nothing to analyze still reach every analyzer through `report_skipped_packet`, so a detector that watches the clock sees time pass; this fork's five detectors take the new argument. Warnings raised on skipped packets are no longer dropped by rayhunter-check or the web report reader. - The Rust toolchain pinned to 1.98.0 for CI and local builds. - Help tooltips for the installer GUI's options, and three dependency bumps. Resolved against the fork: - The harness keeps its packet numbers and its list of traffic it never claimed to analyze; those packets now advance detector clocks like any other skipped packet. - The settings page keeps its tabbed layout; the new detector appears in the Detection tab with an explanation like the others. - The no-diag alert sits in the cell-site panel under the SIM verdict rather than at the top of the page, since it answers the same question: is the device saying anything at all. Its judgement is a tested helper and it is styled for dark mode. - Upstream's test that builds a bare 2G element now builds one with the message bytes this fork's 2G element carries. - A detector page, index row, configuration key, guide update and troubleshooting entry, in the fork's documentation style. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Fix #882
An alternative to #1107 where the no-NAS analyzer is stripped down, and the analyzer interface is kept minimal to not use system time. This simplifies code but prevents the analyzer from emitting alerts if there are no packets at all.
Instead, we add a bespoke alerting component to the UI that compares packet timestamps with current system time. If the two are far apart, there is a warning in the UI. The warning goes away if we see packets again. Display or ntfy is not implemented.
Pull Request Checklist
cargo fmt.You must check one of: