Subject: kern/29757: SIOCGNATL can't do inbound lookups
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Peter Postma <peter@pointless.nl>
List: netbsd-bugs
Date: 03/21/2005 21:14:00
>Number:         29757
>Category:       kern
>Synopsis:       SIOCGNATL can't do inbound lookups
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Mon Mar 21 21:14:00 +0000 2005
>Originator:     Peter Postma
>Release:        NetBSD 3.0_BETA
>Organization:
>Environment:
System: NetBSD mercury.pointless.nl 3.0_BETA NetBSD 3.0_BETA (mercury) #135: Thu Mar 17 16:37:29 CET 2005 peter@mercury.pointless.nl:/usr/obj/sys/arch/sparc64/compile/mercury sparc64
Architecture: sparc64
Machine: sparc64
>Description:
SIOCGNATL can do outbound lookups, it looks for the real address when
we know the destination/source addresses & ports.

But it can't do inbound lookups, to look for the source address (on the lan)
when we know the destination/real addresses & ports.

The latter would be useful when doing a lookup on the gateway for an ident
query, you'll need to find the source address then (FYI: I'm currently
working to implement this into identd(8) and it's almost finished).

>How-To-Repeat:
>Fix:
This patch add the flags IPN_IN and IPN_OUT which can be specified in the
natlook struct. If none of these flags are specified, it defaults to the
IPN_OUT lookup (which was also the previous behaviour).

Index: ip_nat.c
===================================================================
RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_nat.c,v
retrieving revision 1.5
diff -u -r1.5 ip_nat.c
--- ip_nat.c	19 Feb 2005 21:30:25 -0000	1.5
+++ ip_nat.c	21 Mar 2005 20:29:56 -0000
@@ -3349,8 +3349,13 @@
 	nat_t *nat;
 
 	bzero((char *)&fi, sizeof(fi));
-	fi.fin_data[0] = ntohs(np->nl_inport);
-	fi.fin_data[1] = ntohs(np->nl_outport);
+	if (np->nl_flags & IPN_IN) {
+		fi.fin_data[0] = ntohs(np->nl_realport);
+		fi.fin_data[1] = ntohs(np->nl_outport);
+	} else {
+		fi.fin_data[0] = ntohs(np->nl_inport);
+		fi.fin_data[1] = ntohs(np->nl_outport);
+	}
 	if (np->nl_flags & IPN_TCP)
 		fi.fin_p = IPPROTO_TCP;
 	else if (np->nl_flags & IPN_UDP)
@@ -3359,14 +3364,28 @@
 		fi.fin_p = IPPROTO_ICMP;
 
 	/*
-	 * If nl_inip is non null, this is a lookup based on the real
-	 * ip address. Else, we use the fake.
+	 * We can do two sorts of lookups:
+	 * - IPN_IN: we have the `real' and `out' address, look for `in'.
+	 * - IPN_OUT: we have the `in' and `out' address, look for `real'.
 	 */
-	if ((nat = nat_outlookup(&fi, np->nl_flags, fi.fin_p, np->nl_inip,
-				 np->nl_outip))) {
-		np->nl_realip = nat->nat_outip;
-		np->nl_realport = nat->nat_outport;
+	if (np->nl_flags & IPN_IN) {
+		if ((nat = nat_inlookup(&fi, np->nl_flags, fi.fin_p,
+		    np->nl_realip, np->nl_outip))) {
+			np->nl_inip = nat->nat_inip;
+			np->nl_inport = nat->nat_inport;
+		}
+	} else {
+		/*
+		 * If nl_inip is non null, this is a lookup based on the real
+		 * ip address. Else, we use the fake.
+		 */
+		if ((nat = nat_outlookup(&fi, np->nl_flags, fi.fin_p,
+		    np->nl_inip, np->nl_outip))) {
+			np->nl_realip = nat->nat_outip;
+			np->nl_realport = nat->nat_outport;
+		}
 	}
+
 	return nat;
 }
 
Index: ip_nat.h
===================================================================
RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_nat.h,v
retrieving revision 1.4
diff -u -r1.4 ip_nat.h
--- ip_nat.h	19 Feb 2005 21:30:25 -0000	1.4
+++ ip_nat.h	21 Mar 2005 20:29:56 -0000
@@ -251,6 +251,8 @@
 #define	IPN_STICKY	0x80000
 #define	IPN_FRAG	0x100000
 #define	IPN_FIXEDDPORT	0x200000
+#define	IPN_IN		0x400000
+#define	IPN_OUT		0x800000
 #define	IPN_USERFLAGS	(IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|IPN_SPLIT|\
 			 IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST|\
 			 IPN_FRAG|IPN_STICKY|IPN_FIXEDDPORT|IPN_ICMPQUERY)