Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 11 Jun 2003 14:20:20 +0300
From:      Ruslan Ermilov <ru@freebsd.org>
To:        Subscriber <subscriber@insignia.com>
Cc:        freebsd-security@freebsd.org
Subject:   Re: IPFW: combining "divert natd" with "keep-state"
Message-ID:  <20030611112020.GA66629@sunbay.com>
In-Reply-To: <2F03DF3DDE57D411AFF4009027B8C36704129AE8@exchange-uk.isltd.insignia.com>
References:  <2F03DF3DDE57D411AFF4009027B8C36704129AE8@exchange-uk.isltd.insignia.com>

next in thread | previous in thread | raw e-mail | index | archive | help

--kfjH4zxOES6UT95V
Content-Type: multipart/mixed; boundary="MfFXiAuoTsnnDAfZ"
Content-Disposition: inline


--MfFXiAuoTsnnDAfZ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Wed, Jun 11, 2003 at 11:05:00AM +0100, Subscriber wrote:
> I've been using ipfw for a while to create a router with NAT
> and packet filtering, but have never combined it with
> stateful filtering, instead using things like "established" to
> accept incoming TCP packets which are part of a conversation
> initiated from the "inside".
>=20
> I'd like to move to using keep-state/check-state to get tighter
> filtering and also to allow outgoing UDP and the replies, which
> currently I block.
>=20
> But I just can't get my head around how to do this. On the way
> out, should the dynamic rules be created to match the pre-NAT
> or post-NAT packets?
>=20
> The man pages are good at explaining both NAT and dynamic
> rules but not both in combination.
>=20
Jim,

Attached is the conversation I had with Luigi Rizzo exactly
three years ago on this topic.  Maybe it is still helpful.


Cheers,
--=20
Ruslan Ermilov		Sysadmin and DBA,
ru@sunbay.com		Sunbay Software Ltd,
ru@FreeBSD.org		FreeBSD committer

--MfFXiAuoTsnnDAfZ
Content-Type: message/rfc822
Content-Disposition: inline

