* 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
This commit is contained in:
Alexander V. Chernikov 2014-09-27 07:04:12 +00:00
parent 2d8910854b
commit 29c47f18da
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=272201
3 changed files with 116 additions and 54 deletions

View File

@ -1928,55 +1928,20 @@ tcp_signature_apply(void *fstate, void *data, u_int len)
}
/*
* 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, int _unused, int len, int optlen,
break;
#endif
default:
return (EINVAL);
return (NULL);
/* NOTREACHED */
break;
}
@ -2018,9 +1983,61 @@ tcp_signature_compute(struct mbuf *m, int _unused, int len, int optlen,
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, int _unused, int len, int optlen,
break;
#endif
default:
return (EINVAL);
return (-1);
/* NOTREACHED */
break;
}
@ -2110,6 +2127,23 @@ tcp_signature_compute(struct mbuf *m, int _unused, int len, int optlen,
return (0);
}
/*
* 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)
*

View File

@ -122,7 +122,7 @@ SYSCTL_VNET_INT(_net_inet_tcp, OID_AUTO, syncookies_only, CTLFLAG_RW,
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, struct tcpopt *to, struct tcphdr *th,
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, struct tcpopt *to, struct tcphdr *th,
}
#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, struct tcpopt *to, struct tcphdr *th,
/*
* 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 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
}
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)

View File

@ -685,9 +685,15 @@ int tcp_twcheck(struct inpcb *, struct tcpopt *, struct tcphdr *,
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 *