Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 20 Dec 2000 18:56:38 +0100
From:      Jesper Skriver <jesper@skriver.dk>
To:        Don Lewis <Don.Lewis@tsc.tdk.com>
Cc:        Kris Kennaway <kris@FreeBSD.ORG>, Poul-Henning Kamp <phk@critter.freebsd.dk>, security-officer@FreeBSD.ORG, cvs-all@FreeBSD.ORG, freebsd-net@FreeBSD.ORG
Subject:   Re: what to do now ?  Was: cvs commit: src/sys/netinet ip_icmp.c tcp_subr.c tcp_var.h
Message-ID:  <20001220185638.A64470@skriver.dk>
In-Reply-To: <20001220155118.N81814@skriver.dk>; from jesper@skriver.dk on Wed, Dec 20, 2000 at 03:51:18PM %2B0100
References:  <20001218182600.C1856@skriver.dk> <20001219222730.A29741@skriver.dk> <200012201046.CAA19456@salsa.gv.tsc.tdk.com> <20001220155118.N81814@skriver.dk>

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

--HcAYCG3uE/tztfnV
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Wed, Dec 20, 2000 at 03:51:18PM +0100, Jesper Skriver wrote:
> On Wed, Dec 20, 2000 at 02:46:21AM -0800, Don Lewis wrote:
> > } +		/*
> > } +		 * If tcp_sequence is set, then skip sessions where
> > } +		 * the sequence number is not one of a unacknowledged
> > } +		 * packet.
> > } +		 */
> > } +		if ((tcp_sequence) && (tcp_seq_vs_sess(inp, tcp_sequence) == 0)) {
> > }  			inp = inp->inp_list.le_next;
> > }  			continue;
> > 
> > We should pass in an extra flag to indicate if tcp_sequence is valid, since
> > it can legally be zero.
> 
> Ack, will do.

Attached new diff (relative to -current) with this fix.

I think this should be committed, afterwards I'll look at the suggestions
for improvements.

/Jesper

-- 
Jesper Skriver, jesper(at)skriver(dot)dk  -  CCIE #5456
Work:    Network manager @ AS3292 (Tele Danmark DataNetworks)
Private: Geek            @ AS2109 (A much smaller network ;-)

One Unix to rule them all, One Resolver to find them,
One IP to bring them all and in the zone to bind them.

--HcAYCG3uE/tztfnV
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="tcp_drop_icmp_unreach3.diff"

diff -ru src/sys/netinet.old/in_pcb.c src/sys/netinet/in_pcb.c
--- src/sys/netinet.old/in_pcb.c	Sun Dec 17 18:57:24 2000
+++ src/sys/netinet/in_pcb.c	Wed Dec 20 18:28:35 2000
@@ -665,15 +665,20 @@
  * cmds that are uninteresting (e.g., no error in the map).
  * Call the protocol specific routine (if any) to report
  * any errors for each matching socket.
+ *
+ * If tcp_seq_check != 0 it also checks if tcp_sequence is
+ * a valid TCP sequence number for the session.
  */
 void
-in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
+in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify, tcp_sequence, tcp_seq_check)
 	struct inpcbhead *head;
 	struct sockaddr *dst;
 	u_int fport_arg, lport_arg;
 	struct in_addr laddr;
 	int cmd;
 	void (*notify) __P((struct inpcb *, int));
