Skip to content

Drop packets with invalid NAT requirements in flow-filter#1341

Draft
qmonnet wants to merge 2 commits intomainfrom
pr/qmonnet/flow-filter-skip-nat
Draft

Drop packets with invalid NAT requirements in flow-filter#1341
qmonnet wants to merge 2 commits intomainfrom
pr/qmonnet/flow-filter-skip-nat

Conversation

@qmonnet
Copy link
Member

@qmonnet qmonnet commented Mar 13, 2026

NOT BLOCKING FOR 26.01

Some NAT requirements are not currently supported, including:

  • Masquerading for destination IP address, when the packet has no flow information attached
  • Port forwarding for the source IP address/port, when the packet has no flow information attached

The flow-filter stage has visibility on these NAT requirements, and on the availability of flow session information for the packet. And yet, on non-ambiguous lookup results, it will let packets go through even if the NAT requirements are not valid. One consequence is that additional processing is required, because it falls down to the relevant NAT stages to check their context and dump the packet in that case. Another consequence is that, once a NAT stage eventually dumps the packet, it may do so for reasons that may not obvious when looking at the log. For example, we've observed logs such as:

ERROR dp-worker-8 dataplane_nat::stateful::apalloc: 256: No address pool found for source address 10.50.2.2. Did we hit a bug when building the stateful NAT allocator?
ERROR dp-worker-8 dataplane_nat::stateful: 513: stateful-NAT: Error processing packet: allocation failed: new NAT session creation denied

These logs are not incorrect, in the sense that in the context of the stateful NAT stage, reaching that point might be a bug if we assumed that the packet did require to be NAT-ed.

So in this PR, we add a check to the flow-filter stage to check the two cases described above, and to drop the packet with more helpful log information when we get invalid NAT requirements.

@Fredi-raspall Let me know what you think of it, it sounds like the right place to drop packets when we have invalid NAT requirements, but that's pushing a bit more logic to the flow-filter stage.

Add a helper function to fake flow session information for a packet,
setting the destination VPC, but using some mock-up data for stateful
NAT or port forwarding context, because we don't need to read it in the
tests (and setting the real data might involve sorting out circular
dependencies).

This is in prevision for the addition of more checks setting flow
session information.

Signed-off-by: Quentin Monnet <qmo@qmon.net>
@qmonnet qmonnet requested a review from a team as a code owner March 13, 2026 17:34
@qmonnet qmonnet added the area/nat Related to Network Address Translation (NAT) label Mar 13, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds early validation in the flow-filter stage to drop packets with unsupported NAT requirements (destination masquerade or source port-forwarding) when no flow session info is attached. Previously these packets would pass through to downstream NAT stages, which would fail with confusing error messages.

