Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: don't panic on STUN requests for unknown interfaces #493

Merged

Conversation

thomaseizinger
Copy link
Collaborator

Resolves: #473.

Comment on lines +1173 to +1177
// The local candidate will be
// either a host candidate (for cases where the request was not received
// through a relay) or a relayed candidate (for cases where it is
// received through a relay). The local candidate can never be a
// server-reflexive candidate.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if this is still true with our changes in #455? Shouldn't we instead also check for server-reflexive candidates and compare the base instead?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .expect here comes from the assumption you're going to configure all ways you are going to receive traffic. server-reflexive (and peer-reflexive) are secondary (not configured), they are discovered and more crucially always received via a primary (host or relayed).

The logic below would be very strange if the local_idx can be a secondary (reflexive). It would imply we can make a NAT - NAT like a server reflexive of a server reflexive.

Copy link

@lolgesten lolgesten left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this scenario not use .accepts_message() to test whether the ICE agent want the packet?

While I accept we don't have to panic, I still believe the user should configure the ICE agent correctly. Silently discarding random UDP packets means it's easy to introduce bugs and not notice a misconfiguration.

@thomaseizinger
Copy link
Collaborator Author

While I accept we don't have to panic, I still believe the user should configure the ICE agent correctly. Silently discarding random UDP packets means it's easy to introduce bugs and not notice a misconfiguration.

We do use accepts_message in our code and I can still trigger this panic. That being said, we don't yet have https://github.com/algesten/str0m/pull/488in our fork so that might change things?

@thomaseizinger
Copy link
Collaborator Author

accepts_message only checks the message and doesn't have access to the destination SocketAddr so it cannot check whether it has a candidate for that:

pub fn accepts_message(&self, message: &StunMessage<'_>) -> bool {

@algesten
Copy link
Owner

algesten commented Apr 3, 2024

We do use accepts_message in our code and I can still trigger this panic. That being said, we don't yet have https://github.com/algesten/str0m/pull/488in our fork so that might change things?

Interesting! That would be good to know. It makes a big difference to me if accepts_message says "yes" and handle_message says "panic"!

Spontaneously it seems these should be in lockstep.

@thomaseizinger
Copy link
Collaborator Author

We do use accepts_message in our code and I can still trigger this panic. That being said, we don't yet have algesten/str0m/pull/488in our fork so that might change things?

Interesting! That would be good to know. It makes a big difference to me if accepts_message says "yes" and handle_message says "panic"!

Spontaneously it seems these should be in lockstep.

See the comment above. i think we'd have to change accepts_message to accept a StunPacket to make it say "no" to packets from unknown interfaces.

Note that the way this panic gets triggered for us is:

  1. We invalidate all other candidates as soon as we have a working path
  2. We want to delay sending of relay candidates by ~1s to first check if we can hole-punch

Combinding (1) and (2) leads to a race condition where we might have already invalidated a candidate but the remote wants to still send use STUN requests.

@algesten
Copy link
Owner

algesten commented Apr 3, 2024

Right. Hm. Maybe we should just add the interface check to the accepts message.

Neither of "I accept it and discard it", or "I accept it and panic" seems entirely right.

@thomaseizinger
Copy link
Collaborator Author

My take on it is:

  • IceAgent::handle_packet must not panic, regardless what data you feed it. IMO, one of the aspects of a SANS-IO design is that you can (directly) feed it unstructured input from the network. Thus, it must not panic or otherwise we have a DoS attack vector. I think the correct solution for this fn is to discard the message.
  • IceAgent::accepts_message is useful when multiple agents are multiplexed on a single socket. IMO there isn't a lot of value in having this function (we've discussed this before but I'll mention it for completeness). Processing a message and checking whether we want to do so requires very similar code. Code that must not diverge. To me, it seems like we could just do whatever we do in accepts_message at the very top of handle_message and return true | false from it, indicating whether we've handled the message. It might not hold true for the entire Rtc instance but at least for the IceAgent, doing the actual processing should be very cheap.

Perhaps as a compromise, we could make accepts_message pub(crate) such that the Rtc instance can still call it but the public API of IceAgent doesn't expose it? Then it wouldn't be a silent discard but just returning false to indicate that we didn't handle it.

@thomaseizinger
Copy link
Collaborator Author

thomaseizinger commented Apr 3, 2024

We can also (additionally) align the two APIs such that the entire packet can be passed to accepts_message and checked early.

Copy link
Owner

@algesten algesten left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm good merging this now, if you think it's ok?

Copy link
Collaborator Author

@thomaseizinger thomaseizinger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we return false now, should we also change stun_server_handle_message to return false in case we discard it based on an unknown candidate?

@algesten
Copy link
Owner

algesten commented Apr 4, 2024

If we return false now, should we also change stun_server_handle_message to return false in case we discard it based on an unknown candidate?

I tried that but didn't like where it was going. Places like if candidate.discarded { return are not clear whether it's true or false.

I decided that rather than muddle the semantics, the bool is exactly that of accepts_message.

@thomaseizinger
Copy link
Collaborator Author

I decided that rather than muddle the semantics, the bool is exactly that of accepts_message.

Okay, in that case, isn't that commit unrelated to this change? I am not sure how atomic you want to be on your PRs but it could be done separately in that case.

Otherwise, I am happy with this going in :)

@lolgesten
Copy link

Let's merge it! I'll reference the PR twice in the changelog.

@algesten algesten merged commit a0f4217 into algesten:main Apr 5, 2024
22 checks passed
github-merge-queue bot pushed a commit to firezone/firezone that referenced this pull request Apr 10, 2024
This bump includes a fix that triggers a panic on unknown interfaces
(algesten/str0m#493). The panic is what is
currently blocking #4268 from
proceeding.
github-merge-queue bot pushed a commit to firezone/firezone that referenced this pull request Apr 10, 2024
This bump includes a fix that triggers a panic on unknown interfaces
(algesten/str0m#493). The panic is what is
currently blocking #4268 from
proceeding.
github-merge-queue bot pushed a commit to firezone/firezone that referenced this pull request Apr 10, 2024
This bump includes a fix that triggers a panic on unknown interfaces
(algesten/str0m#493). The panic is what is
currently blocking #4268 from
proceeding.
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.

Remove panic on missing candidates
3 participants