add position to add rule
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s
This commit is contained in:
@@ -255,7 +255,7 @@ class CreateRuleRequest(BaseModel):
|
||||
table: str = Field(..., description="Table name (e.g. filter)", example="filter")
|
||||
chain: str = Field(..., description="Chain name (e.g. forward)", example="forward")
|
||||
expr: Any = Field(..., description="nft JSON expression (machine-readable). This field is required for JSON rule creation.")
|
||||
position: Optional[Any] = Field(None, description="Optional position metadata (if you want to specify insertion position)")
|
||||
position: Optional[int] = Field(None, description="Optional zero-based insertion position (0 = top). If omitted the rule is appended.")
|
||||
comment: Optional[str] = Field(None, description="Optional comment")
|
||||
|
||||
class Config:
|
||||
@@ -264,6 +264,7 @@ class CreateRuleRequest(BaseModel):
|
||||
"family": "bridge",
|
||||
"table": "filter",
|
||||
"chain": "forward",
|
||||
"position": 1,
|
||||
"expr": [{"match": {"left": {"payload": {"protocol": "ip", "field": "protocol"}}, "op": "==", "right": "icmp"}}, {"drop": None}],
|
||||
}
|
||||
}
|
||||
@@ -706,7 +707,7 @@ def list_rules():
|
||||
def create_rule_json(req: CreateRuleRequest):
|
||||
"""
|
||||
Create a rule from JSON (expr required).
|
||||
- Attempts to render expr -> textual fragment and execute: `add rule <family> <table> <chain> <fragment>`
|
||||
- Attempts to render expr -> textual fragment and execute: `add rule <family> <table> <chain> [position N] <fragment>`
|
||||
- If rendering fails: 400 instructing the client to use POST /firewall/raw
|
||||
- Returns ExecResult on success (201) or on error (400) with stdout/stderr in body.
|
||||
- If nft wrapper returns an invalid rc but the command produced no stderr, we double-check the chain
|
||||
@@ -728,7 +729,39 @@ def create_rule_json(req: CreateRuleRequest):
|
||||
)
|
||||
|
||||
expr_text = rendered.strip()
|
||||
cmd = f"add rule {family} {table} {chain} {expr_text}"
|
||||
|
||||
# If a position is provided, try to determine chain length to clamp the position.
|
||||
position_token = ""
|
||||
if req.position is not None:
|
||||
# ensure numeric and non-negative
|
||||
try:
|
||||
pos_candidate = int(req.position)
|
||||
except Exception:
|
||||
raise NftError("position must be an integer >= 0")
|
||||
if pos_candidate < 0:
|
||||
raise NftError("position must be >= 0")
|
||||
|
||||
# attempt to read current ruleset to know chain length
|
||||
try:
|
||||
nft_json = mgr.list_rules_json()
|
||||
custom = build_predictable_ruleset(nft_json)
|
||||
chain_rules: List[Dict[str, Any]] = []
|
||||
for t in custom.get("tables", []):
|
||||
if t.get("family") == family and t.get("name") == table:
|
||||
for ch in t.get("chains", []):
|
||||
if ch.get("name") == chain:
|
||||
chain_rules = ch.get("rules", [])
|
||||
break
|
||||
chain_len = len(chain_rules)
|
||||
# clamp position to [0, chain_len]
|
||||
pos = max(0, min(chain_len, pos_candidate))
|
||||
except Exception:
|
||||
# if we cannot read ruleset, just use provided pos_candidate (server may still accept or fail)
|
||||
pos = pos_candidate
|
||||
|
||||
position_token = f" position {pos}"
|
||||
|
||||
cmd = f"add rule {family} {table} {chain}{position_token} {expr_text}"
|
||||
logger.info("create_rule_json executing command: %s", cmd)
|
||||
|
||||
res = mgr.cmd(cmd)
|
||||
|
||||
Reference in New Issue
Block a user