Bug 189655

Summary: [ipfw] ipfw does not pass same_ports option to kernel nat (libalias)
Product: Base System Reporter: Andriy Mayevskyy <major12>
Component: kernAssignee: Andrey V. Elsukov <ae>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 9.2-RELEASE   
Hardware: Any   
OS: Any   

Description Andriy Mayevskyy 2014-05-11 12:20:00 UTC
ipfw command is used to configure kernel nat.
ipfw option 'same_ports' seems to be ignored while configuration and kernel nat (libalias) always behaves like this option was enabled.

E.g.
If we send packet from 10.0.0.5 port 200
with same_ports packed should be aliased (if possible) to <alias_addr>:200
and w/o same_ports to <alias_addr>:<random_port>

Currently packets are aliased to port 200 in both cases
ipfw nat 1 config if em1 same_ports
and
ipfw nat 1 config if em1

Fix: 

I suppose that there is a bug in
sys/netpfil/ipfw/ip_fw_nat.c

LibAliasSetMode has next prototype

/* Change mode for some operations */
unsigned int
LibAliasSetMode(
    struct libalias *la,
    unsigned int flags,		/* Which state to bring flags to */
    unsigned int mask		/* Mask of which flags to affect (use 0 to
				 * do a probe for flag values) */
)

and it is called in wrong way
LibAliasSetMode(ptr->lib, cfg->mode, cfg->mode);

This code will set only the bits that are 1 (ones). But we need to clear bit that is responsible for SAME_PORTS so this bit value should be 0 in mode and 1 in mask.

So since same_ports are enable by default in libalias and ipfw fails to change it we have described incorrect behavior.
How-To-Repeat: Test kernel is:
-------------
ident TEST
options IPFIREWALL
options IPFIREWALL_DEFAULT_TO_ACCEPT
options IPDIVERT
options LIBALIAS
options IPFIREWALL_NAT
include GENERIC
-------------
ipfw is configured in next way:

ipfw nat 1 config if em1
ipfw add 100 nat 1 ip from any to any via em1

Network layout is
client --(em0) natbox (em1)-- internet

At client I use python script to bind to port 200 and send packets to internet.
At natbox I can check packets with tcpdump -n -i em1
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2014-05-13 05:54:36 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-ipfw

Over to maintainer(s).
Comment 2 Andrey V. Elsukov freebsd_committer freebsd_triage 2014-05-16 12:49:10 UTC
Responsible Changed
From-To: freebsd-ipfw->ae

Take it.
Comment 3 Andrey V. Elsukov freebsd_committer freebsd_triage 2014-05-16 15:11:52 UTC
This is a multi-part message in MIME format.
Comment 4 Andriy Mayevskyy 2014-05-18 12:43:47 UTC
With your patch the option works correctly. Good job.

On Fri, May 16, 2014 at 5:11 PM, Andrey V. Elsukov <ae@freebsd.org> wrote:
> Hello, Andriy.
>
> Your analysis is correct. Can you test this patch?
> It looks like this behavior was copied from the ng_nat without any
> change. ng_nat and natd call LibAliasSetMode for each option and it is
> ok for them, but ipfw nat does its configuration in one step, so I think
> it is safe to pass ~0 as mask.
>
> --
> WBR, Andrey V. Elsukov
Comment 5 dfilter service freebsd_committer freebsd_triage 2014-05-18 15:25:23 UTC
Author: ae
Date: Sun May 18 14:25:19 2014
New Revision: 266399
URL: http://svnweb.freebsd.org/changeset/base/266399

Log:
  Since ipfw nat configures all options in one step, we should set all bits
  in the mask when calling LibAliasSetMode() to properly clear unneeded
  options.
  
  PR:		189655
  MFC after:	1 week
  Sponsored by:	Yandex LLC

Modified:
  head/sys/netpfil/ipfw/ip_fw_nat.c

