Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 15 Feb 2002 15:56:46 -0700
From:      "Aaron D. Gifford" <agifford@infowest.com>
To:        freebsd-net@freebsd.org
Cc:        kudzu@tenebras.com
Subject:   Re: Bug in stateful code? 
Message-ID:  <20020215225647.DBAB521CE8@ns1.infowest.com>

next in thread | raw e-mail | index | archive | help
I use stateful rules and natd together without any trouble.  You just have to 
think through VERY carefully exactly what is happening to each and every 
packet during it's journey and write your rules accordingly.

Let's look at your example ruleset, Michael:

Michael Sierchio (kudzu@tenebras.com) wrote:
>$on = external net = X.Y.Z/24
>$in = internal net = A.B.C/24  (192.168.1.0/24)
>
>the external IP is X.Y.Z.23
>the internal IP is A.B.C.1
>
>firewall rules:
>
>[some static rules...]
>
>$fw add divert natd ip from any to any via $external_interface
>
>$fw add check-state
>
>$fw add allow tcp from $in to any setup keep-state
>$fw add allow udp from $in to any keep-state
>
>$fw add allow tcp from $on to any setup keep-state
>$fw add allow udp from $on to any keep-state
>
>An ssh connection from A.B.C.4 to X.Y.Z.44 causes the following dynamic rules
>to appear:
>
>02400 15 3197 (T 16, slot 760) <-> tcp, X.Y.Z.23 1549<-> X.Y.Z.44 22
>02200 45 9151 (T 296, slot 913) <-> tcp, A.B.C.4 1549<-> X.Y.Z.44 22

After carefully reading your above rules, I can assure you that you're NOT 
seeing a bug at all, and what you see is what I expect SHOULD be happening.

Let's follow a SYN, SYN-ACK, ACK three-way TCP handshake through your ruleset:

Your SYN packet from INSIDE to OUTSIDE first traverses your ruleset IN VIA 
your internal interface.  It MATCHES your rule:

  "$fw add allow tcp from $in to any setup keep-state"

This adds the dynamic rule you see as "A.B.C.4 1549<-> X.Y.Z.44 22".

Next, your packet goes through the list again, this time OUT VIA your 
external interface.  It matches your NAT divert rule, the source address of 
the SYN packet gets changed from A.B.C.4 to A.B.C.1.  This now modified 
packet does NOT MATCH the check-state because the source address differs.  So 
this same SYN packet now matches this rule:

  "$fw add allow tcp from $on to any setup keep-state"

That's the other dynamic rule you see as "X.Y.Z.23 1549<-> X.Y.Z.44 22"

Now let's trace the SYN-ACK packet from X.Y.Z.44 port 22 back to your inside 
machine.  It enters IPFW as a packet IN VIA your external interface, so this 
packet immediately matches your NAT divert rule and is rewritten with a 
DESTINATION address of "A.B.C.D 1549".

This reply packet will NEVER hit your check-state, and that's why the 
dynamic rule "X.Y.Z.23 1549<-> X.Y.Z.44 22" stays in the SYN state until it 
times out. 

Continuing on, the now translated SYN/ACK now hits the check-state and 
MATCHES the dynamic rule "A.B.C.4 1549<-> X.Y.Z.44 22" and that rule's 
timeout is updated just fine.

Now you your inside source sends an ACK packet back to complete the 3-way 
handshake.  This ACK enters as an IN VIA internal interface packet. It 
doesn't match the NAT divert, but it DOES match the "A.B.C.4 1549<-> X.Y.Z.44 
22" check-state rule, and updates the dynamic rule's timeout.

Next it enters your ruleset OUT VIA your external interface, hits the NAT 
divert, and gets translated.  It then continues through the rules.

When it hits check-state, while it DOES match the "X.Y.Z.23 1549<-> X.Y.Z.44 
22" dynamic rule in principal, it FAILS to match because the dynamic rule is 
expecting to see a SYN-ACK response from the remote host FIRST (remember, the 
SYN-ACK never matched this particular dynamic rule).  Thus this dynamic rule 
STILL sits, expecting SYN-ACK.

Since no further rules match, if you default to deny, your ACK packet gets 
dropped/denied.

Is this the behavior you are seeing?

If anyone is interested, I'd be happy to post my ipfw rules I use at home.  I 
have a single Internet visible IP and a few hosts translated sitting behind 
it on a broadband connection.

Aaron out.

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020215225647.DBAB521CE8>