Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 27 Sep 2014 07:04:13 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r272201 - head/sys/netinet
Message-ID:  <201409270704.s8R74Ddr074239@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Sat Sep 27 07:04:12 2014
New Revision: 272201
URL: http://svnweb.freebsd.org/changeset/base/272201

Log:
  * Split tcp_signature_compute() into 2 pieces:
   - tcp_get_sav() - SADB key lookup
   - tcp_signature_do_compute() - actual computation
  * Fix TCP signature case for listening socket:
    do not assume EVERY connection coming to socket
    with TCP_SIGNATURE set to be md5 signed regardless
    of SADB key existance for particular address. This
    fixes the case for routing software having _some_
    BGP sessions secured by md5.
  * Simplify TCP_SIGNATURE handling in tcp_input()
  
  MFC after:	2 weeks

Modified:
  head/sys/netinet/tcp_subr.c
  head/sys/netinet/tcp_syncache.c
  head/sys/netinet/tcp_var.h

Modified: head/sys/netinet/tcp_subr.c
==============================================================================
--- head/sys/netinet/tcp_subr.c	Sat Sep 27 05:50:31 2014	(r272200)
+++ head/sys/netinet/tcp_subr.c	Sat Sep 27 07:04:12 2014	(r272201)
@@ -1928,55 +1928,20 @@ tcp_signature_apply(void *fstate, void *
 }
 
 /*
- * Compute TCP-MD5 hash of a TCP segment. (RFC2385)
- *
- * Parameters:
- * m		pointer to head of mbuf chain
- * _unused	
- * 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)
- *
- * We do this over ip, tcphdr, segment data, and the key in the SADB.
- * When called from tcp_input(), we can be sure that th_sum has been
- * zeroed out and verified already.
- *
- * Return 0 if successful, otherwise return -1.
- *
  * XXX The key is retrieved from the system's PF_KEY SADB, by keying a
  * search with the destination IP address, and a 'magic SPI' to be
  * determined by the application. This is hardcoded elsewhere to 1179
- * right now. Another branch of this code exists which uses the SPD to
- * specify per-application flows but it is unstable.
- */
-int
-tcp_signature_compute(struct mbuf *m, int _unused, int len, int optlen,
-    u_char *buf, u_int direction)
+*/
+struct secasvar *
+tcp_get_sav(struct mbuf *m, u_int direction)
 {
 	union sockaddr_union dst;
-#ifdef INET
-	struct ippseudo ippseudo;
-#endif
-	MD5_CTX ctx;
-	int doff;
-	struct ip *ip;
-#ifdef INET
-	struct ipovly *ipovly;
-#endif
 	struct secasvar *sav;
-	struct tcphdr *th;
+	struct ip *ip;
 #ifdef INET6
 	struct ip6_hdr *ip6;
-	struct in6_addr in6;
 	char ip6buf[INET6_ADDRSTRLEN];
-	uint32_t plen;
-	uint16_t nhdr;
 #endif
-	u_short savecsum;
-
-	KASSERT(m != NULL, ("NULL mbuf chain"));
-	KASSERT(buf != NULL, ("NULL signature pointer"));
 
 	/* Extract the destination from the IP header in the mbuf. */
 	bzero(&dst, sizeof(union sockaddr_union));
@@ -2003,7 +1968,7 @@ tcp_signature_compute(struct mbuf *m, in
 		break;
 #endif
 	default:
-		return (EINVAL);
+		return (NULL);
 		/* NOTREACHED */
 		break;
 	}
@@ -2018,9 +1983,61 @@ tcp_signature_compute(struct mbuf *m, in
 			    ip6_sprintf(ip6buf, &dst.sin6.sin6_addr) :
 #endif
 			"(unsupported)"));
-		return (EINVAL);
 	}
 
