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

json schema is missing synproxy support #15

Closed
Luap99 opened this issue Mar 11, 2024 · 3 comments · Fixed by #29
Closed

json schema is missing synproxy support #15

Luap99 opened this issue Mar 11, 2024 · 3 comments · Fixed by #29
Labels
bug Something isn't working
Milestone

Comments

@Luap99
Copy link
Contributor

Luap99 commented Mar 11, 2024

some info about synproxy can be found here https://wiki.nftables.org/wiki-nftables/index.php/Synproxy

The field is not documented in the libnftables-json(5) page

some example output for named synproxy

# nft list ruleset
table ip foo {
	synproxy https-synproxy {
		mss 1460
		wscale 7
		timestamp sack-perm
	}

	synproxy other-synproxy {
		mss 1460
		wscale 5
	}

	chain pre {
		type filter hook prerouting priority raw; policy accept;
		tcp dport 8888 tcp flags syn notrack
	}

	chain bar {
		type filter hook forward priority filter; policy accept;
		ct state invalid,untracked synproxy name ip saddr map { 192.168.1.0/24 : "https-synproxy", 192.168.2.0/24 : "other-synproxy" }
	}
}

# nft -j list ruleset | jq
{
  "nftables": [
    {
      "metainfo": {
        "version": "1.0.7",
        "release_name": "Old Doc Yak",
        "json_schema_version": 1
      }
    },
    {
      "table": {
        "family": "ip",
        "name": "foo",
        "handle": 2
      }
    },
    {
      "synproxy": {
        "family": "ip",
        "name": "https-synproxy",
        "table": "foo",
        "handle": 3,
        "mss": 1460,
        "wscale": 7,
        "flags": [
          "timestamp",
          "sack-perm"
        ]
      }
    },
    {
      "synproxy": {
        "family": "ip",
        "name": "other-synproxy",
        "table": "foo",
        "handle": 4,
        "mss": 1460,
        "wscale": 5
      }
    },
    {
      "chain": {
        "family": "ip",
        "table": "foo",
        "name": "pre",
        "handle": 1,
        "type": "filter",
        "hook": "prerouting",
        "prio": -300,
        "policy": "accept"
      }
    },
    {
      "chain": {
        "family": "ip",
        "table": "foo",
        "name": "bar",
        "handle": 2,
        "type": "filter",
        "hook": "forward",
        "prio": 0,
        "policy": "accept"
      }
    },
    {
      "rule": {
        "family": "ip",
        "table": "foo",
        "chain": "pre",
        "handle": 5,
        "expr": [
          {
            "match": {
              "op": "==",
              "left": {
                "payload": {
                  "protocol": "tcp",
                  "field": "dport"
                }
              },
              "right": 8888
            }
          },
          {
            "match": {
              "op": "in",
              "left": {
                "payload": {
                  "protocol": "tcp",
                  "field": "flags"
                }
              },
              "right": "syn"
            }
          },
          {
            "notrack": null
          }
        ]
      }
    },
    {
      "rule": {
        "family": "ip",
        "table": "foo",
        "chain": "bar",
        "handle": 7,
        "expr": [
          {
            "match": {
              "op": "in",
              "left": {
                "ct": {
                  "key": "state"
                }
              },
              "right": [
                "invalid",
                "untracked"
              ]
            }
          },
          {
            "synproxy": {
              "map": {
                "key": {
                  "payload": {
                    "protocol": "ip",
                    "field": "saddr"
                  }
                },
                "data": {
                  "set": [
                    [
                      {
                        "prefix": {
                          "addr": "192.168.1.0",
                          "len": 24
                        }
                      },
                      "https-synproxy"
                    ],
                    [
                      {
                        "prefix": {
                          "addr": "192.168.2.0",
                          "len": 24
                        }
                      },
                      "other-synproxy"
                    ]
                  ]
                }
              }
            }
          }
        ]
      }
    }
  ]
}

and for anonymous synproxy

