Skip to content

Add no-NAS analyzer - #1107

Closed
untitaker wants to merge 1 commit into
mainfrom
no-nas-analyzer
Closed

Add no-NAS analyzer#1107
untitaker wants to merge 1 commit into
mainfrom
no-nas-analyzer

Conversation

@untitaker

@untitaker untitaker commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Fix #882

Add a new heuristic that alerts if there hasn't been any NAS message in the past 5 minutes. The heuristic is disabled by default.

I've tested it:

  • on tplink using with and without a SIM. With a SIM it's silent, without a SIM it alerts
  • on orbic without a SIM

If there is no SIM-card inserted on TP-Link, I only see GsmRrSignallingMessage, which we appear to skip entirely in log_to_gsmtap. This leads to a situation where the analyzer does not get called at all with any messages, so with the current trait it could never produce an event.

To fix that, I extended the analyzer trait so that analyzers can observe time advancing without there being messages. Analyzers now periodically get their poll method called regardless of whether there are new messages to analyze.

Polling an analyzer without relying on traffic from QMDL to drive the clock should also cause this heuristic to alert on cases where /dev/diag is just outright broken.

This method could also later be used in imsi_requested.rs which currently relies on packet counters as a kind of "clock".

Pull Request Checklist

  • The Rayhunter team has recently expressed interest in reviewing a PR for this.
    • If not, this PR may be closed due our limited resources and need to prioritize how we spend them.
  • Added or updated any documentation as needed to support the changes in this PR.
  • Code has been linted and run through cargo fmt.
  • If any new functionality has been added, unit tests were also added.
  • CONTRIBUTING.md has been read.
  • Your pull request is fewer than ~400 lines of code. (close enough)

You must check one of:

  • No generative AI (including LLMs) tools were used to create this PR.
  • Generative AI was used to create this PR. I certify that I have read and understand the code, and that all comments and descriptions were authored by myself and are not the product of generative AI.

Fix #882

Add a new heuristic that alerts if there hasn't been any NAS message in
the past 5 minutes. The heuristic is disabled by default.

I've tested it using with and without a SIM. With a SIM it's silent,
without a SIM it alerts.

If there is no SIM-card inserted on TP-Link, I only see
GsmRrSignallingMessage, which we appear to skip entirely in
log_to_gsmtap. This leads to a situation where the analyzer does not get
called at all with any messages, so with the current trait it could
never produce an event.

To fix that, I extended the analyzer trait so that analyzers can observe
time advancing without there being messages. Analyzers now periodically
get their `poll` method called regardless of whether there are new
messages to analyze.

Polling an analyzer without relying on traffic from QMDL to drive the
clock should also alert on cases where `/dev/diag` is just outright
broken.

This method could also later be used in `imsi_requested.rs` which
currently relies on packet counters as a kind of "clock".
@untitaker
untitaker marked this pull request as ready for review August 14, 2026 20:29
@bmw

bmw commented Aug 24, 2026

Copy link
Copy Markdown
Member

i'll plan on reviewing this, but if someone else wants to, just let me know

@bmw bmw self-assigned this Aug 24, 2026
@bmw

bmw commented Aug 26, 2026

Copy link
Copy Markdown
Member

this is a tricky problem that i feel like the current architecture in main isn't currently well set up to handle

i think your approach is clever, but i worry about using wall time when it's not saved in the captures and we have reanalyze/rayhunter-check. meaningful wall time won't be available so reanalysis can give different results which is something i'd really like to avoid if we can

what do you think about something vaguely like this?

in addition to avoiding wall time, other things i like about this approach are

  • when we travel backwards in time we update the saved timestamp to the older value. please let me know if you think this is the wrong approach, but from what i've seen, future timestamps after time traveling seem to continue from this older value rather than suddenly jumping forward again
  • we also handle jumping forwards in time which i've seen in the captures sent to EFF. i think this could happen in an area no cell service if nothing else

other things i think we could consider doing in this or another PR are

  • refactor gsmtap_parser::parse to not parse the timestamp since we're now already doing it before that function is called
  • disable the no NAS analyzer for the rest of the current analysis if a NAS message is ever seen. as i understand it, if we ever see a NAS message, we should expect the SIM is working, i wouldn't expect that to change over the course of a capture, and disabling it reduces the likelihood of positives

please let me know what you think when you get a chance

@untitaker

Copy link
Copy Markdown
Collaborator Author

@bmw I think the main problem I see is that many device clocks actually start at 1970 at boot. They then count seconds fine, but the timestamps are all wrong. So I tried to avoid letting the analyzers know about absolute time. I do think we should persist system timestamps in the capture and use them for replay but it seems to me that we would need a new json file like GPS for that?

I agree with the two suggestions to refactor the parser and disabling the heuristic early.

@bmw

bmw commented Aug 27, 2026

Copy link
Copy Markdown
Member