+	u_int32_t tcp_sequence;
+	int tcp_seq_check;
 {
 	register struct inpcb *inp, *oinp;
 	struct in_addr faddr;
@@ -714,6 +719,15 @@
 		    (lport && inp->inp_lport != lport) ||
 		    (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
 		    (fport && inp->inp_fport != fport)) {
+			inp = inp->inp_list.le_next;
+			continue;
+		}
+		/*
+		 * If tcp_seq_check is set, then skip sessions where
+		 * the sequence number is not one of a unacknowledged
+		 * packet.
+		 */
+		if ((tcp_seq_check == 1) && (tcp_seq_vs_sess(inp, tcp_sequence) == 0)) {
 			inp = inp->inp_list.le_next;
 			continue;
 		}
diff -ru src/sys/netinet.old/in_pcb.h src/sys/netinet/in_pcb.h
--- src/sys/netinet.old/in_pcb.h	Sun Dec 17 18:57:24 2000
+++ src/sys/netinet/in_pcb.h	Wed Dec 20 17:33:34 2000
@@ -290,7 +290,8 @@
 			       struct in_addr, u_int, struct in_addr, u_int,
 			       int, struct ifnet *));
 void	in_pcbnotify __P((struct inpcbhead *, struct sockaddr *,
-	    u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int)));
+	    u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int),
+		u_int32_t, int));
 void	in_pcbrehash __P((struct inpcb *));
 int	in_setpeeraddr __P((struct socket *so, struct sockaddr **nam));
 int	in_setsockaddr __P((struct socket *so, struct sockaddr **nam));
diff -ru src/sys/netinet.old/tcp_subr.c src/sys/netinet/tcp_subr.c
--- src/sys/netinet.old/tcp_subr.c	Sun Dec 17 18:57:24 2000
+++ src/sys/netinet/tcp_subr.c	Wed Dec 20 18:34:36 2000
@@ -139,9 +139,20 @@
  * as required by rfc1122 section 3.2.2.1
  */
  
-static int	icmp_admin_prohib_like_rst = 0;
+static int	icmp_admin_prohib_like_rst = 1;
 SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_admin_prohib_like_rst, CTLFLAG_RW,
-	&icmp_admin_prohib_like_rst, 0, "Treat ICMP administratively prohibited messages like TCP RST, rfc1122 section 3.2.2.1");
+	&icmp_admin_prohib_like_rst, 0, 
+	"Treat ICMP administratively prohibited messages like TCP RST, rfc1122 section 3.2.2.1");
+
+/*
+ * When icmp_admin_prohib_like_rst is enabled, only act on
+ * sessions in SYN-SENT state
+ */
+
+static int	icmp_like_rst_syn_sent_only = 1;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, icmp_like_rst_syn_sent_only, CTLFLAG_RW,
+	&icmp_like_rst_syn_sent_only, 0, 
+	"When icmp_admin_prohib_like_rst is enabled, only act on sessions in SYN-SENT state");
 
 static void	tcp_cleartaocache __P((void));
 static void	tcp_notify __P((struct inpcb *, int));
@@ -967,12 +978,23 @@
 	register struct ip *ip = vip;
 	register struct tcphdr *th;
 	void (*notify) __P((struct inpcb *, int)) = tcp_notify;
+	tcp_seq tcp_sequence = 0;
+	int tcp_seq_check = 0;
 
 	if (cmd == PRC_QUENCH)
 		notify = tcp_quench;
-	else if ((icmp_admin_prohib_like_rst == 1) && (cmd == PRC_UNREACH_PORT) && (ip))
+	else if ((icmp_admin_prohib_like_rst == 1) && (cmd == PRC_UNREACH_PORT) && 
+			(ip) && ((IP_VHL_HL(ip->ip_vhl) << 2) == sizeof(struct ip))) {
+		/*
+		 * Only go here if the length of the IP header in the ICMP packet
+		 * is 20 bytes, that is it doesn't have options, if it does have
+		 * options, we will not have the first 8 bytes of the TCP header,
+		 * and thus we cannot match against TCP source/destination port
+		 * numbers and TCP sequence number.
+		 */
+		tcp_seq_check = 1;
 		notify = tcp_drop_syn_sent;
-	else if (cmd == PRC_MSGSIZE)
+	} else if (cmd == PRC_MSGSIZE)
 		notify = tcp_mtudisc;
 	else if (!PRC_IS_REDIRECT(cmd) &&
 		 ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0))