+	return (sav);
+}
+
+/*
+ * Compute 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
+ * sav		pointer to security assosiation
+ *
+ * We do this over ip, tcphdr, segment data, and the key in the SADB.
+ * When called from tcp_input(), we can be sure that th_sum has been
+ * zeroed out and verified already.
+ *
+ * Releases reference to SADB key before return. 
+ *
+ * Return 0 if successful, otherwise return -1.
+ *
+ */
+int
+tcp_signature_do_compute(struct mbuf *m, int len, int optlen,
+    u_char *buf, struct secasvar *sav)
+{
+#ifdef INET
+	struct ippseudo ippseudo;
+#endif
+	MD5_CTX ctx;
+	int doff;
+	struct ip *ip;
+#ifdef INET
+	struct ipovly *ipovly;
+#endif
+	struct tcphdr *th;
+#ifdef INET6
+	struct ip6_hdr *ip6;
+	struct in6_addr in6;
+	uint32_t plen;
+	uint16_t nhdr;
+#endif
+	u_short savecsum;
+
+	KASSERT(m != NULL, ("NULL mbuf chain"));
+	KASSERT(buf != NULL, ("NULL signature pointer"));
+
+	/* Extract the destination from the IP header in the mbuf. */
+	ip = mtod(m, struct ip *);
+#ifdef INET6
+	ip6 = NULL;	/* Make the compiler happy. */
+#endif
+
 	MD5Init(&ctx);
 	/*
 	 * Step 1: Update MD5 hash with IP(v6) pseudo-header.
@@ -2077,7 +2094,7 @@ tcp_signature_compute(struct mbuf *m, in
 		break;
 #endif
 	default:
-		return (EINVAL);
+		return (-1);
 		/* NOTREACHED */
 		break;
 	}
@@ -2111,6 +2128,23 @@ tcp_signature_compute(struct mbuf *m, in
 }
 
 /*
+ * Compute TCP-MD5 hash of a TCP segment. (RFC2385)
+ *
+ * Return 0 if successful, otherwise return -1.
+ */
+int
+tcp_signature_compute(struct mbuf *m, int _unused, int len, int optlen,
+    u_char *buf, u_int direction)
+{
+	struct secasvar *sav;
+
+	if ((sav = tcp_get_sav(m, direction)) == NULL)
+		return (-1);
+
+	return (tcp_signature_do_compute(m, len, optlen, buf, sav));
+}
+
+/*
  * Verify the TCP-MD5 hash of a TCP segment. (RFC2385)
  *
  * Parameters:

Modified: head/sys/netinet/tcp_syncache.c
==============================================================================
--- head/sys/netinet/tcp_syncache.c	Sat Sep 27 05:50:31 2014	(r272200)
+++ head/sys/netinet/tcp_syncache.c	Sat Sep 27 07:04:12 2014	(r272201)
@@ -122,7 +122,7 @@ SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO,
 static void	 syncache_drop(struct syncache *, struct syncache_head *);
 static void	 syncache_free(struct syncache *);
 static void	 syncache_insert(struct syncache *, struct syncache_head *);
-static int	 syncache_respond(struct syncache *);
+static int	 syncache_respond(struct syncache *, struct syncache_head *, int);
 static struct	 socket *syncache_socket(struct syncache *, struct socket *,
 		    struct mbuf *m);
 static void	 syncache_timeout(struct syncache *sc, struct syncache_head *sch,
@@ -467,7 +467,7 @@ syncache_timer(void *xsch)
 			free(s, M_TCPLOG);
 		}
 
-		(void) syncache_respond(sc);
+		syncache_respond(sc, sch, 1);
 		TCPSTAT_INC(tcps_sc_retransmitted);
 		syncache_timeout(sc, sch, 0);
 	}
@@ -1213,7 +1213,7 @@ syncache_add(struct in_conninfo *inc, st
 			    s, __func__);
 			free(s, M_TCPLOG);
 		}
-		if (syncache_respond(sc) == 0) {
+		if (syncache_respond(sc, sch, 1) == 0) {
 			sc->sc_rxmits = 0;
 			syncache_timeout(sc, sch, 1);
 			TCPSTAT_INC(tcps_sndacks);
@@ -1325,11 +1325,9 @@ syncache_add(struct in_conninfo *inc, st
 	}
 #ifdef TCP_SIGNATURE
 	/*
-	 * If listening socket requested TCP digests, and received SYN
+	 * If listening socket requested TCP digests, OR received SYN
 	 * contains the option, flag this in the syncache so that
 	 * syncache_respond() will do the right thing with the SYN+ACK.
-	 * XXX: Currently we always record the option by default and will
-	 * attempt to use it in syncache_respond().
 	 */
 	if (to->to_flags & TOF_SIGNATURE || ltflags & TF_SIGNATURE)
 		sc->sc_flags |= SCF_SIGNATURE;
