Networking

Why iptables -C Fails 'Bad Rule' on NAT PREROUTING REDIRECT

Fix iptables -C 'Bad rule (does a matching rule exist?)' error for NAT PREROUTING REDIRECT rules visible in -t nat -L. Learn table mismatch, --to-ports syntax, hostname resolution, nftables issues, and exact verification with -S and iptables-save.

1 answer 1 view

Why does iptables -C report ‘Bad rule (does a matching rule exist in that chain?)’ for a REDIRECT rule visible in the NAT PREROUTING chain?

Issue Description:
The rule appears in iptables -t nat -L output:

Chain PREROUTING (policy ACCEPT)
target prot opt source destination 
REDIRECT tcp -- 109x194x11x11.static-business.msk.ertelecom.ru anywhere tcp dpt:https redir ports 4444
REDIRECT tcp -- 178.218.11.11 anywhere tcp dpt:https redir ports 4444
...

However, checking the specific rule fails:

root@107976:~# iptables -C PREROUTING -s 178.218.11.11 -p tcp --dport 443 -j REDIRECT --to-port 4444
iptables: Bad rule (does a matching rule exist in that chain?).

What is causing this mismatch? How can I correctly verify if the iptables NAT PREROUTING REDIRECT rule matches the specified criteria?

The iptables -C Bad rule error hits when checking a NAT PREROUTING REDIRECT rule because the command defaults to the filter table—no PREROUTING chain there—and your check uses --to-port 4444 while the actual rule likely specifies --to-ports 4444. That tiny syntax mismatch kills the verification, even though iptables -t nat -L shows the rule clearly. Fix it by always adding -t nat and pulling the exact spec from iptables -S or iptables-save; for your 178.218.11.11 HTTPS redirect, try iptables -t nat -C PREROUTING -s 178.218.11.11 -p tcp --dport 443 -j REDIRECT --to-ports 4444.


Contents


Why iptables -C Fails with “Bad rule” on NAT PREROUTING REDIRECT Rules

Ever run iptables -C PREROUTING ... and get slapped with “Bad rule (does a matching rule exist in that chain?)”—even when iptables -t nat -L spits out your REDIRECT rule right there? You’re not alone. This trips up sysadmins daily because iptables -C without -t defaults to the filter table. Filter has INPUT, FORWARD, OUTPUT chains. No PREROUTING. Zip.

Your output shows PREROUTING under NAT: that tcp dpt:https REDIRECT to ports 4444 for 178.218.11.11 (and the hostname version). Perfect for intercepting inbound HTTPS traffic pre-routing decision. But punch in iptables -C PREROUTING -s 178.218.11.11 -p tcp --dport 443 -j REDIRECT --to-port 4444? Boom—filter table lookup fails instantly. No chain, no rule.

A Server Fault thread nails this exact pitfall: user saw NAT rules in -L, but -C bombed without -t nat. Add it, and suddenly your check matches reality. But wait—there’s more. Syntax tweaks (coming up) can still derail it.

Quick test? Run iptables -t filter -L PREROUTING. “No chain/target/match by that name.” That’s your smoking gun.


Understanding iptables Tables: NAT vs Filter and PREROUTING Chain

Iptables isn’t one big rulebook—it’s five tables, each with specialized chains. Filter? Defaults for blocking/allowing traffic (INPUT/FORWARD/OUTPUT). NAT? That’s where magic like PREROUTING lives, rewriting packets before the routing decision.

PREROUTING chain only exists in NAT (and mangle/raw, but NAT’s your spot for REDIRECT). Your rule grabs inbound TCP:443 from 178.218.11.11, bounces it to local port 4444. Why? Proxying HTTPS? MitM setup? Common in reverse proxies or security tools.

Netfilter hook order: PREROUTING (NAT) → routing → INPUT (filter). Miss the table, and -C hunts ghosts. The official iptables man page spells it out: -t table mandatory for non-filter; default is filter since forever.

Picture this table:

Table Key Chains When It Runs Your REDIRECT Fits?
filter INPUT, FORWARD, OUTPUT Post-routing decision No—blocks packets
nat PREROUTING, INPUT, OUTPUT, POSTROUTING Pre/post routing Yes—redirects early
mangle PREROUTING etc. Marking/TOS tweaks Maybe, but not here

No wonder -C without -t nat chokes on PREROUTING.


Correct Syntax for Checking REDIRECT Rules: --to-ports vs --to-port

Syntax is brutal—tiny diffs, massive fails. Your -C uses --to-port 4444. But -L shows “redir ports 4444”. That’s shorthand for --to-ports 4444.

REDIRECT module demands --to-ports (plural) in nat PREROUTING. Supports ranges: --to-ports 1000-2000. --to-port? Invalid there, or single-port only in some contexts. Linux man pages confirm: “REDIRECT --to-ports port[-port]”. Plural. Always.

Your failing command:

iptables -C PREROUTING -s 178.218.11.11 -p tcp --dport 443 -j REDIRECT --to-port 4444

