From cti.wnc.nedlloyd.nl!wilfred Tue Jul 18 07:57:31 1995
Return-Path: <wilfred@cti.wnc.nedlloyd.nl>
Received: from sun4nl.NL.net by iiit.swan.ac.uk  with smtp
	(Linux Smail3.1.28.1 #8) id m0sY6aw-00013zC; Tue, 18 Jul 95 07:57 BST
Received: from rtmrd1 by sun4nl.NL.net via EUnet
	id AA22805 (5.65b/CWI-3.3); Tue, 18 Jul 1995 09:05:36 +0200
Received: from apollo (apollo.wnc.nedlloyd.nl) by zeus.wnc.nedlloyd.nl (4.1/1.52)
    id AA20638; Tue, 18 Jul 95 09:01:18 +0200
Received: by apollo (4.1/1.52)
    id AA01161; Tue, 18 Jul 95 09:01:17 +0200
From: wilfred@cti.wnc.nedlloyd.nl (Wilfred Mollenvanger)
Message-Id: <9507180701.AA01161@apollo>
Subject: Re: linux kernel: ip_fw
To: iialan@iifeak.swan.ac.uk (Alan Cox)
Date: Tue, 18 Jul 1995 09:01:17 +0200 (MET DST)
In-Reply-To: <m0sXmJS-000142C@iiit.swan.ac.uk> from "Alan Cox" at Jul 17, 95 10:18:05 am
X-Mailer: ELM [version 2.4 PL24 PGP1]
Mime-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Content-Length: 10841     
Status: RO

Hi,

Here are the unified diffs I promised. I also included the patches for
the ipfwadm-1.2 package.


Wilfred.

--- linux/net/ipv4/ip_fw.c	Sun Jun 11 18:46:25 1995
+++ linux.new/net/ipv4/ip_fw.c	Mon Jul 17 19:29:25 1995
@@ -19,6 +19,9 @@
  *	Porting bidirectional entries from BSD, fixing accounting issues,
  *	adding struct ip_fwpkt for checking packets with interface address
  *		Jos Vos 5/Mar/1995.
+ *	Established connections (ACK check), ACK check on bidirectional rules,
+ *	ICMP type check.
+ *		Wilfred Mollenvanger 7/7/1995.
  *
  * Masquerading functionality
  *
@@ -179,10 +182,11 @@
 	struct ip_fw *f;
 	struct tcphdr		*tcp=(struct tcphdr *)((unsigned long *)ip+ip->ihl);
 	struct udphdr		*udp=(struct udphdr *)((unsigned long *)ip+ip->ihl);
+	struct icmphdr		*icmp=(struct icmphdr *)((unsigned long *)ip+ip->ihl);
 	__u32			src, dst;
-	__u16			src_port=0, dst_port=0;
+	__u16			src_port=0, dst_port=0, icmp_type=0;
 	unsigned short		f_prt=0, prt;
-	char			notcpsyn=1, frag1, match;
+	char			notcpsyn=1, notcpack=1, frag1, match;
 	unsigned short		f_flag;
 
 	/*
@@ -233,7 +237,10 @@
 			if (frag1) {
 				src_port=ntohs(tcp->source);
 				dst_port=ntohs(tcp->dest);
-				if(tcp->syn && !tcp->ack)
+				if(tcp->ack)
+					/* We *DO* have ACK, value FALSE */
+					notcpack=0;
+				if(tcp->syn && notcpack)
 					/* We *DO* have SYN, value FALSE */
 					notcpsyn=0;
 			}
@@ -249,7 +256,8 @@
 			prt=IP_FW_F_UDP;
 			break;
 		case IPPROTO_ICMP:
-			dprintf2("ICMP:%d ",((char *)portptr)[0]&0xff);
+			icmp_type=(__u16)(icmp->type);
+			dprintf2("ICMP:%d ",icmp_type);
 			prt=IP_FW_F_ICMP;
 			break;
 		default:
@@ -335,6 +343,21 @@
 			 
 			 if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn)
 			 	continue;
