Skip to content

chore(connlib): use proxy ip to match filters instead of translated#6960

Merged
thomaseizinger merged 13 commits into
mainfrom
chore/firezone/merge-traffic-filters-by-type
Oct 15, 2024
Merged

chore(connlib): use proxy ip to match filters instead of translated#6960
thomaseizinger merged 13 commits into
mainfrom
chore/firezone/merge-traffic-filters-by-type

Conversation

@conectado

@conectado conectado commented Oct 8, 2024

Copy link
Copy Markdown
Contributor

Previously, when a gateway checked if a packet was allowed through, it used the real IP of the DNS resource that the client was trying to communicate with.

The problem with this was that if there's an overlapping CIDR resource with the real IP this would allow a user to send packets using the filters for that resource instead of the DNS resource filters.

This can be confusing for users as packet can flow unexpectedly to the resources even if the filter doesn't permit it, so we use the IP of the packet before we translate it to the real IP to match the filters.

This doesn't change the security of this feature as a user can just change the IP of the packet with the dst of the DNS or the cidr resource according to what they need.

Fixes #6806

@vercel

vercel Bot commented Oct 8, 2024

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
firezone ✅ Ready (Inspect) Visit Preview 💬 Add feedback Oct 10, 2024 4:08pm

@conectado
conectado marked this pull request as ready for review October 9, 2024 00:54
@conectado

Copy link
Copy Markdown
Contributor Author

I manually tested this with the local docker-compose as it's hard to do automated testing until we do non-icmp packets in proptests

@thomaseizinger thomaseizinger left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Left some comments with ideas.

Comment thread website/src/components/Changelog/Gateway.tsx Outdated
fn ensure_allowed_dst(&mut self, packet: &IpPacket) -> anyhow::Result<()> {
let dst = packet.destination();

// Note a Gateway with Internet resource should never get packets for other resources

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you open an issue where we can brainstorm design ideas how we can model this better?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Comment thread rust/connlib/tunnel/src/peer.rs
ipv4: Ipv4Addr,
ipv6: Ipv6Addr,
resources: HashMap<ResourceId, ResourceOnGateway>,
internet_resource_enabled: bool,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't this implicit from having an Internet Resource in the hash map? Why track this separately?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If this is just a cache, let's document that. Plus, should we have a follow-up to make it an either resources or Internet resource in here once Internet Sites are released?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Let's do it as part of #6982

Comment thread rust/connlib/tunnel/src/peer.rs Outdated

debug_assert!(resource.is_dns());

let mut filter_engine = FilterEngine::empty();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a way we can de-duplicate this with the above bit?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

LMK what you think now

}

#[cfg(test)]
mod tests {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would it be very difficult to at least add a unit-test? I think some kind of automated test would be good, doesn't have to be a proptest.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I can do it, I'd need to replicate the whole proxy-ips thingy to have it mean something. Let me take another look at this.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I can do it, I'd need to replicate the whole proxy-ips thingy to have it mean something. Let me take another look at this.

It shouldn't be that difficult, should it? All we need is to define a few IP addresses, doesn't have to be 8, 1 proxy IP should be enough, right?

@thomaseizinger

Copy link
Copy Markdown
Member

I manually tested this with the local docker-compose as it's hard to do automated testing until we do non-icmp packets in proptests

I think doing a TCP handshake in the proptests should be pretty easy now that we have etherparse. Do you want to try adding that? I don't think it will help with one much because testing filters might be tricky but it would be a good addition regardless :)

@conectado

Copy link
Copy Markdown
Contributor Author

I manually tested this with the local docker-compose as it's hard to do automated testing until we do non-icmp packets in proptests

I think doing a TCP handshake in the proptests should be pretty easy now that we have etherparse. Do you want to try adding that? I don't think it will help with one much because testing filters might be tricky but it would be a good addition regardless :)

yeah, I'd like to do that. But why do you think adding filters would be hard? It's encoding the expected packets?

@thomaseizinger

Copy link
Copy Markdown
Member

I manually tested this with the local docker-compose as it's hard to do automated testing until we do non-icmp packets in proptests

I think doing a TCP handshake in the proptests should be pretty easy now that we have etherparse. Do you want to try adding that? I don't think it will help with one much because testing filters might be tricky but it would be a good addition regardless :)

yeah, I'd like to do that. But why do you think adding filters would be hard? It's encoding the expected packets?

I think so yes. If we randomly sample the filters, I think we will need to essentially re-build the filter matching engine in the tests to compute, whether the packet will make it through.

What we can do is perhaps make a simpler model by only adding resources with certain filters, like HTTP, HTTPS, SSH etc. If there is only a certain list to choose from, we can for example easily test that packets on other ports don't go through.

That would still have the benefit of checking what we fix in this PR I think. We do still miss out on some of the overlapping filters logic then but perhaps that is a good trade-off? Similarly to DNS names where we only use 1 level of subdomains for wildcard resources, the proptest could only use a certain subset of the filter features and we leave the rest to more specific unit tests.

Comment thread rust/connlib/tunnel/src/peer.rs Outdated
Comment thread rust/connlib/tunnel/src/peer.rs Outdated
Comment on lines +395 to +396
tracing::trace!(%addr, filters = ?filter_engine, "Installing new filters");
self.filters.insert(*addr, filter_engine);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could we deduplicate this too? I think it should be possible to have have a function that takes ip and list of filters, creates a filter engine, logs it and inserts it, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's possible but I'd need a wrapper for the network table so it can be done by self.filter or a static function. Otherwise the borrow checker won't allow to take self as mutable as I'm already holding self.resources as immutable.

I could also just clone self.resources but would require making ResourceOnGateway clonable.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

updated with the static function version

@thomaseizinger thomaseizinger left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Great stuff!

@conectado

Copy link
Copy Markdown
Contributor Author

@thomaseizinger added some unit-test! With this it should be ready for merge

@thomaseizinger thomaseizinger left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Awesome, thanks for adding tests!

@conectado
conectado added this pull request to the merge queue Oct 10, 2024
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 10, 2024
@jamilbk
jamilbk added this pull request to the merge queue Oct 13, 2024
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 13, 2024
@thomaseizinger
thomaseizinger added this pull request to the merge queue Oct 15, 2024
Merged via the queue into main with commit eedee56 Oct 15, 2024
@thomaseizinger
thomaseizinger deleted the chore/firezone/merge-traffic-filters-by-type branch October 15, 2024 23:35
thomaseizinger added a commit that referenced this pull request Oct 17, 2024
In #6960, split up the filter handling by resource type. This uncovered
an issue that was already known in and fixed in the portal in #6962:
Upstream DNS servers must not be in any of the reserved IP ranges.

Related: #7060.
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.

Merge traffic filter rules on the gateway by resource type

2 participants