svn commit: r272201 - head/sys/netinet
Alexander V. Chernikov
melifaro at FreeBSD.org
Sat Sep 27 07:04:14 UTC 2014
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 *
More information about the svn-src-head
mailing list