+
+			/*
+			 * When a bidirectional rule is used we only check
+			 * for ack bits on reverse matches. This way it's
+			 * easy to set up rules which only allow connections
+			 * initiated from "normal" match adresses.
+			 */
+
+			if((f->fw_flg&IP_FW_F_TCPACK) && notcpack)
+				if(f->fw_flg&IP_FW_F_BIDIR) {
+					if(match & 0x02)
+						continue;
+				} else
+					continue;
+
 			/*
 			 *	Specific firewall - packet's protocol
 			 *	must match firewall's.
@@ -343,7 +366,10 @@
 			if(prt!=f_prt)
 				continue;
 				
-			if(!(prt==IP_FW_F_ICMP || ((match & 0x01) &&
+			if((prt==IP_FW_F_ICMP &&
+				! port_match(&f->fw_pts[0], f->fw_nsp,
+					icmp_type,f->fw_flg&IP_FW_F_SRNG)) ||
+			    !(prt==IP_FW_F_ICMP || ((match & 0x01) &&
 				port_match(&f->fw_pts[0], f->fw_nsp, src_port,
 					f->fw_flg&IP_FW_F_SRNG) &&
 				port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port,
--- linux/include/linux/ip_fw.h	Tue Jun  6 10:22:11 1995
+++ linux.new/include/linux/ip_fw.h	Sat Jul 15 16:45:48 1995
@@ -87,7 +87,8 @@
 #define IP_FW_F_TCPSYN	0x080	/* For tcp packets-check SYN only     */
 #define IP_FW_F_ICMPRPL 0x100	/* Send back icmp unreachable packet  */
 #define IP_FW_F_MASQ	0x200	/* Masquerading			      */