@@ -1359,7 +1357,7 @@ syncache_add(struct in_conninfo *inc, st
 	/*
 	 * Do a standard 3-way handshake.
 	 */
-	if (syncache_respond(sc) == 0) {
+	if (syncache_respond(sc, sch, 0) == 0) {
 		if (V_tcp_syncookies && V_tcp_syncookiesonly && sc != &scs)
 			syncache_free(sc);
 		else if (sc != &scs)
@@ -1387,7 +1385,7 @@ done:
 }
 
 static int
-syncache_respond(struct syncache *sc)
+syncache_respond(struct syncache *sc, struct syncache_head *sch, int locked)
 {
 	struct ip *ip = NULL;
 	struct mbuf *m;
@@ -1398,6 +1396,9 @@ syncache_respond(struct syncache *sc)
 #ifdef INET6
 	struct ip6_hdr *ip6 = NULL;
 #endif
+#ifdef TCP_SIGNATURE
+	struct secasvar *sav;
+#endif
 
 	hlen =
 #ifdef INET6
@@ -1508,8 +1509,29 @@ syncache_respond(struct syncache *sc)
 		if (sc->sc_flags & SCF_SACK)
 			to.to_flags |= TOF_SACKPERM;
 #ifdef TCP_SIGNATURE
-		if (sc->sc_flags & SCF_SIGNATURE)
-			to.to_flags |= TOF_SIGNATURE;
+		sav = NULL;
+		if (sc->sc_flags & SCF_SIGNATURE) {
+			sav = tcp_get_sav(m, IPSEC_DIR_OUTBOUND);
+			if (sav != NULL)
+				to.to_flags |= TOF_SIGNATURE;
+			else {
+
+				/*
+				 * We've got SCF_SIGNATURE flag
+				 * inherited from listening socket,
+				 * but to SADB key for given source
+				 * address. Assume signature is not
+				 * required and remove signature flag
+				 * instead of silently dropping
+				 * connection.
+				 */
+				if (locked == 0)
+					SCH_LOCK(sch);
+				sc->sc_flags &= ~SCF_SIGNATURE;
+				if (locked == 0)
+					SCH_UNLOCK(sch);
+			}
+		}
 #endif
 		optlen = tcp_addoptions(&to, (u_char *)(th + 1));
 
@@ -1520,8 +1542,8 @@ syncache_respond(struct syncache *sc)
 
 #ifdef TCP_SIGNATURE
 		if (sc->sc_flags & SCF_SIGNATURE)
-			tcp_signature_compute(m, 0, 0, optlen,
-			    to.to_signature, IPSEC_DIR_OUTBOUND);
+			tcp_signature_do_compute(m, 0, optlen,
+			    to.to_signature, sav);
 #endif
 #ifdef INET6
 		if (sc->sc_inc.inc_flags & INC_ISIPV6)

Modified: head/sys/netinet/tcp_var.h
==============================================================================
--- head/sys/netinet/tcp_var.h	Sat Sep 27 05:50:31 2014	(r272200)
+++ head/sys/netinet/tcp_var.h	Sat Sep 27 07:04:12 2014	(r272201)
@@ -685,9 +685,15 @@ int	 tcp_twcheck(struct inpcb *, struct 
 	    struct mbuf *, int);
 void	 tcp_setpersist(struct tcpcb *);
 #ifdef TCP_SIGNATURE
+struct secasvar;
+struct secasvar *tcp_get_sav(struct mbuf *, u_int);
+int	 tcp_signature_do_compute(struct mbuf *, int, int, u_char *,
+	    struct secasvar *);
 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);
+int	tcp_signature_check(struct mbuf *m, int off0, int tlen, int optlen,
+	    struct tcpopt *to, struct tcphdr *th, u_int tcpbflag);
 #endif
 void	 tcp_slowtimo(void);
 struct tcptemp *



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