i agree that we'd need a new JSON file or something if we wanted to persist wall time. i think we could go that route if you really wanted, but like you said, it'd bloat storage. i also worry it'd add significant complexity to the code and the UX without benefiting the no NAS analyzer that much over just adding a call to the analyzers on skipped packets like i did in my gist. i think another nice thing about removing the use of wall time is we won't generate false positives in areas with no cell service at all

i do agree that the date in the timestamp can be ridiculously off though. if we did want to try using timestamps, we could name the variables something like {capture,packet}_timestamp and/or add code comments describing the wonkiness these values sometimes have if you think that'd help

alternatively, maybe a middle ground between our approaches would be to keep the general structure of my suggestion and stop using wall time but pass in durations instead of timestamps. i'd be fine with an approach like this, but to be honest, i prefer timestamps. yes they're really off sometimes, but it's the actual timestamp in the QMDL/PCAP that we have for the packet and i worry almost any kind of preprocessing of the timestamp before feeding it to the analyzers makes the system more complex and less flexible. for example, i personally think the way my gist handles traveling back in time is saneish while with durations the harness would have to pass in a negative duration or skip providing durations until the timestamps catch up again. passing in a duration of zero or something on the first packet also feels a little awkward to me

does any of this sway you at all? what's your preferred path forward here?

@untitaker

untitaker commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

sorry, i didn't pay attention yesterday. i just realized you just wanted to get rid of system time for replayability and it has nothing to do with timestamps vs durations. but this changes functionality.

the problem i ran into is that this would not make it possible to trigger the no-NAS heuristic on hypothetical recordings that have zero packets (i.e. the QMDL is literally empty). there are two hypothetical cases where this could matter:

  • using this heuristic to validate new device ports. from this follows that the analyzer has to deal in durations.
  • "imsi requested without attach" is currently not firing if there are no qmdl packets at all coming after the imsi request. i would like to fix that, too

fwiw i've not been able to get an empty QMDL just by using the orbic in the wrong ITU region. so these cases are really rare/theoretical

but yes this destroys replayability because there's nothing to replay in this case. in all other cases where we have a steady stream of messages, the clock should end up mostly being driven by the qmdl messages, and therefore most recordings should turn out to be replayable in practice.

@bmw

bmw commented Aug 31, 2026

Copy link
Copy Markdown
Member

here are two hypothetical cases where this could matter:

  • using this heuristic to validate new device ports

can we not validate new device ports well enough using the test_analyzer? if not, is this something we could fix maybe by creating another heuristic that fires on any qmdl message at all?

i'm also a little hesitant to have no-NAS fire when there's no traffic as i think it'd generate false positives in areas with no signal like i said in my last message

  • "imsi requested without attach" is currently not firing if there are no qmdl packets at all coming after the imsi request

could we not just use the update_timestamp approach from my gist and have the heuristic fire if it's been X minutes without an auth request followup? this wouldn't work if there are no qmdl packets at all like you said, but my potentially wrong intuition says this is probably good enough

sorry i'm fighting you so much on this. i'm just not sure using system time really buys us that much while also opening the door to replayability issues. does you find any of this convincing or do you still really think we need to introduce system time and polling to the analyzers right now?

@untitaker

Copy link
Copy Markdown
Collaborator Author

but my potentially wrong intuition says this is probably good enough

I mean if we say it's good enough from a requirements perspective then yes i think your approach makes more sense.

I also tried approaches where the analyzer internally spawns a tokio thread that sleeps with a timeout, but this just caused more chaos and had the same replayability issues.

@bmw

bmw commented Aug 31, 2026

Copy link
Copy Markdown
Member

I mean if we say it's good enough from a requirements perspective then yes i think your approach makes more sense.

unless you have a link to an issue or discussion or something suggesting otherwise, i personally think we should consider it good enough for now. i think exposing the packet timestamps to the analyzers is a definite improvement over what we currently have, it allows us to make progress on the different features discussed here without any major downsides, and we can always refactor and add system time in the future if this approach turns out to not be good enough

alternatively, you or i can get cooper to weigh in at a high level here, but the man is busy and i have a slight preference to work this out among the two of us if we can

untitaker added a commit that referenced this pull request Aug 31, 2026
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.
untitaker added a commit that referenced this pull request Aug 31, 2026
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.
@bmw

bmw commented Sep 1, 2026

Copy link
Copy Markdown
Member

with us mostly in agreement on #1132, shall we close this?

@untitaker untitaker closed this Sep 1, 2026
@untitaker
untitaker deleted the no-nas-analyzer branch September 1, 2026 18:09
untitaker added a commit that referenced this pull request Sep 2, 2026
* Add no-NAS analyzer and no-diag alerts

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.

* Address no-NAS analyzer review feedback

* add newline

* Only update timestamps for skipped packets

* Assert event and analyzer counts match

* roll back changes to gsmtap_parser, add timestamp to analyze_.. functions, simplify analyzer

* fix bugs in rayhunter-check and UI that would hide findings on skipped messages (past recordings only)

* Fix prettier formatting in analysis.svelte.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Warn when SIM card is suspected to not be working

2 participants