-#define IP_FW_F_MASK	0x3FF	/* All possible flag bits mask        */
+#define IP_FW_F_TCPACK	0x400	/* For tcp-packets match if ACK is set*/
+#define IP_FW_F_MASK	0x7FF	/* All possible flag bits mask        */
 
 /*    
  *	New IP firewall options for [gs]etsockopt at the RAW IP level.
diff -u ipfwadm-1.2/ipfw.4 ipfwadm-1.2.new/ipfw.4
--- ipfwadm-1.2/ipfw.4	Sun Apr  9 17:16:55 1995
+++ ipfwadm-1.2.new/ipfw.4	Sun Jul 16 21:42:43 1995
@@ -15,6 +15,8 @@
 .\"		E-mail: info@xos.nl
 .\"		WWW:    http://www.xos.nl/
 .\"
+.\"	Add IP_FW_F_TCPACK
+.\"		Wilfred Mollenvanger <wilfred@nedlloyd.nl> 7/7/95.
 .\"
 .\"	This program is free software; you can redistribute it and/or modify
 .\"	it under the terms of the GNU General Public License as published by
@@ -265,6 +267,11 @@
 .B IP_FW_F_TCPSYN
 (only matches when the SYN bit is set and the ACK bit is cleared
 in the TCP header; this option only applies to rules
+that also have the
+.B IP_FW_F_TCP
+flag set),
+.B IP_FW_F_TCPACK
+(only matches when the ACK bit is set; this option also only applies to rules
 that also have the
 .B IP_FW_F_TCP
 flag set),
diff -u ipfwadm-1.2/ipfwadm.8 ipfwadm-1.2.new/ipfwadm.8
--- ipfwadm-1.2/ipfwadm.8	Sun Apr  9 17:16:55 1995
+++ ipfwadm-1.2.new/ipfwadm.8	Sun Jul 16 19:27:48 1995
@@ -15,6 +15,8 @@
 .\"		E-mail: info@xos.nl
 .\"		WWW:    http://www.xos.nl/
 .\"
+.\"	-g option
+.\"		Wilfred Mollenvanger <wilfred@nedlloyd.nl> 7/7/95.
 .\"
 .\"	This program is free software; you can redistribute it and/or modify
 .\"	it under the terms of the GNU General Public License as published by
@@ -180,6 +182,8 @@
 may not be used in in combination with the check command.
 .TP
 .BR "-S " "\fIaddress\fP[/\fImask\fP] [\fIport\fP ...]"
+.TP
+.BR "-S " "\fIaddress\fP[/\fImask\fP] [\fIICMP type\fP ...]"
 Source specification (mandatory).
 .I Address
 can be either a hostname, a network name, or a plain IP address.
@@ -192,7 +196,8 @@
 is equivalent with
 .IR 255.255.255.0 .
 .sp 0.5
-The source may include one or more port specifications.
+For the tcp and udp protocol the source may include one or more port
+specifications.
 Each of them can either be a service name or a port number.
 One of the port specifications may be a range of ports, in the format
 .IR port : port .
@@ -211,9 +216,14 @@
 .I tcp
 or
 .I udp
-protocol.
+protocol (see below for icmp).
 Also, when the check command is specified, exactly one port is
 required in combination with either of these protocols.
+.sp 0.5
+With the
+.I icmp
+protocol the icmp type can be specified the same way as ports are specified.
+ICMP types are integer values from 0 to 18 defined in <linux/icmp.h>.
 .TP
 .BR "-D " "\fIaddress\fP[/\fImask\fP] [\fIport\fP ...]
 Destination specification (mandatory).
@@ -237,7 +247,9 @@
 .TP
 .BI -b
 Bidirectional mode.
-The rule will match with IP packets in both directions.
+The rule will match with IP packets in both directions. See also the
+.B -g
+option.
 This option is only valid in combination with the add or delete command.
 .TP
 .BI -e
@@ -286,9 +298,20 @@
 option).
 .TP
 .BI -y
-Only match TCP packets with the SYN bit set and the ACK bit cleared.
+Only match TCP packets with the SYN bit set and the ACK bit cleared
+ie the first packet of a connection.
 This option is only valid in combination with the add and delete command
-and the TCP protocol.
+and the TCP protocol. When used with the check command the SYN bit will
+be set.
+.TP
+.BI -g
+Only match TCP packets with the ACK bit set, also known as
+established connections. This option is only valid in combination with
+the add and delete command and the TCP protocol. When used with
+the check command the ACK bit will be set. When this option is used
+in combination with the
+.B -b
+option, only packets with a "reverse" match are checked for the ACK bit.
 .SH FILES
 .I /proc/net/ip_acct
 .br
diff -u ipfwadm-1.2/ipfwadm.c ipfwadm-1.2.new/ipfwadm.c
--- ipfwadm-1.2/ipfwadm.c	Tue Jul 11 21:58:43 1995
+++ ipfwadm-1.2.new/ipfwadm.c	Mon Jul 17 19:23:58 1995
@@ -46,6 +46,9 @@
  *	1.4	Change the usage messages and add a large help text for -h.
  *	1.5	Change code to make "gcc -Wall" happy (and a few of these
  *		warnings were really serious ...).
+ *
+ *      Add tcp ACK check and ICMP type check.
+ *		Wilfred Mollenvanger <wilfred@nedlloyd.nl> 7/7/95.
  */
 
 #include <stdio.h>
@@ -91,6 +94,7 @@
 #define OPT_VERBOSE	0x0200
 #define OPT_PRINTK	0x0400
 #define OPT_EXPANDED	0x0800
+#define OPT_TCPACK	0x1000
 
 #define FMT_NUMERIC	0x0001
 #define FMT_NOCOUNTS	0x0002
@@ -176,7 +180,8 @@
 
 	program = argv[0];
 
-	while ((c = getopt(argc, argv, "ABFadlzfp:chP:S:D:I:beknvxy")) != -1)
+	/* HELP! we're out of meaningfull option letters */
+	while ((c = getopt(argc, argv, "ABFadlzfp:chP:S:D:I:beknvxyg")) != -1)
 		switch (c) {
 		case 'A':
 			if (chain != CHN_NONE)
@@ -298,6 +303,11 @@
 			options |= OPT_TCPSYN;
 			firewall.fw_flg |= IP_FW_F_TCPSYN;
 			break;
+		case 'g':
+			check_option(OPT_TCPACK, 'g');
+			options |= OPT_TCPACK;
+			firewall.fw_flg |= IP_FW_F_TCPACK;
+			break;
 		case '?':
 		default:
 			exit_tryhelp(2);
@@ -341,7 +351,14 @@
 		exit_error(2, "specific protocol required for check command");
 
 	if (firewall.fw_flg & IP_FW_F_TCPSYN && kind != IP_FW_F_TCP)
-		exit_error(2, "SYN option (-s) only allowed for TCP protocol");
+		exit_error(2, "SYN option (-y) only allowed for TCP protocol");
+
+	if (firewall.fw_flg & IP_FW_F_TCPACK && kind != IP_FW_F_TCP)
+		exit_error(2, "ACK option (-g) only allowed for TCP protocol");
+
+	if (firewall.fw_flg & IP_FW_F_TCPACK && firewall.fw_flg & IP_FW_F_TCPSYN)
+		/* well it could make some sense but isn't implemented yet */
+		exit_error(2, "Using both -y and -g makes no sence");
 
 	if ((options & OPT_VIAHOST) && (command & (CMD_LIST | CMD_FLUSH |
 			CMD_RESET | CMD_POLICY)))
@@ -375,8 +392,8 @@
 			(int) firewall.fw_ndp, firewall.fw_flg & IP_FW_F_DRNG);
 	}
 