@@ -980,10 +1002,12 @@
 	if (ip) {
 		th = (struct tcphdr *)((caddr_t)ip 
 				       + (IP_VHL_HL(ip->ip_vhl) << 2));
+		if (tcp_seq_check == 1)
+			tcp_sequence = ntohl(th->th_seq);
 		in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport,
-			cmd, notify);
+			cmd, notify, tcp_sequence, tcp_seq_check);
 	} else
-		in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify);
+		in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify, 0, 0);
 }
 
 #ifdef INET6
@@ -1070,6 +1094,30 @@
 #endif /* INET6 */
 
 /*
+ * Check if the supplied TCP sequence number is a sequence number
+ * for a sent but unacknowledged packet on the given TCP session.
+ */
+int
+tcp_seq_vs_sess(inp, tcp_sequence)
+	struct inpcb *inp;
+	tcp_seq tcp_sequence;
+{
+	struct tcpcb *tp = intotcpcb(inp);
+	/*
+	 * If the sequence number is less than that of the last 
+	 * unacknowledged packet, or greater than that of the 
+	 * last sent, the given sequence number is not that
+	 * of a sent but unacknowledged packet for this session.
+	 */
+	if (SEQ_LT(tcp_sequence, tp->snd_una) ||
+			SEQ_GT(tcp_sequence, tp->snd_max)) {
+		return(0);
+	} else {
+		return(1);
+	}
+}
+
+/*
  * When a source quench is received, close congestion window
  * to one segment.  We will gradually open it again as we proceed.
  */
@@ -1086,7 +1134,9 @@
 
 /*
  * When a ICMP unreachable is recieved, drop the
- * TCP connection, but only if in SYN_SENT
+ * TCP connection, depending on the sysctl
+ * icmp_like_rst_syn_sent_only, it only drops
+ * the session if it's in SYN-SENT state
  */
 void
 tcp_drop_syn_sent(inp, errno)
@@ -1094,8 +1144,9 @@
 	int errno;
 {
 	struct tcpcb *tp = intotcpcb(inp);
-	if((tp) && (tp->t_state == TCPS_SYN_SENT))
-			tcp_drop(tp, errno);
+	if((tp) && ((icmp_like_rst_syn_sent_only == 0) || 
+			(tp->t_state == TCPS_SYN_SENT)))
+		tcp_drop(tp, errno);
 }
 
 /*
diff -ru src/sys/netinet.old/tcp_var.h src/sys/netinet/tcp_var.h
--- src/sys/netinet.old/tcp_var.h	Sun Dec 17 18:57:24 2000
+++ src/sys/netinet/tcp_var.h	Tue Dec 19 20:16:54 2000
@@ -392,6 +392,7 @@
 struct tcpcb *
 	 tcp_newtcpcb __P((struct inpcb *));
 int	 tcp_output __P((struct tcpcb *));
+int	 tcp_seq_vs_sess __P((struct inpcb *, tcp_seq));
 void	 tcp_quench __P((struct inpcb *, int));
 void	 tcp_respond __P((struct tcpcb *, void *,
 	    struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int));
diff -ru src/sys/netinet.old/udp_usrreq.c src/sys/netinet/udp_usrreq.c
--- src/sys/netinet.old/udp_usrreq.c	Sun Dec 17 18:57:24 2000
+++ src/sys/netinet/udp_usrreq.c	Wed Dec 20 17:33:00 2000
@@ -512,9 +512,9 @@
 	if (ip) {
 		uh = (struct udphdr *)((caddr_t)ip + (ip->ip_hl << 2));
 		in_pcbnotify(&udb, sa, uh->uh_dport, ip->ip_src, uh->uh_sport,
-			cmd, udp_notify);
+			cmd, udp_notify, 0, 0);
 	} else
-		in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify);
+		in_pcbnotify(&udb, sa, 0, zeroin_addr, 0, cmd, udp_notify, 0, 0);
 }
 
 static int

--HcAYCG3uE/tztfnV--


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




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