Modified: head/sys/netpfil/ipfw/ip_fw_nat.c
==============================================================================
--- head/sys/netpfil/ipfw/ip_fw_nat.c	Sun May 18 14:18:23 2014	(r266398)
+++ head/sys/netpfil/ipfw/ip_fw_nat.c	Sun May 18 14:25:19 2014	(r266399)
@@ -443,7 +443,7 @@ ipfw_nat_cfg(struct sockopt *sopt)
 	ptr->ip = cfg->ip;
 	ptr->redir_cnt = cfg->redir_cnt;
 	ptr->mode = cfg->mode;
-	LibAliasSetMode(ptr->lib, cfg->mode, cfg->mode);
+	LibAliasSetMode(ptr->lib, cfg->mode, ~0);
 	LibAliasSetAddress(ptr->lib, ptr->ip);
 	memcpy(ptr->if_name, cfg->if_name, IF_NAMESIZE);
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 6 Andrey V. Elsukov freebsd_committer freebsd_triage 2014-05-18 15:39:36 UTC
State Changed
From-To: open->patched

Patched in head/. Thanks!
Comment 7 dfilter service freebsd_committer freebsd_triage 2014-05-26 08:02:06 UTC
Author: ae
Date: Mon May 26 07:02:03 2014
New Revision: 266678
URL: http://svnweb.freebsd.org/changeset/base/266678

Log:
  MFC r266399:
    Since ipfw nat configures all options in one step, we should set all bits
    in the mask when calling LibAliasSetMode() to properly clear unneeded
    options.
  
    PR:		189655

Modified:
  stable/10/sys/netpfil/ipfw/ip_fw_nat.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/netpfil/ipfw/ip_fw_nat.c
==============================================================================
--- stable/10/sys/netpfil/ipfw/ip_fw_nat.c	Mon May 26 02:19:50 2014	(r266677)
+++ stable/10/sys/netpfil/ipfw/ip_fw_nat.c	Mon May 26 07:02:03 2014	(r266678)
@@ -441,7 +441,7 @@ ipfw_nat_cfg(struct sockopt *sopt)
 	ptr->ip = cfg->ip;
 	ptr->redir_cnt = cfg->redir_cnt;
 	ptr->mode = cfg->mode;
-	LibAliasSetMode(ptr->lib, cfg->mode, cfg->mode);
+	LibAliasSetMode(ptr->lib, cfg->mode, ~0);
 	LibAliasSetAddress(ptr->lib, ptr->ip);
 	memcpy(ptr->if_name, cfg->if_name, IF_NAMESIZE);
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 8 dfilter service freebsd_committer freebsd_triage 2014-05-26 09:22:38 UTC
Author: ae
Date: Mon May 26 08:22:34 2014
New Revision: 266680
URL: http://svnweb.freebsd.org/changeset/base/266680

Log:
  MFC r266399:
    Since ipfw nat configures all options in one step, we should set all bits
    in the mask when calling LibAliasSetMode() to properly clear unneeded
    options.
  
    PR:		189655
  Approved by:	re (marius)

Modified:
  stable/9/sys/netpfil/ipfw/ip_fw_nat.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/netpfil/   (props changed)

Modified: stable/9/sys/netpfil/ipfw/ip_fw_nat.c
==============================================================================
--- stable/9/sys/netpfil/ipfw/ip_fw_nat.c	Mon May 26 07:04:30 2014	(r266679)
+++ stable/9/sys/netpfil/ipfw/ip_fw_nat.c	Mon May 26 08:22:34 2014	(r266680)
@@ -442,7 +442,7 @@ ipfw_nat_cfg(struct sockopt *sopt)
 	ptr->ip = cfg->ip;
 	ptr->redir_cnt = cfg->redir_cnt;
 	ptr->mode = cfg->mode;
-	LibAliasSetMode(ptr->lib, cfg->mode, cfg->mode);
+	LibAliasSetMode(ptr->lib, cfg->mode, ~0);
 	LibAliasSetAddress(ptr->lib, ptr->ip);
 	memcpy(ptr->if_name, cfg->if_name, IF_NAMESIZE);
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 9 Andrey V. Elsukov freebsd_committer freebsd_triage 2014-05-26 10:16:46 UTC
State Changed
From-To: patched->closed

Merged to stable/9 and stable/10.