Changes:

  • Added check_nat_requirements() validation before setting NAT requirements for single-match lookups in flow-filter
  • Updated tests to expect packets to be filtered/dropped in invalid NAT scenarios, and added new test cases with flow info attached
  • Extracted fake_flow_session test helper to reduce duplication

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
flow-filter/src/lib.rs Added check_nat_requirements() function and call it before set_nat_requirements for single-match lookups
flow-filter/src/tests.rs Updated assertions for now-dropped packets, added test cases with flow info, extracted fake_flow_session helper

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +135 to +141
if check_nat_requirements(packet, &dst_data).is_err() {
debug!(
"{nfi}: Invalid NAT requirements found for flow {tuple}, dropping packet"
);
packet.done(DoneReason::Filtered);
return;
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Looking into it

Some NAT requirements are not currently supported, including:

- Masquerading for destination IP address, when the packet has no flow
  information attached
- Port forwarding for the source IP address/port, when the packet has no
  flow information attached

The flow-filter stage has visibility on these NAT requirements, and on
the availability of flow session information for the packet. And yet, on
non-ambiguous lookup results, it will let packets go through even if the
NAT requirements are not valid. One consequence is that additional
processing is required, because it falls down to the relevant NAT stages
to check their context and dump the packet in that case. Another
consequence is that, once a NAT stage eventually dumps the packet, it
may do so for reasons that may not obvious when looking at the log. For
example, we've observed logs such as:

    ERROR dp-worker-8 dataplane_nat::stateful::apalloc: 256: No address pool found for source address 10.50.2.2.
        Did we hit a bug when building the stateful NAT allocator?
    ERROR dp-worker-8 dataplane_nat::stateful: 513: stateful-NAT: Error processing packet: allocation failed:
        new NAT session creation denied

These logs are not incorrect, in the sense that in the context of the
stateful NAT stage, reaching that point might be a bug if we assumed
that the packet did require to be NAT-ed.

So in this commit, we add a check to the flow-filter stage to check the
two cases described above, and to drop the packet with more helpful log
information when we get invalid NAT requirements.

We also adjust and compensate the unit tests affected by the change.

Signed-off-by: Quentin Monnet <qmo@qmon.net>
@qmonnet qmonnet force-pushed the pr/qmonnet/flow-filter-skip-nat branch from a173135 to 9609b0e Compare March 13, 2026 17:41
@qmonnet qmonnet self-assigned this Mar 13, 2026
@Fredi-raspall
Copy link
Contributor

What issue does this relate to?

@Fredi-raspall
Copy link
Contributor

I think the changes are okay. I have the concern whether this could block legitimate traffic. Also, I believe the error occurs in the multiple matches case, which is not yet covered. I'd opt not to add risky logic there and let instead the next NFs drop as they deem, because the checks are already there, but may make a decision when the multiple case match is addressed.

@Fredi-raspall
Copy link
Contributor

@qmonnet I believe that the approach in #1342 (which we wante to implement anyway) solves the issue.

@qmonnet qmonnet marked this pull request as draft March 16, 2026 12:37
@qmonnet
Copy link
Member Author

qmonnet commented Mar 16, 2026

Moved to draft until we clear up the discussion on the relationship with #1342.

What issue does this relate to?

This PR was initially driven by a report about the confusing logs mentioned above, on Slack, I don't think we've got a corresponding issue on GitHub.

I think the changes are okay. I have the concern whether this could block legitimate traffic.

Conversely, if we assume in the NAT stages that we only receive traffic that we should indeed NAT, we risk letting packets go through even though they're not legit 🤷. I still prefer the risk of dropping legit traffic.

Also, I believe the error occurs in the multiple matches case, which is not yet covered.

As I replied to Copilot, I've been looking into it.

I'd opt not to add risky logic there and let instead the next NFs drop as they deem, because the checks are already there, but may make a decision when the multiple case match is addressed.

👍 I'll work on completing it

@qmonnet I believe that the approach in #1342 (which we wante to implement anyway) solves the issue.

I don't believe it does, I think it addresses something different. #1342 bypasses flow-filter in the case when we have a valid, established flow for the packet; if there's no flow in place, it doesn't change the logic (and I expect we'd still get the same logs from stateful NAT as described above, for example). On the contrary, in the current PR, check_nat_requirements() actually checks (and may drop) when there is no flow for the packet.

@Fredi-raspall
Copy link
Contributor

Moved to draft until we clear up the discussion on the relationship with #1342.

What issue does this relate to?

This PR was initially driven by a report about the confusing logs mentioned above, on Slack, I don't think we've got a corresponding issue on GitHub.

Ok. I remember seeing something, somewhere, but could not recall the source.

I think the changes are okay. I have the concern whether this could block legitimate traffic.

Conversely, if we assume in the NAT stages that we only receive traffic that we should indeed NAT, we risk letting packets go through even though they're not legit 🤷. I still prefer the risk of dropping legit traffic.

Also, I believe the error occurs in the multiple matches case, which is not yet covered.

As I replied to Copilot, I've been looking into it.

I'd opt not to add risky logic there and let instead the next NFs drop as they deem, because the checks are already there, but may make a decision when the multiple case match is addressed.

👍 I'll work on completing it

@qmonnet I believe that the approach in #1342 (which we wante to implement anyway) solves the issue.

I don't believe it does, I think it addresses something different. #1342 bypasses flow-filter in the case when we have a valid, established flow for the packet; if there's no flow in place, it doesn't change the logic (and I expect we'd still get the same logs from stateful NAT as described above, for example). On the contrary, in the current PR, check_nat_requirements() actually checks (and may drop) when there is no flow for the packet.

Ok. I see what you mean

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/nat Related to Network Address Translation (NAT)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants