Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 9 May 2011 18:29:48 +0000 (UTC)
From:      Attilio Rao <attilio@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r221705 - stable/8/sys/netinet
Message-ID:  <201105091829.p49ITmnl008028@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: attilio
Date: Mon May  9 18:29:48 2011
New Revision: 221705
URL: http://svn.freebsd.org/changeset/base/221705

Log:
  MFC r221023:
  Add the possibility to verify MD5 hash of incoming TCP packets.
  
  Sponsored by:	Sandvine Incorporated

Modified:
  stable/8/sys/netinet/tcp_input.c
  stable/8/sys/netinet/tcp_subr.c
  stable/8/sys/netinet/tcp_syncache.c
  stable/8/sys/netinet/tcp_var.h
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/netinet/tcp_input.c
==============================================================================
--- stable/8/sys/netinet/tcp_input.c	Mon May  9 18:05:13 2011	(r221704)
+++ stable/8/sys/netinet/tcp_input.c	Mon May  9 18:29:48 2011	(r221705)
@@ -205,6 +205,12 @@ static void	 tcp_xmit_timer(struct tcpcb
 static void	 tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *);
 static void inline
 		 tcp_congestion_exp(struct tcpcb *);
+static void inline 	tcp_fields_to_host(struct tcphdr *);
+#ifdef TCP_SIGNATURE
+static void inline 	tcp_fields_to_net(struct tcphdr *);
+static int inline	tcp_signature_verify_input(struct mbuf *, int, int,
+			    int, struct tcpopt *, struct tcphdr *, u_int);
+#endif
 
 /*
  * Kernel module interface for updating tcpstat.  The argument is an index
@@ -236,6 +242,40 @@ tcp_congestion_exp(struct tcpcb *tp)
 		tp->t_flags |= TF_ECN_SND_CWR;
 }
 
+static inline void
+tcp_fields_to_host(struct tcphdr *th)
+{
+
+	th->th_seq = ntohl(th->th_seq);
+	th->th_ack = ntohl(th->th_ack);
+	th->th_win = ntohs(th->th_win);
+	th->th_urp = ntohs(th->th_urp);
+}
+
+#ifdef TCP_SIGNATURE
+static inline void
+tcp_fields_to_net(struct tcphdr *th)
+{
+
+	th->th_seq = htonl(th->th_seq);
+	th->th_ack = htonl(th->th_ack);
+	th->th_win = htons(th->th_win);
+	th->th_urp = htons(th->th_urp);
+}
+
+static inline int
+tcp_signature_verify_input(struct mbuf *m, int off0, int tlen, int optlen,
+    struct tcpopt *to, struct tcphdr *th, u_int tcpbflag)
+{
+	int ret;
+
+	tcp_fields_to_net(th);
+	ret = tcp_signature_verify(m, off0, tlen, optlen, to, th, tcpbflag);
+	tcp_fields_to_host(th);
+	return (ret);
+}
+#endif
+
 /* Neighbor Discovery, Neighbor Unreachability Detection Upper layer hint. */
 #ifdef INET6
 #define ND6_HINT(tp) \
@@ -315,6 +355,9 @@ tcp_input(struct mbuf *m, int off0)
 	int thflags;
 	int rstreason = 0;	/* For badport_bandlim accounting purposes */
 	uint8_t iptos;
+#ifdef TCP_SIGNATURE
+	uint8_t sig_checked = 0;
+#endif
 #ifdef IPFIREWALL_FORWARD
 	struct m_tag *fwd_tag;
 #endif
@@ -472,10 +515,7 @@ tcp_input(struct mbuf *m, int off0)
 	/*
 	 * Convert TCP protocol specific fields to host format.
 	 */
-	th->th_seq = ntohl(th->th_seq);
-	th->th_ack = ntohl(th->th_ack);
-	th->th_win = ntohs(th->th_win);
-	th->th_urp = ntohs(th->th_urp);
+	tcp_fields_to_host(th);
 
 	/*
 	 * Delay dropping TCP, IP headers, IPv6 ext headers, and TCP options.
@@ -657,8 +697,24 @@ relocked:
 		}
 		INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
 
+#ifdef TCP_SIGNATURE
+		tcp_dooptions(&to, optp, optlen,
+		    (thflags & TH_SYN) ? TO_SYN : 0);
+		if (sig_checked == 0) {
+			tp = intotcpcb(inp);
+			if (tp == NULL || tp->t_state == TCPS_CLOSED) {
+				rstreason = BANDLIM_RST_CLOSEDPORT;
+				goto dropwithreset;
+			}
+			if (!tcp_signature_verify_input(m, off0, tlen, optlen,
+			    &to, th, tp->t_flags))
+				goto dropunlock;
+			sig_checked = 1;
+		}
+#else
 		if (thflags & TH_SYN)
 			tcp_dooptions(&to, optp, optlen, TO_SYN);
+#endif
 		/*
 		 * NB: tcp_twcheck unlocks the INP and frees the mbuf.
 		 */
@@ -817,6 +873,26 @@ relocked:
 			tp = intotcpcb(inp);
 			KASSERT(tp->t_state == TCPS_SYN_RECEIVED,
 			    ("%s: ", __func__));
+#ifdef TCP_SIGNATURE
+			if (sig_checked == 0)  {
+				tcp_dooptions(&to, optp, optlen,
+				    (thflags & TH_SYN) ? TO_SYN : 0);
+				if (!tcp_signature_verify_input(m, off0, tlen,
+				    optlen, &to, th, tp->t_flags)) {
+
+					/*
+					 * In SYN_SENT state if it receives an
+					 * RST, it is allowed for further
+					 * processing.
+					 */
+					if ((thflags & TH_RST) == 0 ||
+					    (tp->t_state == TCPS_SYN_SENT) == 0)
+						goto dropunlock;
+				}
+				sig_checked = 1;
+			}
+#endif
+
 			/*
 			 * Process the segment and the data it
 			 * contains.  tcp_do_segment() consumes
@@ -1021,6 +1097,25 @@ relocked:
 		return;
 	}
 
+#ifdef TCP_SIGNATURE
+	if (sig_checked == 0)  {
+		tcp_dooptions(&to, optp, optlen,
+		    (thflags & TH_SYN) ? TO_SYN : 0);
+		if (!tcp_signature_verify_input(m, off0, tlen, optlen, &to,
+		    th, tp->t_flags)) {
+
+			/*
+			 * In SYN_SENT state if it receives an RST, it is
+			 * allowed for further processing.
+			 */
+			if ((thflags & TH_RST) == 0 ||
+			    (tp->t_state == TCPS_SYN_SENT) == 0)
+				goto dropunlock;
+		}
+		sig_checked = 1;
+	}
+#endif
+
 	/*
 	 * Segment belongs to a connection in SYN_SENT, ESTABLISHED or later
 	 * state.  tcp_do_segment() always consumes the mbuf chain, unlocks

Modified: stable/8/sys/netinet/tcp_subr.c
==============================================================================
--- stable/8/sys/netinet/tcp_subr.c	Mon May  9 18:05:13 2011	(r221704)
+++ stable/8/sys/netinet/tcp_subr.c	Mon May  9 18:29:48 2011	(r221705)
@@ -257,6 +257,12 @@ SYSCTL_VNET_INT(_net_inet_tcp_inflight, 
     &VNET_NAME(tcp_inflight_stab), 0,
     "Inflight Algorithm Stabilization 20 = 2 packets");
 
+#ifdef TCP_SIGNATURE
+static int	tcp_sig_checksigs = 1;
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, signature_verify_input, CTLFLAG_RW,
+    &tcp_sig_checksigs, 0, "Verify RFC2385 digests on inbound traffic");
+#endif
+
 VNET_DEFINE(uma_zone_t, sack_hole_zone);
 #define	V_sack_hole_zone		VNET(sack_hole_zone)
 
@@ -2084,6 +2090,66 @@ tcp_signature_compute(struct mbuf *m, in
 	KEY_FREESAV(&sav);
 	return (0);
 }
+
+/*
+ * Verify the TCP-MD5 hash of a TCP segment. (RFC2385)
+ *
+ * Parameters:
+ * m		pointer to head of mbuf chain
+ * len		length of TCP segment data, excluding options
+ * optlen	length of TCP segment options
+ * buf		pointer to storage for computed MD5 digest
+ * direction	direction of flow (IPSEC_DIR_INBOUND or OUTBOUND)
+ *
+ * Return 1 if successful, otherwise return 0.
+ */
+int
+tcp_signature_verify(struct mbuf *m, int off0, int tlen, int optlen,
+    struct tcpopt *to, struct tcphdr *th, u_int tcpbflag)
+{
+	char tmpdigest[TCP_SIGLEN];
+
+	if (tcp_sig_checksigs == 0)
+		return (1);
+	if ((tcpbflag & TF_SIGNATURE) == 0) {
+		if ((to->to_flags & TOF_SIGNATURE) != 0) {
+
+			/*
+			 * If this socket is not expecting signature but
+			 * the segment contains signature just fail.
+			 */
+			TCPSTAT_INC(tcps_sig_err_sigopt);
+			TCPSTAT_INC(tcps_sig_rcvbadsig);
+			return (0);
+		}
+
+		/* Signature is not expected, and not present in segment. */
+		return (1);
+	}
+
+	/*
+	 * If this socket is expecting signature but the segment does not
+	 * contain any just fail.
+	 */
+	if ((to->to_flags & TOF_SIGNATURE) == 0) {
+		TCPSTAT_INC(tcps_sig_err_nosigopt);
+		TCPSTAT_INC(tcps_sig_rcvbadsig);
+		return (0);
+	}
+	if (tcp_signature_compute(m, off0, tlen, optlen, &tmpdigest[0],
+	    IPSEC_DIR_INBOUND) == -1) {
+		TCPSTAT_INC(tcps_sig_err_buildsig);
+		TCPSTAT_INC(tcps_sig_rcvbadsig);
+		return (0);
+	}
+	
+	if (bcmp(to->to_signature, &tmpdigest[0], TCP_SIGLEN) != 0) {
+		TCPSTAT_INC(tcps_sig_rcvbadsig);
+		return (0);
+	}
+	TCPSTAT_INC(tcps_sig_rcvgoodsig);
+	return (1);
+}
 #endif /* TCP_SIGNATURE */
 
 static int

Modified: stable/8/sys/netinet/tcp_syncache.c
==============================================================================
--- stable/8/sys/netinet/tcp_syncache.c	Mon May  9 18:05:13 2011	(r221704)
+++ stable/8/sys/netinet/tcp_syncache.c	Mon May  9 18:29:48 2011	(r221705)
@@ -1010,7 +1010,8 @@ _syncache_add(struct in_conninfo *inc, s
 	struct syncache_head *sch;
 	struct mbuf *ipopts = NULL;
 	u_int32_t flowtmp;
-	int win, sb_hiwat, ip_ttl, ip_tos, noopt;
+	u_int ltflags;
+	int win, sb_hiwat, ip_ttl, ip_tos;
 	char *s;
 #ifdef INET6
 	int autoflowlabel = 0;
@@ -1043,7 +1044,7 @@ _syncache_add(struct in_conninfo *inc, s
 	ip_tos = inp->inp_ip_tos;
 	win = sbspace(&so->so_rcv);
 	sb_hiwat = so->so_rcv.sb_hiwat;
-	noopt = (tp->t_flags & TF_NOOPT);
+	ltflags = (tp->t_flags & (TF_NOOPT | TF_SIGNATURE));
 
 	/* By the time we drop the lock these should no longer be used. */
 	so = NULL;
@@ -1238,14 +1239,14 @@ _syncache_add(struct in_conninfo *inc, s
 	 * XXX: Currently we always record the option by default and will
 	 * attempt to use it in syncache_respond().
 	 */
-	if (to->to_flags & TOF_SIGNATURE)
+	if (to->to_flags & TOF_SIGNATURE || ltflags & TF_SIGNATURE)
 		sc->sc_flags |= SCF_SIGNATURE;
 #endif
 	if (to->to_flags & TOF_SACKPERM)
 		sc->sc_flags |= SCF_SACK;
 	if (to->to_flags & TOF_MSS)
 		sc->sc_peer_mss = to->to_mss;	/* peer mss may be zero */
-	if (noopt)
+	if (ltflags & TF_NOOPT)
 		sc->sc_flags |= SCF_NOOPT;
 	if ((th->th_flags & (TH_ECE|TH_CWR)) && V_tcp_do_ecn)
 		sc->sc_flags |= SCF_ECN;

Modified: stable/8/sys/netinet/tcp_var.h
==============================================================================
--- stable/8/sys/netinet/tcp_var.h	Mon May  9 18:05:13 2011	(r221704)
+++ stable/8/sys/netinet/tcp_var.h	Mon May  9 18:29:48 2011	(r221705)
@@ -470,7 +470,14 @@ struct	tcpstat {
 	u_long	tcps_ecn_shs;		/* ECN successful handshakes */
 	u_long	tcps_ecn_rcwnd;		/* # times ECN reduced the cwnd */
 
-	u_long	_pad[12];		/* 6 UTO, 6 TBD */
+	/* TCP_SIGNATURE related stats */
+	u_long	tcps_sig_rcvgoodsig;	/* Total matching signature received */
+	u_long	tcps_sig_rcvbadsig;	/* Total bad signature received */
+	u_long	tcps_sig_err_buildsig;	/* Mismatching signature received */
+	u_long	tcps_sig_err_sigopt;	/* No signature expected by socket */
+	u_long	tcps_sig_err_nosigopt;	/* No signature provided by segment */
+
+	u_long	_pad[7];		/* 6 UTO, 1 TBD */
 };
 
 #ifdef _KERNEL
@@ -638,6 +645,8 @@ int	 tcp_twrespond(struct tcptw *, int);
 void	 tcp_setpersist(struct tcpcb *);
 #ifdef TCP_SIGNATURE
 int	 tcp_signature_compute(struct mbuf *, int, int, int, u_char *, u_int);
+int	 tcp_signature_verify(struct mbuf *, int, int, int, struct tcpopt *,
+	    struct tcphdr *, u_int);
 #endif
 void	 tcp_slowtimo(void);
 struct tcptemp *



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