Skip to content

Introduce rule parser to support upcoming stateful rules#184

Open
edi-oai wants to merge 2 commits into
mainfrom
dev/edi/rule-parser
Open

Introduce rule parser to support upcoming stateful rules#184
edi-oai wants to merge 2 commits into
mainfrom
dev/edi/rule-parser

Conversation

@edi-oai

@edi-oai edi-oai commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

The idea is to:

  1. Start with the parser
  2. Implement connection/flow tracking
  3. Later extend it to support more complex rules, e.g. ports, multiple directions, etc.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0dfede19e6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/proxy/mod.rs
.into_iter()
.map(|rule| match rule {
Rule::Stateless(target) => target,
Rule::Stateful { .. } => unreachable!("stateful rules were rejected before conversion"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reject unsupported stateful rules without panicking

When a library caller passes a publicly constructible Rule::Stateful to the public Proxy::new API, this branch panics before the constructor can return its Result. The CLI and control-socket validators do not protect direct library callers, so a validly parsed rule such as "from @host" can crash the process; reject unsupported rules with an error at the constructor boundary instead.

Useful? React with 👍 / 👎.

@edi-oai edi-oai Jul 22, 2026

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.

We do ensure that there are no Rule::Stateful rules in main.rs.

@fkorotkov-oai fkorotkov-oai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not a fan of this syntax in regards to existing "allow"/""block". WhenI'm looking at

--allow="from @host proto tcp port 8080"

I read it as a sentence and after "allow" I want to know what do I allow. For example, in my example of

--allow="IN tcp @host"

I can read it as "allow INbound tcp trafic from host". With the example above my mind can't construct a phrase.

Comment thread lib/proxy/rule.pest

stateful = { direction ~ " "+ ~ target }
direction = { "from" | "to" }
target = @{ ANY+ }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

so port and protocols will be part of "target"?

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.

No, they will be separate to allow composition.

This keeps the grammar unambiguous: targets describe endpoints, while protocol and port are independent match criteria that can be combined with from and to.

@edi-oai

edi-oai commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

I'm not a fan of this syntax in regards to existing "allow"/""block". WhenI'm looking at

--allow="from @host proto tcp port 8080"

I read it as a sentence and after "allow" I want to know what do I allow. For example, in my example of

This rule would allow incoming traffic from the host's TCP port 8080 to the guest, with a nit that proto tcp should probably come first.

Here's an example to allow incoming traffic from the host to the guest's TCP port 8080:

proto tcp from @host to port 8080
--allow="IN tcp @host"

I can read it as "allow INbound tcp trafic from host". With the example above my mind can't construct a phrase.

How do you envision this syntax enabling us to construct more complex rules in the future?

For example, what would the rule look like that allows traffic from @host to a specific port on an @-alias or CIDR inside of a VM or a network of VMs?

For a PF-like language, this is already well thought out:

proto tcp from @host to @-alias port 8080

@fkorotkov-oai

Copy link
Copy Markdown
Collaborator

My concern is that this proposes adopting a full PF-like grammar before Softnet needs one—and we might never need one.

For example, I don’t expect Softnet to support rules such as:

pass in proto tcp from 10.0.0.0/8 port >= 1024 \
    to ! 10.1.2.3 port != ssh

Adopting similar syntax may imply that this level of expressiveness is supported or planned. If we eventually need rules that complex, a multiline configuration file would probably be a better interface than --allow and --block.

For the current single-VM use case, I would keep the syntax simple:

--allow="IN tcp/8080 @host"

If we later need explicit source and destination endpoints, the syntax can evolve naturally:

--allow="IN tcp/8080 from @host to @alias"

That gives us from/to when we actually need them without committing to a full PF-like grammar upfront.

@edi-oai

edi-oai commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

My concern is that this proposes adopting a full PF-like grammar

Nowhere does it propose that, sorry — perhaps I wasn't clear.

It just takes a small subset of what we need right now, while giving us a clear path forward in case we need more extensibility in the future.

From what you're already envisioning above:

--allow="IN tcp/8080 from @host to @alias"

A PF subset would be less ambiguous here, because it associates the port with the specific endpoint:

--allow="proto tcp from @host to @alias port 8080"

This ambiguity can already be seen in simpler rules like:

IN tcp/8080 @host

Does tcp/8080 here actually refer to the source or the destination port of the packet destined to @host?

@edi-oai

edi-oai commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@fkorotkov-oai I think we can combine the in/out direction you proposed with the existing from/to endpoint syntax to remove both ambiguities:

  • in/out explicitly identifies the direction of the packet that establishes the flow
  • from/to identifies the endpoint to which an address or port belongs

Examples:

  • in proto tcp from @host to port 8080 — an inbound flow from @host to TCP port 8080 on the VM
  • out proto tcp to @host port 8080 — an outbound flow from the VM to TCP port 8080 on @host

Implemented in/out in 964014b.

@edi-oai
edi-oai requested a review from fkorotkov-oai July 23, 2026 11:23
@fkorotkov-oai

Copy link
Copy Markdown
Collaborator

What about four tuple format that won't require a grammar:

<DIRECTION> <SERVICE> <RELATION> <REMOTE>

ingress tcp/443 from any
ingress tcp/22 from @host
egress tcp/443 to 10.0.0.0/8
egress udp/53 to any

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.

2 participants