-	if (kind == IP_FW_F_ICMP && (firewall.fw_nsp != 0 || firewall.fw_ndp != 0))
-		exit_error(2, "no ports allowed with protocol ICMP");
+	if (kind == IP_FW_F_ICMP && firewall.fw_ndp != 0)
+		exit_error(2, "specify ICMP type with source address only");
 	if (kind == IP_FW_F_ALL && (firewall.fw_nsp != 0 || firewall.fw_ndp != 0))
 		exit_error(2, "no ports allowed without specific protocol");
 	else if (command == CMD_CHECK && kind != IP_FW_F_ICMP &&
@@ -975,7 +992,7 @@
 			fputs("typ ", fp);
 		fputs("prot ", fp);
 		if (format & FMT_OPTIONS)
-			fputs("opt ", fp);
+			fputs("opt  ", fp);
 		if (format & FMT_VIAHOST)
 			fprintf(fp, FMT("%-15s ","(%s) "), "interface");
 		fprintf(fp, FMT("%-20s ","%s "), "source");
@@ -1040,6 +1057,7 @@
 			fputs("opt ", fp);
 		fputc((flags & IP_FW_F_BIDIR) ? 'b' : '-', fp);
 		fputc((flags & IP_FW_F_TCPSYN) ? 'y' : '-', fp);
+		fputc((flags & IP_FW_F_TCPACK) ? 'g' : '-', fp);
 		fputc((flags & IP_FW_F_PRN) ? 'k' : '-', fp);
 		fputc(' ', fp);
 	}
@@ -1077,7 +1095,7 @@
 	if (format & FMT_NOTABLE)
 		fputs("  ", fp);
 
-	if (kind != IP_FW_F_TCP && kind != IP_FW_F_UDP) {
+	if (kind != IP_FW_F_TCP && kind != IP_FW_F_UDP && kind !=IP_FW_F_ICMP) {
 		fputs(" n/a", fp);
 		if (!(format & FMT_NONEWLINE))
 			putc('\n', fp);
@@ -1099,11 +1117,13 @@
 				fprintf(fp, "%d", fw->fw_pts[i]);
 		}
 
-	fputs(" ->", fp);
+	if(kind !=IP_FW_F_ICMP)
+	    fputs(" ->", fp);
 
-	if (fw->fw_ndp == 0)
+	if (fw->fw_ndp == 0) {
+	    if(kind !=IP_FW_F_ICMP)
 		fputs((format & FMT_NUMERIC) ? " *" : " any", fp);
-	else
+	} else
 		for (i = fw->fw_nsp; i < fw->fw_nsp + fw->fw_ndp; i++) {
 			fputc((i == fw->fw_nsp) ? ' ' : ((flags & IP_FW_F_DRNG &&
 				i == (fw->fw_nsp + 1)) ? ':' : ','), fp);
@@ -1180,6 +1200,7 @@
 		tcph->source = htons(fw->fw_pts[0]);
 		tcph->dest = htons(fw->fw_pts[1]);
 		tcph->syn = (fw->fw_flg & IP_FW_F_TCPSYN) ? 1 : 0;
+		tcph->ack = (fw->fw_flg & IP_FW_F_TCPACK) ? 1 : 0;
 		break;
 	case IP_FW_F_UDP:
 		iph->protocol = IPPROTO_UDP;

