Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 27 May 2018 23:32:35 +0800
From:      Julian Elischer <julian@freebsd.org>
To:        Jeff <freebsd@wagsky.com>, freebsd-ipfw@freebsd.org
Subject:   Re: Unexpected behavior ipfw check-state with count tag or call
Message-ID:  <a1c2f4e4-10e4-0de7-6d57-b01c1955560e@freebsd.org>
In-Reply-To: <583c0634-c87c-5502-300b-6450253f71a7@wagsky.com>
References:  <583c0634-c87c-5502-300b-6450253f71a7@wagsky.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On 27/5/18 9:03 am, Jeff wrote:
> TL;DR
>
> If an ipfw rule's action is "count [tag]" or "call" and initiates a
> keep-state, when the check-state is matched, the execution not only
> performs the action of the original rule, but also the rule
> number. This results in the "continuation" being not where the
> check-state was executed but where the corresponding keep-state is
> numbered.
yes, that is executed though not really documented.

>
> Before I either file a ticket or start to work on the code or docs,
> is this intended behavior?
>
> ---
>
> Context:
>
> IPv4 and NAT -- Capture the "established" connections on egress by use
> of a "count tag XXX keep-state :out-ifN" rule. When a "return" packet
> arrives, the "check-state :out-ifN" would then tag the packet XXX,
> which could be used in identifying it as it flows through the firewall
> as "expected from valid connection", even as its addr:port is modified.
> You can't "accept keep-state" as the packet still needs NAT on the 
> way in.
>
> I've tried "count tag" as well as "call" to "tag ; return" with the 
> same
> results, the "next" rule evaluated is the one following the keep-state
> rule, not the check-state rule.
>
that is expected.
the way it is implemented is that the dynamic rule is basically a 
shortcut to the action part of the static rule that made it.
I didn't write it and it surprised me in the beginning but it can be 
useful as well sometimes.

> (I've still got a couple other things I'm going to try as 
> work-arounds.)
>
>
> Once I've got my rules running here, I'd like to tackle this, but I
> don't know if this is a "documentation weakness", or perhaps
> unintended behavior, based on the man pages and what I've been able to
> find in the code. I know the man page and comments have grown
> organically since I started using ipfw back in the 4.0 days and may
> not be completely up-to-date.
>
> If there's any insight into intent of the code before I dive in, I'd
> certainly appreciate it!
>
> Thanks,
>
> Jeff
>
>
>
>
>
> ipfw(8):
>
>      check-state [:flowname | :any]
>              Checks the packet against the dynamic ruleset.  If a 
> match is
>              found, execute the action associated with the rule which
>              generated this dynamic rule, otherwise move to the next 
> rule.
>
> "action associated with the rule" -- not the rule itself
>
>
>
> ip_fw_dynamic.c has some "interesting" comments:
>
>  * Each dynamic rule holds a pointer to the parent ipfw rule so
>  * we know what action to perform. Dynamic rules are removed when
>  * the parent rule is deleted. This can be changed by dyn_keep_states
>  * sysctl.
>  *
>  * There are some limitations with dynamic rules -- we do not
>  * obey the 'randomized match', and we do not do multiple
>  * passes through the firewall. XXX check the latter!!!
>
>
>
> ip_fw2.c appears to the match/dispatch:
>
> 2191 /*
> 2192  * Found dynamic entry, update stats
> 2193  * and jump to the 'action' part of
> 2194  * the parent rule by setting
> 2195  * f, cmd, l and clearing cmdlen.
> 2196  */
>
> (I haven't pursued the code deeper yet)
>
>
>
>
> Here are the rules used for confirming this behavior
>
>
> 192.168.0.100 is the management interface
> 10.0.0.100 is the "outside" interface, leading to the "true" gateway
> 172.217.11.164 is an IP of www.google.com used to drive outside traffic
>
> 00001 reass
> 00010 allow via lo0
> 00011 deny ip from 127.0.0.0/8 to any
> 00012 deny ip from any to 127.0.0.0/8
> 00013 deny ip from ::1 to any
> 00014 deny ip from any to ::1
> 00020 allow tcp from 192.168.0.100 22 to 192.168.0.100/24 via igb2
> 00021 allow tcp from 192.168.0.100/24 to 192.168.0.100 dst-port 22 
> via igb2
> 00080 skipto 90 log proto tcp src-ip 10.0.0.100 via igb0 dst-ip 
> 172.217.11.164 dst-port 443
> 00081 skipto 90 log proto tcp src-ip 172.217.11.164 src-port 443 
> dst-ip 10.0.0.100 via igb0
> 00092 skipto 2000 log not layer2 in
> 00093 skipto 3000 log not layer2 out recv *
> 00094 skipto 4000 log not layer2 out // not recv *
> 00099 deny log // first-stage dispatch problem
> 02000 count log // ip_input
> 02100 count log tagged 40
> 02104 check-state :IP4_TAG_OUTER_outside log // "established" IPv4 
> connections
> 02500 count log // Inbound "NAT" of IPv4
> 02510 allow log tagged 40 // "established" IPv4 connections,post-NAT
> 02999 deny log // ip_input -- DENY remaining
> 03000 deny log // ip_output -- forwarded
> 04000 count log // ip_output -- common output
> 04204 count log // Outbound "NAT"
> 04304 count log tag 40 xmit igb0 keep-state :IP4_TAG_OUTER_outside
> 04400 allow log tagged 40
> 04999 deny log // ip_output -- common output -- DENY remaining
> 65535 deny ip from any to any
>
> # First packet goes out, tagged keep-state at 4304, accepted at 4400
>
> ipfw: 80 SkipTo 90 TCP 10.0.0.100:45427 172.217.11.164:443 out via igb0
> ipfw: 94 SkipTo 4000 TCP 10.0.0.100:45427 172.217.11.164:443 out via 
> igb0
> ipfw: 4000 Count TCP 10.0.0.100:45427 172.217.11.164:443 out via igb0
> ipfw: 4204 Count TCP 10.0.0.100:45427 172.217.11.164:443 out via igb0
> ipfw: 4304 Count TCP 10.0.0.100:45427 172.217.11.164:443 out via igb0
> ipfw: 4400 Accept TCP 10.0.0.100:45427 172.217.11.164:443 out via igb0
>
> # Return packet comes back, check-state fires at 2104 (as expected)
> # Action is logged as 4304 (location of the keep-state rule)
> # Then continues at 4400 -- UNEXPECTED
>
> ipfw: 81 SkipTo 90 TCP 172.217.11.164:443 10.0.0.100:45427 in via igb0
> ipfw: 92 SkipTo 2000 TCP 172.217.11.164:443 10.0.0.100:45427 in via 
> igb0
> ipfw: 2000 Count TCP 172.217.11.164:443 10.0.0.100:45427 in via igb0
> ipfw: 2104 UNKNOWN TCP 172.217.11.164:443 10.0.0.100:45427 in via igb0
> ipfw: 4304 Count TCP 172.217.11.164:443 10.0.0.100:45427 in via igb0
> ipfw: 4400 Accept TCP 172.217.11.164:443 10.0.0.100:45427 in via igb0
>
> [...]
>
> _______________________________________________
> freebsd-ipfw@freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/freebsd-ipfw
> To unsubscribe, send any mail to "freebsd-ipfw-unsubscribe@freebsd.org"
>
>




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?a1c2f4e4-10e4-0de7-6d57-b01c1955560e>