On Mon, Oct 16, 2023 at 12:17 PM Andrei Borzenkov <arvidjaar(a)gmail.com> wrote:
On Sun, Oct 15, 2023 at 9:34 PM Mai Ling <mailinglists35(a)gmail.com> wrote:
>
> On Sun, Oct 15, 2023 at 9:04 PM Andrei Borzenkov <arvidjaar(a)gmail.com> wrote:
> >
> > On 15.10.2023 20:31, Mai Ling wrote:
[...]
> > > 2) Why does web can initiate outgoing to anywhere?
> > >
> >
> > Educated guess - because source address does not match your zone definition.
>
> but the tcpdump shows the source address and the zone definition shows
> the same address.
From the host (and firewalld running on thi shost) point of view there
is no forwarding. All packets originated from the local host. The
rules for forwarding between two zones are never involved here. So the
only option I see is to use rich rules in HOST -> ANY policy (which
maps to OUTPUT hook).
So I did create a policy, but traffic still passes. I then removed the
policy and created "--direct" rules: traffic does not pass, as
expected.
What am I doing wrong?
Pasted below all commands and output as reproductible steps on a
minimal installation of RHEL9:
[user@el9 ~]$ sudo nmcli connection modify enp3s0 +ipv4.addresses
192.168.1.22/26
[user@el9 ~]$ sudo nmcli connection modify enp3s0 +ipv4.addresses
192.168.1.44/26
[user@el9 ~]$ sudo nmcli connection modify enp3s0 +ipv4.addresses
192.168.1.55/26
[user@el9 ~]$ sudo nmcli device reapply enp3s0
Connection successfully reapplied to device 'enp3s0'.
[user@el9 ~]$ sudo firewall-cmd --get-active-zones
public
interfaces: enp3s0
[user@el9 ~]$ sudo firewall-cmd --list-all --zone=public
public (active)
target: default
icmp-block-inversion: no
interfaces: enp3s0
sources:
services: cockpit dhcpv6-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
[user@el9 ~]$ sudo firewall-cmd --permanent --new-policy=output
success
[user@el9 ~]$ sudo firewall-cmd --permanent --policy=output --set-target=REJECT
success
[user@el9 ~]$ sudo firewall-cmd --permanent --policy=output
--add-rich-rule='rule family="ipv4" source address="192.168.1.22"
destination address="192.168.1.44" port port="8080"
protocol="tcp"
accept'
success
[user@el9 ~]$ sudo firewall-cmd --permanent --policy=output
--add-ingress-zone=HOST
success
[user@el9 ~]$ sudo firewall-cmd --permanent --policy=output
--add-egress-zone=ANY
success
[user@el9 ~]$ sudo firewall-cmd --reload
success
[user@el9 ~]$ sudo firewall-cmd --info-policy=output
output (active)
priority: -1
target: REJECT
ingress-zones: HOST
egress-zones: ANY
services:
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
rule family="ipv4" source address="192.168.1.22" destination
address="192.168.1.44" port port="8080" protocol="tcp"
accept
[user@el9 ~]$ sudo nft list ruleset
table inet firewalld {
chain mangle_PREROUTING {
type filter hook prerouting priority mangle + 10; policy accept;
jump mangle_PREROUTING_ZONES
}
chain mangle_PREROUTING_POLICIES_pre {
jump mangle_PRE_policy_allow-host-ipv6
}
chain mangle_PREROUTING_ZONES {
iifname "enp3s0" goto mangle_PRE_public
goto mangle_PRE_public
}
chain mangle_PREROUTING_POLICIES_post {
}
chain nat_PREROUTING {
type nat hook prerouting priority dstnat + 10; policy accept;
jump nat_PREROUTING_ZONES
}
chain nat_PREROUTING_POLICIES_pre {
jump nat_PRE_policy_allow-host-ipv6
}
chain nat_PREROUTING_ZONES {
iifname "enp3s0" goto nat_PRE_public
goto nat_PRE_public
}
chain nat_PREROUTING_POLICIES_post {
}
chain nat_POSTROUTING {
type nat hook postrouting priority srcnat + 10; policy accept;
jump nat_POSTROUTING_ZONES
}
chain nat_POSTROUTING_POLICIES_pre {
}
chain nat_POSTROUTING_ZONES {
oifname "enp3s0" goto nat_POST_public
goto nat_POST_public
}
chain nat_POSTROUTING_POLICIES_post {
}
chain nat_OUTPUT {
type nat hook output priority -90; policy accept;
jump nat_OUTPUT_POLICIES_pre
jump nat_OUTPUT_POLICIES_post
}
chain nat_OUTPUT_POLICIES_pre {
jump nat_OUT_policy_output
}
chain nat_OUTPUT_POLICIES_post {
}
chain filter_PREROUTING {
type filter hook prerouting priority filter + 10; policy accept;
icmpv6 type { nd-router-advert, nd-neighbor-solicit } accept
meta nfproto ipv6 fib saddr . mark . iif oif missing drop
}
chain filter_INPUT {
type filter hook input priority filter + 10; policy accept;
ct state { established, related } accept
ct status dnat accept
ct state invalid drop
iifname "lo" accept
jump filter_INPUT_ZONES
reject with icmpx admin-prohibited
}
chain filter_FORWARD {
type filter hook forward priority filter + 10; policy accept;
ct state { established, related } accept
ct status dnat accept
ct state invalid drop
iifname "lo" accept
ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24,
2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28,
2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable
jump filter_FORWARD_ZONES
reject with icmpx admin-prohibited
}
chain filter_OUTPUT {
type filter hook output priority filter + 10; policy accept;
ct state { established, related } accept
oifname "lo" accept
ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24,
2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28,
2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable
jump filter_OUTPUT_POLICIES_pre
jump filter_OUTPUT_POLICIES_post
}
chain filter_INPUT_POLICIES_pre {
jump filter_IN_policy_allow-host-ipv6
}
chain filter_INPUT_ZONES {
iifname "enp3s0" goto filter_IN_public
goto filter_IN_public
}
chain filter_INPUT_POLICIES_post {
}
chain filter_FORWARD_POLICIES_pre {
}
chain filter_FORWARD_ZONES {
iifname "enp3s0" goto filter_FWD_public
goto filter_FWD_public
}
chain filter_FORWARD_POLICIES_post {
}
chain filter_OUTPUT_POLICIES_pre {
jump filter_OUT_policy_output
}
chain filter_OUTPUT_POLICIES_post {
}
...
[default filter IN stripped]
...
[default empty nat stripped]
...
[default empty FWD stripped]
...
[defaults empty nat and mangle stripped]
...
[default allow host ipv6 policy stripped]
...
chain filter_OUT_policy_output {
jump filter_OUT_policy_output_pre
jump filter_OUT_policy_output_log
jump filter_OUT_policy_output_deny
jump filter_OUT_policy_output_allow
jump filter_OUT_policy_output_post
reject with icmpx admin-prohibited
}
chain filter_OUT_policy_output_pre {
}
chain filter_OUT_policy_output_log {
}
chain filter_OUT_policy_output_deny {
}
chain filter_OUT_policy_output_allow {
ip daddr 192.168.1.44 ip saddr 192.168.1.22 tcp dport
8080 ct state { new, untracked } accept
}
chain filter_OUT_policy_output_post {
}
chain nat_OUT_policy_output {
jump nat_OUT_policy_output_pre
jump nat_OUT_policy_output_log
jump nat_OUT_policy_output_deny
jump nat_OUT_policy_output_allow
jump nat_OUT_policy_output_post
}
chain nat_OUT_policy_output_pre {
}
chain nat_OUT_policy_output_log {
}
chain nat_OUT_policy_output_deny {
}
chain nat_OUT_policy_output_allow {
}
chain nat_OUT_policy_output_post {
}
}
[user@el9 ~]$ coproc sudo tcpdump -qnni any -s 1024 -w firewalld.pcap
[1] 15505
[user@el9 ~]$ tcpdump: data link type LINUX_SLL2
dropped privs to tcpdump
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2),
snapshot length 1024 bytes
[user@el9 ~]$ cat api.sh
while true; do ncat -lvk 192.168.13.44 8080 -c '
request=""
while IFS= read -r line; do
line=$(echo "$line" | tr -d "\r")
if echo "$line" | grep -qE "^GET /" ; then
request=$(echo "$line" | cut -d " " -f2)
elif [ "x$line" = x ] ; then
HTTP_RESPONSE="HTTP/1.1 200 OK\r\nContent-Type:
text/plain\r\n\r\nthis is 192.168.13.44 port 8080\r\n"
echo -en "$HTTP_RESPONSE"
break
fi
done'; done
[user@el9 ~]$ cat api2.sh
while true; do ncat -lvk 192.168.13.55 8080 -c '
request=""
while IFS= read -r line; do
line=$(echo "$line" | tr -d "\r")
if echo "$line" | grep -qE "^GET /" ; then
request=$(echo "$line" | cut -d " " -f2)
elif [ "x$line" = x ] ; then
HTTP_RESPONSE="HTTP/1.1 200 OK\r\nContent-Type:
text/plain\r\n\r\nthis is 192.168.13.55 port 8080\r\n"
echo -en "$HTTP_RESPONSE"
break
fi
done'; done
[user@el9 ~]$ http_proxy='' ALL_PROXY='' curl --interface 192.168.1.22
-m1 -v 192.168.1.55:8080
* Trying 192.168.1.55:8080...
* Name '192.168.1.22' family 2 resolved to '192.168.1.22' family 2
* Local port: 0
* Connected to 192.168.1.55 (192.168.1.55) port 8080 (#0)
GET / HTTP/1.1
Host: 192.168.1.55:8080
User-Agent: curl/7.76.1
Accept: */*
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/plain
* no chunk, no close, no size. Assume close to signal end
<
this is 192.168.1.55 port 8080
* Closing connection 0
[user@el9 ~]$ http_proxy='' ALL_PROXY='' curl --interface 192.168.1.22
-m1 -v 192.168.1.44:8080
* Trying 192.168.1.44:8080...
* Name '192.168.1.22' family 2 resolved to '192.168.1.22' family 2
* Local port: 0
* Connected to 192.168.1.44 (192.168.1.44) port 8080 (#0)
GET / HTTP/1.1
Host: 192.168.1.44:8080
User-Agent: curl/7.76.1
Accept: */*
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/plain
* no chunk, no close, no size. Assume close to signal end
<
this is 192.168.1.44 port 8080
* Closing connection 0
[user@el9 ~]$ tcpdump -qnnr firewalld.pcap
reading from file firewalld.pcap, link-type LINUX_SLL2 (Linux cooked
v2), snapshot length 1024
Warning: interface names might be incorrect
02:25:46.893238 enp3s0 M IP 192.168.1.30.25353 > 224.0.0.249.25353:
UDP, length 41
02:25:46.893372 enp3s0 M IP 192.168.1.30.25353 > 224.0.0.249.25353:
UDP, length 477
02:25:52.353101 lo In IP 192.168.1.22.59448 > 192.168.1.55.8080: tcp 0
02:25:52.353122 lo In IP 192.168.1.55.8080 > 192.168.1.22.59448: tcp 0
02:25:52.353138 lo In IP 192.168.1.22.59448 > 192.168.1.55.8080: tcp 0
02:25:52.353482 lo In IP 192.168.1.22.59448 > 192.168.1.55.8080: tcp 82
02:25:52.353492 lo In IP 192.168.1.55.8080 > 192.168.1.22.59448: tcp 0
02:25:52.379587 lo In IP 192.168.1.55.8080 > 192.168.1.22.59448: tcp 78
02:25:52.379615 lo In IP 192.168.1.22.59448 > 192.168.1.55.8080: tcp 0
02:25:52.379681 lo In IP 192.168.1.55.8080 > 192.168.1.22.59448: tcp 0
02:25:52.379837 lo In IP 192.168.1.22.59448 > 192.168.1.55.8080: tcp 0
02:25:52.379878 lo In IP 192.168.1.55.8080 > 192.168.1.22.59448: tcp 0
02:25:56.990959 lo In IP 192.168.1.22.33200 > 192.168.1.44.8080: tcp 0
02:25:56.991004 lo In IP 192.168.1.44.8080 > 192.168.1.22.33200: tcp 0
02:25:56.991033 lo In IP 192.168.1.22.33200 > 192.168.1.44.8080: tcp 0
02:25:56.991124 lo In IP 192.168.1.22.33200 > 192.168.1.44.8080: tcp 82
02:25:56.991133 lo In IP 192.168.1.44.8080 > 192.168.1.22.33200: tcp 0
02:25:57.017231 lo In IP 192.168.1.44.8080 > 192.168.1.22.33200: tcp 78
02:25:57.017268 lo In IP 192.168.1.22.33200 > 192.168.1.44.8080: tcp 0
02:25:57.017511 lo In IP 192.168.1.44.8080 > 192.168.1.22.33200: tcp 0
02:25:57.017605 lo In IP 192.168.1.22.33200 > 192.168.1.44.8080: tcp 0
02:25:57.017671 lo In IP 192.168.1.44.8080 > 192.168.1.22.33200: tcp 0
[user@el9 ~]$ sudo firewall-cmd --direct --add-rule ipv4 filter OUTPUT
1000 -p tcp -s 192.168.1.22 -d 192.168.1.44 --dport 8080 -j ACCEPT
success
[user@el9 ~]$ sudo firewall-cmd --direct --add-rule ipv4 filter OUTPUT
1500 -s 192.168.1.22 -j LOG --log-prefix 'REJECT: ' --log-level 1
success
[user@el9 ~]$ sudo firewall-cmd --direct --add-rule ipv4 filter OUTPUT
2000 -s 192.168.1.22 -j REJECT
success
[user@el9 ~]$ sudo firewall-cmd --direct --get-all-rules
ipv4 filter OUTPUT 1000 -p tcp -s 192.168.1.22 -d 192.168.1.44 --dport
8080 -j ACCEPT
ipv4 filter OUTPUT 1500 -s 192.168.1.22 -j LOG --log-prefix 'REJECT: '
--log-level 1
ipv4 filter OUTPUT 2000 -s 192.168.1.22 -j REJECT
[user@el9 ~]$ sudo nft list ruleset
table ip filter {
chain OUTPUT {
type filter hook output priority filter; policy accept;
ip saddr 192.168.1.22 ip daddr 192.168.1.44 tcp dport
8080 counter packets 0 bytes 0 accept
ip saddr 192.168.1.22 counter packets 0 bytes 0 log
prefix "REJECT: " level alert
ip saddr 192.168.1.22 counter packets 0 bytes 0 reject
}
}
[...]
[user@el9 ~]$ http_proxy='' ALL_PROXY='' curl --interface 192.168.1.22
-m1 -v 192.168.1.44:8080
* Trying 192.168.1.44:8080...
* Name '192.168.1.22' family 2 resolved to '192.168.1.22' family 2
* Local port: 0
* Connected to 192.168.1.44 (192.168.1.44) port 8080 (#0)
GET / HTTP/1.1
Host: 192.168.1.44:8080
User-Agent: curl/7.76.1
Accept: */*
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/plain
* no chunk, no close, no size. Assume close to signal end
<
this is 192.168.1.44 port 8080
* Closing connection 0
[user@el9 ~]$ http_proxy='' ALL_PROXY='' curl --interface 192.168.1.22
-m1 -v 192.168.1.55:8080
* Trying 192.168.1.55:8080...
* Name '192.168.1.22' family 2 resolved to '192.168.1.22' family 2
* Local port: 0
* connect to 192.168.1.55 port 8080 failed: Connection refused
* Failed to connect to 192.168.1.55 port 8080: Connection refused
* Closing connection 0
curl: (7) Failed to connect to 192.168.1.55 port 8080: Connection refused
[user@el9 ~]$ tcpdump -qnnr firewalld.pcap
reading from file firewalld.pcap, link-type LINUX_SLL2 (Linux cooked
v2), snapshot length 1024
Warning: interface names might be incorrect
02:33:00.098612 lo In IP 192.168.1.22.38738 > 192.168.1.44.8080: tcp 0
02:33:00.098642 lo In IP 192.168.1.44.8080 > 192.168.1.22.38738: tcp 0
02:33:00.098660 lo In IP 192.168.1.22.38738 > 192.168.1.44.8080: tcp 0
02:33:00.098727 lo In IP 192.168.1.22.38738 > 192.168.1.44.8080: tcp 82
02:33:00.098735 lo In IP 192.168.1.44.8080 > 192.168.1.22.38738: tcp 0
02:33:00.125065 lo In IP 192.168.1.44.8080 > 192.168.1.22.38738: tcp 78
02:33:00.125096 lo In IP 192.168.1.22.38738 > 192.168.1.44.8080: tcp 0
02:33:00.125185 lo In IP 192.168.1.44.8080 > 192.168.1.22.38738: tcp 0
02:33:00.125338 lo In IP 192.168.1.22.38738 > 192.168.1.44.8080: tcp 0
02:33:00.125362 lo In IP 192.168.1.44.8080 > 192.168.1.22.38738: tcp 0
02:33:03.959440 lo In IP 192.168.1.55 > 192.168.1.22: ICMP
192.168.1.55 tcp port 8080 unreachable, length 68
[user@el9 ~]$ journalctl -kb|tail -2
Oct 20 02:28:50 el9 kernel: Warning: Deprecated Driver is detected:
nft_compat will not be maintained in a future major release and may be
disabled
Oct 20 02:33:03 el9 kernel: REJECT: IN= OUT=lo SRC=192.168.1.22
DST=192.168.1.55 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=20926 DF
PROTO=TCP SPT=40286 DPT=8080 WINDOW=65495 RES=0x00 SYN URGP=0