Winning version:

iptables -t nat -C PREROUTING -s 178.218.11.11 -p tcp --dport 443 -j REDIRECT --to-ports 4444

Hostname rule? -s 109x194x11x11.static-business.msk.ertelecom.ru resolves at runtime, but -C needs exact match—IP or resolved form. More on that next.

Test it. If still “Bad rule”? Rule order or partial match. -C requires exact spec match, byte-for-byte.


Extracting Exact Rule Syntax with iptables -S and iptables-save

Guessing syntax? Recipe for pain. Dump the real deal.

First, iptables -t nat -S PREROUTING. Numeric output, full glory:

-A PREROUTING -s 178.218.11.11/32 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 4444

See the /32? Or -m tcp? -L hides matches/modules. Copy-paste that into -C. Boom—verifies.

Pro move: iptables-save | grep PREROUTING; dumps all rules raw, across tables. Grep your IP or “REDIRECT.*4444”. Cyberciti guide pushes this for NAT hunts—handles huge rulesets.

Example from your setup:

# iptables-save | grep -A2 PREROUTING
-A PREROUTING -s 109.194.11.11.static-business.msk.ertelecom.ru/32 -p tcp --dport 443 -j REDIRECT --to-ports 4444
-A PREROUTING -s 178.218.11.11/32 -p tcp --dport 443 -j REDIRECT --to-ports 4444

Now -C with that exact string. No more “Bad rule”.


Handling Hostnames and IP Resolution in iptables Rules

That first rule: 109x194x11x11.static-business.msk.ertelecom.ru. Hostname in -s? Iptables resolves it at insert time via DNS, stores as IP. But -L shows original hostname (reverse lookup magic).

-C? Must match stored IP form. Run host 109.194.11.11.static-business.msk.ertelecom.ru or dig it. Say it resolves to 109.194.11.11—use -s 109.194.11.11 in check.

Mismatch? “Bad rule”. Tricky if DNS changes post-insert. Always -S for truth.

IPv6? ip6tables -t nat. But your case screams IPv4.


nftables Backend Issues and iptables-legacy Workaround

Modern distros (Ubuntu 20+, RHEL 8+) default to nftables backend for iptables commands. Translation layer glitches: “Bad rule” on NAT checks, especially containers/Docker.

Red Hat details flag this—nft rejects some legacy syntax in checks, even if insert worked. Your hostname rule? nftables might mangle resolution.

Switch: update-alternatives --set iptables /usr/sbin/iptables-legacy. Retry -C. Often fixes. Or go native: nft list table nat. Raw ruleset, no compat woes.

Docker users? Host iptables rarely affects container NAT—check nft list table ip nat.


Best Practices: Verify and Test NAT PREROUTING Rules Effectively

Don’t stop at -C. Full audit:

  1. List verbose: iptables -t nat -L PREROUTING -n -v -x. Counters show hits.
  2. Script checks: SuperUser exampleiptables -t nat -C ... 2>/dev/null || echo "Missing".
  3. Test traffic: nc -l 4444; curl from 178.218.11.11:443. lands on 4444?
  4. Backup: iptables-save > rules.v4.
  5. Monitor: watch -n1 'iptables -t nat -L -v -n'.

Edge: Multiport rules? Specify --multiport. Firewalld? firewall-cmd --direct --get-all-rules.

Workflow: -t nat -S → copy → -C → counters → test.


Sources

  1. Server Fault: iptables -C check doesn’t work — Explains table mismatch causing “Bad rule” for PREROUTING: https://serverfault.com/questions/1083046/iptables-c-check-doesnt-work
  2. iptables(8) - Linux man page — Official details on tables, chains, and REDIRECT syntax: https://man7.org/linux/man-pages/man8/iptables.8.html
  3. Linux iptables man page — REDIRECT module specifics including --to-ports requirement: https://linux.die.net/man/8/iptables
  4. Checking iptables PREROUTING NAT rules — Commands for listing and grepping NAT PREROUTING rules: https://www.cyberciti.biz/faq/checking-list-iptables-prerouting-nat-rules-linux-command/
  5. Red Hat: Bad rule error with nftables — nftables compatibility issues in RHEL with iptables NAT: https://access.redhat.com/solutions/6514071
  6. SuperUser: Check if iptables rule exists — Scripting safe rule checks with error suppression: https://superuser.com/questions/360094/how-can-i-check-if-an-iptables-rule-exists

Conclusion

Bottom line: iptables -C Bad rule for NAT PREROUTING REDIRECT stems from missing -t nat, --to-port vs --to-ports, or backend quirks—fix with exact -S dumps. Grab iptables -t nat -S PREROUTING, paste into -C, watch it succeed. Pro tip: Script it, check counters, test live traffic. You’ll nail these redirects every time, no more head‑scratching.

Authors
Verified by moderation
Moderation
Why iptables -C Fails 'Bad Rule' on NAT PREROUTING REDIRECT