X-UIDL: *A(!!FQ4!!\Y_"!'_F!!
Received: (from ru@localhost) by whale.sunbay.crimea.ua (8.9.3/1.13) id
	XAA08390; Thu, 8 Jun 2000 23:20:52 +0300 (EEST)
Date: Thu, 8 Jun 2000 23:20:52 +0300
From: Ruslan Ermilov <ru@FreeBSD.org>
To: Luigi Rizzo <luigi@FreeBSD.org>
Subject: [IPFW] keep-state/check-state with divert
Message-ID: <20000608232052.A7856@sunbay.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
X-Mailer: Mutt 1.0i

Hi!

I have found an "endless-loop problem" with ipfw when using both
`divert' and `keep-state'/`check-state' rules.  

I was thinking that combining these two features together would
allow me to fix PR conf/13769.  The idea of this problem report
is that people usually block Intranet traffic on their external
interface, and as well use it for NAT purposes.  The problem is
that when incoming packets are dealiased they appear as "coming
IN with Intranet dst_ip through public interface".

Here is what I was thinking about (rl0 - external interface):

: ipfw -f flush
: 
: ipfw add 100 divert natd ip from any to any out via rl0 keep-state
: ipfw add 200 divert natd ip from any to any in via rl0
: ipfw add 300 check-state
: ipfw add 400 deny log ip from any to any in via rl0
: 
: ipfw add 500 allow ip from any to any

But unfortunately this does not work, and this creates an infinite
loop for rule 100, i.e. outgoing packet is first aliased (rule 100),
then passed to rule 200, then 300, which triggers (the dynamic) rule
100:

Script started on Thu Jun  8 21:47:35 2000
perl# ipfw show; sleep 0.5; ipfw sh; sleep 0.5; ipfw show
00100 382707 26024076 divert 8668 ip from any to any keep-state out xmit rl0
00200      0        0 divert 8668 ip from any to any in recv rl0
00300      0        0 check-state
00400      0        0 deny log ip from any to any in recv rl0
00500      0        0 allow ip from any to any
65535      0        0 deny ip from any to any
## Dynamic rules:
00100 382706 26024008 (T 30, # 113) ty 0 udp, local.ip 1654 <-> remote.ip 53

00100 387636 26359248 divert 8668 ip from any to any keep-state out xmit rl0
00200      0        0 divert 8668 ip from any to any in recv rl0
00300      0        0 check-state
00400      0        0 deny log ip from any to any in recv rl0
00500      0        0 allow ip from any to any
65535      0        0 deny ip from any to any
## Dynamic rules:
00100 387635 26359180 (T 30, # 113) ty 0 udp, local.ip 1654 <-> remote.ip 53

00100 392412 26684016 divert 8668 ip from any to any keep-state out xmit rl0
00200      0        0 divert 8668 ip from any to any in recv rl0
00300      0        0 check-state
00400      0        0 deny log ip from any to any in recv rl0
00500      0        0 allow ip from any to any
65535      0        0 deny ip from any to any
## Dynamic rules:
00100 392411 26683948 (T 30, # 113) ty 0 udp, local.ip 1654 <-> remote.ip 53
perl# exit

Script done on Thu Jun  8 21:47:55 2000

It is my understanding, that when a dynamic rule is created, it just copies
protocol, src and dst ip/ports, and action from the original rule, right?
Would it be possible if for `divert' rule the action for dynamic rule will
be `allow'?  Also, I don't like the idea that if the `keep-state' option
is present in the rule, then this rule becomes like a simple `check-state'.
What was the intent for this?  Any thoughts?


Thanks,
-- 
Ruslan Ermilov		Oracle Developer/DBA,
ru@sunbay.com		Sunbay Software AG,
ru@FreeBSD.org		FreeBSD committer,
+380.652.512.251	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age

--MfFXiAuoTsnnDAfZ
Content-Type: message/rfc822
Content-Disposition: inline

X-UIDL: >9Z"!RYk!!E!)"!9`P!!
Received: from hub.freebsd.org (hub.FreeBSD.ORG [204.216.27.18]) by
	whale.sunbay.crimea.ua (8.9.3/1.13) with ESMTP id IAA17127 for
	<ru@sunbay.crimea.ua>; Fri, 9 Jun 2000 08:26:26 +0300 (EEST)
Received: by hub.freebsd.org (Postfix)
	id EA1F537C1C3; Thu,  8 Jun 2000 22:26:07 -0700 (PDT)
Delivered-To: ru@freebsd.org
Received: from info.iet.unipi.it (info.iet.unipi.it [131.114.9.184])
	by hub.freebsd.org (Postfix) with ESMTP
	id 2F81737B669; Thu,  8 Jun 2000 22:26:02 -0700 (PDT)
	(envelope-from luigi@info.iet.unipi.it)
Received: (from luigi@localhost)
	by info.iet.unipi.it (8.9.3/8.9.3) id HAA07626;
	Fri, 9 Jun 2000 07:25:34 +0200 (CEST)
	(envelope-from luigi)
From: Luigi Rizzo <luigi@info.iet.unipi.it>
Message-Id: <200006090525.HAA07626@info.iet.unipi.it>
Subject: Re: [IPFW] keep-state/check-state with divert
In-Reply-To: <20000608232052.A7856@sunbay.com> from Ruslan Ermilov at "Jun 8,
 2000 11:20:52 pm"
To: Ruslan Ermilov <ru@FreeBSD.org>
Date: Fri, 9 Jun 2000 07:25:34 +0200 (CEST)
Cc: Luigi Rizzo <luigi@FreeBSD.org>
X-Mailer: ELM [version 2.4ME+ PL61 (25)]
MIME-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit

> Hi!
> 
> I have found an "endless-loop problem" with ipfw when using both
> `divert' and `keep-state'/`check-state' rules.  

what version is this, 3.4 or above ?
But mainly, writing a ruleset which involves divert is tricky
because packets are reinjected into the firewall so you have to
consider the possible paths when laying out your rules.  What
i generally do is a 'skipto' for packets that might need to be
diverted so they do not interfere with the main path.

To summarise, i think the problem is partly with the ruleset,
not just in the ipfw implementation. What i probably agree is
that a check-state should not match dynamic rules with
a lower rule-number (basically the idea of check-state was
to have it near the very beginning of a ruleset, before all
keep-state rules, and after the check for clearly unacceptable
packets).

	cheers
	luigi

> interface, and as well use it for NAT purposes.  The problem is
> that when incoming packets are dealiased they appear as "coming
> IN with Intranet dst_ip through public interface".
> 
> Here is what I was thinking about (rl0 - external interface):
> 
> : ipfw -f flush
> : 
> : ipfw add 100 divert natd ip from any to any out via rl0 keep-state
> : ipfw add 200 divert natd ip from any to any in via rl0
> : ipfw add 300 check-state
> : ipfw add 400 deny log ip from any to any in via rl0
> : 
> : ipfw add 500 allow ip from any to any
> 
> But unfortunately this does not work, and this creates an infinite
> loop for rule 100, i.e. outgoing packet is first aliased (rule 100),
> then passed to rule 200, then 300, which triggers (the dynamic) rule
> 100:
> 
> Script started on Thu Jun  8 21:47:35 2000
> perl# ipfw show; sleep 0.5; ipfw sh; sleep 0.5; ipfw show
> 00100 382707 26024076 divert 8668 ip from any to any keep-state out xmit rl0
> 00200      0        0 divert 8668 ip from any to any in recv rl0
> 00300      0        0 check-state
> 00400      0        0 deny log ip from any to any in recv rl0
> 00500      0        0 allow ip from any to any
> 65535      0        0 deny ip from any to any
> ## Dynamic rules:
> 00100 382706 26024008 (T 30, # 113) ty 0 udp, local.ip 1654 <-> remote.ip 53
> 
> 00100 387636 26359248 divert 8668 ip from any to any keep-state out xmit rl0
> 00200      0        0 divert 8668 ip from any to any in recv rl0
> 00300      0        0 check-state
> 00400      0        0 deny log ip from any to any in recv rl0
> 00500      0        0 allow ip from any to any
> 65535      0        0 deny ip from any to any
> ## Dynamic rules:
> 00100 387635 26359180 (T 30, # 113) ty 0 udp, local.ip 1654 <-> remote.ip 53
> 
> 00100 392412 26684016 divert 8668 ip from any to any keep-state out xmit rl0
> 00200      0        0 divert 8668 ip from any to any in recv rl0
> 00300      0        0 check-state
> 00400      0        0 deny log ip from any to any in recv rl0
> 00500      0        0 allow ip from any to any
> 65535      0        0 deny ip from any to any
> ## Dynamic rules:
> 00100 392411 26683948 (T 30, # 113) ty 0 udp, local.ip 1654 <-> remote.ip 53
> perl# exit
> 
> Script done on Thu Jun  8 21:47:55 2000
> 
> It is my understanding, that when a dynamic rule is created, it just copies
> protocol, src and dst ip/ports, and action from the original rule, right?
> Would it be possible if for `divert' rule the action for dynamic rule will
> be `allow'?  Also, I don't like the idea that if the `keep-state' option
> is present in the rule, then this rule becomes like a simple `check-state'.
> What was the intent for this?  Any thoughts?
> 
> 
> Thanks,
> -- 
> Ruslan Ermilov		Oracle Developer/DBA,
> ru@sunbay.com		Sunbay Software AG,
> ru@FreeBSD.org		FreeBSD committer,
> +380.652.512.251	Simferopol, Ukraine
> 
> http://www.FreeBSD.org	The Power To Serve
> http://www.oracle.com	Enabling The Information Age
> 


--MfFXiAuoTsnnDAfZ
Content-Type: message/rfc822
Content-Disposition: inline

X-UIDL: !ac"!mU@!!'^5"!_][!!
Received: (from ru@localhost) by whale.sunbay.crimea.ua (8.9.3/1.13) id
	KAA75821; Wed, 14 Jun 2000 10:19:53 +0300 (EEST)
Date: Wed, 14 Jun 2000 10:19:53 +0300
From: Ruslan Ermilov <ru@FreeBSD.org>
To: Luigi Rizzo <luigi@FreeBSD.org>
Subject: Re: [IPFW] keep-state/check-state with divert
Message-ID: <20000614101953.A75209@sunbay.com>
References: <20000608232052.A7856@sunbay.com>
	<200006090525.HAA07626@info.iet.unipi.it>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
X-Mailer: Mutt 1.0i
In-Reply-To: <200006090525.HAA07626@info.iet.unipi.it>;
	from luigi@info.iet.unipi.it on Fri, Jun 09, 2000 at 07:25:34AM +0200

On Fri, Jun 09, 2000 at 07:25:34AM +0200, Luigi Rizzo wrote:
> > Hi!
> > 
> > I have found an "endless-loop problem" with ipfw when using both
> > `divert' and `keep-state'/`check-state' rules.  
> 
> what version is this, 3.4 or above ?
> But mainly, writing a ruleset which involves divert is tricky
> because packets are reinjected into the firewall so you have to
> consider the possible paths when laying out your rules.  What
> i generally do is a 'skipto' for packets that might need to be
> diverted so they do not interfere with the main path.
> 
> To summarise, i think the problem is partly with the ruleset,
> not just in the ipfw implementation. What i probably agree is
> that a check-state should not match dynamic rules with
> a lower rule-number (basically the idea of check-state was
> to have it near the very beginning of a ruleset, before all
> keep-state rules, and after the check for clearly unacceptable
> packets).
> 
Yeah, it was really tricky:

: ipfw -f flush
: ipfw add 100 divert natd ip from any to any via rl0 in
: ipfw add 200 check-state
: ipfw add 300 deny ip from 192.168.0.0/16 to any in via rl0
: ipfw add 300 deny ip from any to 192.168.0.0/16 in via rl0
: ipfw add 400 skipto 500 ip from any to any out via rl0 keep-state
: ipfw add 500 divert natd ip from any to any out via rl0
: ipfw add 600 deny ip from 192.168.0.0/16 to any out via rl0
: ipfw add 600 deny ip from any to 192.168.0.0/16 out via rl0
: ipfw add 65000 allow ip from any to any


Cheers,
-- 
Ruslan Ermilov		Oracle Developer/DBA,
ru@sunbay.com		Sunbay Software AG,
ru@FreeBSD.org		FreeBSD committer,
+380.652.512.251	Simferopol, Ukraine

http://www.FreeBSD.org	The Power To Serve
http://www.oracle.com	Enabling The Information Age

--MfFXiAuoTsnnDAfZ--

--kfjH4zxOES6UT95V
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (FreeBSD)

iD8DBQE+5xBzUkv4P6juNwoRAoB7AJ0WbR8wXeIpad7LpgICcJzH9Fr5BgCfQAur
Dcy5mogk39hF6WMSo18LdZA=
=iUQH
-----END PGP SIGNATURE-----

--kfjH4zxOES6UT95V--



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