Skip to content
Search Rocky Linux

    Browse this documentation

    Rocky 10: why direct rules should become policies

    Rocky Linux 10.2 VM with firewalld 2.4.0. In one session: read the deprecation paragraph, add a direct rule, then allow the same service with a policy and compare where each lands in nft.

    Screenshot: public/evidence/firewalld/rocky-direct-vs-policy.png.

    $ man firewalld.direct
    DEPRECATED
    The direct interface has been deprecated. It will be removed in a
    future release. It is superseded by policies, see
    firewalld.policies(5).

    “Will be removed” plus “superseded by policies” is enough to stop writing --direct for new work.

    $ firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 \
    -p tcp --dport 9999 -j ACCEPT
    success
    $ firewall-cmd --reload
    $ nft list ruleset | grep -B4 "dport 9999" | grep chain
    chain INPUT {

    Direct rules land in a bare INPUT chain with no zone association. Three consequences:

    1. zone defaults, logging and rich-rule conditions do not apply;
    2. ordering is manual via the priority number, easy to shadow other rules;
    3. firewall-cmd --list-all never shows them — only --direct --get-all-rules does.
    # firewall-cmd --permanent --new-policy labpolicy
    # firewall-cmd --permanent --policy labpolicy --add-ingress-zone public
    # firewall-cmd --permanent --policy labpolicy --add-egress-zone HOST
    # firewall-cmd --permanent --policy labpolicy --add-port 9997/tcp
    # firewall-cmd --permanent --policy labpolicy --set-target ACCEPT
    # firewall-cmd --reload
    $ firewall-cmd --info-policy=labpolicy
    target: ACCEPT
    ingress-zones: public
    egress-zones: HOST
    ports: 9997/tcp
    $ nft list ruleset | grep -B3 "dport 9997" | grep chain
    chain filter_IN_policy_labpolicy_allow {

    A policy gets its own chain, so it does not overwrite zone rules, and the intent is recorded in the configuration itself: who enters, where to, what is allowed.

    Rocky Linux 10.2: direct to chain INPUT, policy to its own chain

    • One port on a single host: firewall-cmd --add-port in a zone;
    • Source restrictions, logging, rate limiting: rich rules;
    • Forwarding, containers, host-wide intent: policies;
    • --direct: legacy compatibility only.
    1. ingress zone cannot be any — measured INVALID_ZONE: 'any' not among existing zones; use a real zone such as public;
    2. --set-target ACCEPT is broad — it allows the whole zone pair and can shadow the zone’s default deny;
    3. runtime and permanent must match — runtime-only changes vanish on reload.
    • A rule missing from --list-all may live in direct or a policy; check --direct --get-all-rules and --list-policies;
    • Removing a direct rule requires an exact match and fails silently when it does not match;
    • A policy can exist but be inactive — --info-policy shows the state, do not judge by nft chains alone.
    Terminal window
    sudo firewall-cmd --list-policies
    sudo firewall-cmd --permanent --new-policy lab9997
    sudo firewall-cmd --permanent --policy lab9997 --add-ingress-zone public
    sudo firewall-cmd --permanent --policy lab9997 --add-egress-zone HOST
    sudo firewall-cmd --permanent --policy lab9997 --add-port 9997/tcp
    sudo firewall-cmd --permanent --policy lab9997 --set-target ACCEPT
    sudo firewall-cmd --reload
    sudo firewall-cmd --info-policy=lab9997

    Checks:

    1. The policy is active with the expected ingress/egress;
    2. nft list ruleset | grep 9997 shows the allow;
    3. Removing the old direct rule changes nothing;
    4. Delete the policy afterwards.

    常见问题

    Do policies conflict with zones?

    No. They are separate nft chains evaluated in hook order; conflicts usually come from a target that is too permissive.

    Do I still need direct priorities?

    No. Policies express intent through zone pairs and targets instead of manual priority numbers.

    What about an existing direct.xml?

    Export with --direct --get-all-rules, map each rule to a policy or rich rule, verify, then empty direct.xml.