# nft list ruleset
table ip anon_synproxy_demo {
	chain PRE {
		type filter hook prerouting priority raw; policy accept;
		tcp dport 8888 tcp flags syn notrack
	}

	chain IN {
		type filter hook input priority filter; policy accept;
		tcp dport 8888 ct state invalid,untracked synproxy mss 1460 wscale 7 timestamp sack-perm
		ct state invalid drop
	}
}
root@pholzing-fedora:/home/pholzing/CODE/nftables-rs# nft -j list ruleset | jq
{
  "nftables": [
    {
      "metainfo": {
        "version": "1.0.7",
        "release_name": "Old Doc Yak",
        "json_schema_version": 1
      }
    },
    {
      "table": {
        "family": "ip",
        "name": "anon_synproxy_demo",
        "handle": 3
      }
    },
    {
      "chain": {
        "family": "ip",
        "table": "anon_synproxy_demo",
        "name": "PRE",
        "handle": 1,
        "type": "filter",
        "hook": "prerouting",
        "prio": -300,
        "policy": "accept"
      }
    },
    {
      "chain": {
        "family": "ip",
        "table": "anon_synproxy_demo",
        "name": "IN",
        "handle": 2,
        "type": "filter",
        "hook": "input",
        "prio": 0,
        "policy": "accept"
      }
    },
    {
      "rule": {
        "family": "ip",
        "table": "anon_synproxy_demo",
        "chain": "PRE",
        "handle": 3,
        "expr": [
          {
            "match": {
              "op": "==",
              "left": {
                "payload": {
                  "protocol": "tcp",
                  "field": "dport"
                }
              },
              "right": 8888
            }
          },
          {
            "match": {
              "op": "in",
              "left": {
                "payload": {
                  "protocol": "tcp",
                  "field": "flags"
                }
              },
              "right": "syn"
            }
          },
          {
            "notrack": null
          }
        ]
      }
    },
    {
      "rule": {
        "family": "ip",
        "table": "anon_synproxy_demo",
        "chain": "IN",
        "handle": 4,
        "expr": [
          {
            "match": {
              "op": "==",
              "left": {
                "payload": {
                  "protocol": "tcp",
                  "field": "dport"
                }
              },
              "right": 8888
            }
          },
          {
            "match": {
              "op": "in",
              "left": {
                "ct": {
                  "key": "state"
                }
              },
              "right": [
                "invalid",
                "untracked"
              ]
            }
          },
          {
            "synproxy": {
              "mss": 1460,
              "wscale": 7,
              "flags": [
                "timestamp",
                "sack-perm"
              ]
            }
          }
        ]
      }
    },
    {
      "rule": {
        "family": "ip",
        "table": "anon_synproxy_demo",
        "chain": "IN",
        "handle": 5,
        "expr": [
          {
            "match": {
              "op": "in",
              "left": {
                "ct": {
                  "key": "state"
                }
              },
              "right": "invalid"
            }
          },
          {
            "drop": null
          }
        ]
      }
    }
  ]
}

found originally in containers/netavark#942

@jwhb jwhb added the bug Something isn't working label Mar 16, 2024
@jwhb
Copy link
Member

jwhb commented Mar 17, 2024

Thanks for reporting.

Implementing this will require a little bit of reverse engineering of the JSON API as it's not documented. We can use an nft ruleset that presents all valid forms of the synproxy structure, then:

  • apply that ruleset to nft
  • output as json with nft -j list ruleset.

That will be the reference to work on the schema/expr implementations.

I'll start working on this soon™ unless somebody else jumps in. If there is high demand for this feature, please let me know.

@Luap99
Copy link
Contributor Author

Luap99 commented Mar 17, 2024

Yeah I think there more options in the json that are not documented in libnftables-json(5), there are more options documented in nft(8) but of course they do not show how that looks in the json format. So I agree that we need to reverse engineering the format, that is why I included the example outputs above.

This isn't a priority at all for us (netavark) as we have no need for this feature, the problem for us is/was that unknown rules will break the json deserialization. However with #17 we now have the option to only list rules for our table "netavark" which means that should no longer happen as the rules there will only be added by this lib so it should be theoretically impossible to hit such a case.

@jwhb jwhb mentioned this issue Mar 18, 2024
@jwhb jwhb added this to the v0.5.0 milestone Oct 19, 2024
@jwhb
Copy link
Member

jwhb commented Oct 19, 2024

@Luap99: The SynProxy implementation will be released as v0.5.0 as soon as all PRs are merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants