* 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:
parent
2d8910854b
commit
29c47f18da
@ -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
|
* 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
|
* search with the destination IP address, and a 'magic SPI' to be
|
||||||
* determined by the application. This is hardcoded elsewhere to 1179
|
* 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.
|
struct secasvar *
|
||||||
*/
|
tcp_get_sav(struct mbuf *m, u_int direction)
|
||||||
int
|
|
||||||
tcp_signature_compute(struct mbuf *m, int _unused, int len, int optlen,
|
|
||||||
u_char *buf, u_int direction)
|
|
||||||
{
|
{
|
||||||
union sockaddr_union dst;
|
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 secasvar *sav;
|
||||||
struct tcphdr *th;
|
struct ip *ip;
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
struct ip6_hdr *ip6;
|
struct ip6_hdr *ip6;
|
||||||
struct in6_addr in6;
|
|
||||||
char ip6buf[INET6_ADDRSTRLEN];
|
char ip6buf[INET6_ADDRSTRLEN];
|
||||||
uint32_t plen;
|
|
||||||
uint16_t nhdr;
|
|
||||||
#endif
|
#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. */
|
/* Extract the destination from the IP header in the mbuf. */
|
||||||
bzero(&dst, sizeof(union sockaddr_union));
|
bzero(&dst, sizeof(union sockaddr_union));
|
||||||
@ -2003,7 +1968,7 @@ tcp_signature_compute(struct mbuf *m, int _unused, int len, int optlen,
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return (EINVAL);
|
return (NULL);
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2018,9 +1983,61 @@ tcp_signature_compute(struct mbuf *m, int _unused, int len, int optlen,
|
|||||||
ip6_sprintf(ip6buf, &dst.sin6.sin6_addr) :
|
ip6_sprintf(ip6buf, &dst.sin6.sin6_addr) :
|
||||||
#endif
|
#endif
|
||||||
"(unsupported)"));
|
"(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);
|
MD5Init(&ctx);
|
||||||
/*
|
/*
|
||||||
* Step 1: Update MD5 hash with IP(v6) pseudo-header.
|
* 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;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return (EINVAL);
|
return (-1);
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2110,6 +2127,23 @@ tcp_signature_compute(struct mbuf *m, int _unused, int len, int optlen,
|
|||||||
return (0);
|
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)
|
* Verify the TCP-MD5 hash of a TCP segment. (RFC2385)
|
||||||
*
|
*
|
||||||
|
@ -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_drop(struct syncache *, struct syncache_head *);
|
||||||
static void syncache_free(struct syncache *);
|
static void syncache_free(struct syncache *);
|
||||||
static void syncache_insert(struct syncache *, struct syncache_head *);
|
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 *,
|
static struct socket *syncache_socket(struct syncache *, struct socket *,
|
||||||
struct mbuf *m);
|
struct mbuf *m);
|
||||||
static void syncache_timeout(struct syncache *sc, struct syncache_head *sch,
|
static void syncache_timeout(struct syncache *sc, struct syncache_head *sch,
|
||||||
@ -467,7 +467,7 @@ syncache_timer(void *xsch)
|
|||||||
free(s, M_TCPLOG);
|
free(s, M_TCPLOG);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) syncache_respond(sc);
|
syncache_respond(sc, sch, 1);
|
||||||
TCPSTAT_INC(tcps_sc_retransmitted);
|
TCPSTAT_INC(tcps_sc_retransmitted);
|
||||||
syncache_timeout(sc, sch, 0);
|
syncache_timeout(sc, sch, 0);
|
||||||
}
|
}
|
||||||
@ -1213,7 +1213,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
|
|||||||
s, __func__);
|
s, __func__);
|
||||||
free(s, M_TCPLOG);
|
free(s, M_TCPLOG);
|
||||||
}
|
}
|
||||||
if (syncache_respond(sc) == 0) {
|
if (syncache_respond(sc, sch, 1) == 0) {
|
||||||
sc->sc_rxmits = 0;
|
sc->sc_rxmits = 0;
|
||||||
syncache_timeout(sc, sch, 1);
|
syncache_timeout(sc, sch, 1);
|
||||||
TCPSTAT_INC(tcps_sndacks);
|
TCPSTAT_INC(tcps_sndacks);
|
||||||
@ -1325,11 +1325,9 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
|
|||||||
}
|
}
|
||||||
#ifdef TCP_SIGNATURE
|
#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
|
* contains the option, flag this in the syncache so that
|
||||||
* syncache_respond() will do the right thing with the SYN+ACK.
|
* 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)
|
if (to->to_flags & TOF_SIGNATURE || ltflags & TF_SIGNATURE)
|
||||||
sc->sc_flags |= SCF_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.
|
* 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)
|
if (V_tcp_syncookies && V_tcp_syncookiesonly && sc != &scs)
|
||||||
syncache_free(sc);
|
syncache_free(sc);
|
||||||
else if (sc != &scs)
|
else if (sc != &scs)
|
||||||
@ -1387,7 +1385,7 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
syncache_respond(struct syncache *sc)
|
syncache_respond(struct syncache *sc, struct syncache_head *sch, int locked)
|
||||||
{
|
{
|
||||||
struct ip *ip = NULL;
|
struct ip *ip = NULL;
|
||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
@ -1398,6 +1396,9 @@ syncache_respond(struct syncache *sc)
|
|||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
struct ip6_hdr *ip6 = NULL;
|
struct ip6_hdr *ip6 = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef TCP_SIGNATURE
|
||||||
|
struct secasvar *sav;
|
||||||
|
#endif
|
||||||
|
|
||||||
hlen =
|
hlen =
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
@ -1508,8 +1509,29 @@ syncache_respond(struct syncache *sc)
|
|||||||
if (sc->sc_flags & SCF_SACK)
|
if (sc->sc_flags & SCF_SACK)
|
||||||
to.to_flags |= TOF_SACKPERM;
|
to.to_flags |= TOF_SACKPERM;
|
||||||
#ifdef TCP_SIGNATURE
|
#ifdef TCP_SIGNATURE
|
||||||
if (sc->sc_flags & SCF_SIGNATURE)
|
sav = NULL;
|
||||||
to.to_flags |= TOF_SIGNATURE;
|
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
|
#endif
|
||||||
optlen = tcp_addoptions(&to, (u_char *)(th + 1));
|
optlen = tcp_addoptions(&to, (u_char *)(th + 1));
|
||||||
|
|
||||||
@ -1520,8 +1542,8 @@ syncache_respond(struct syncache *sc)
|
|||||||
|
|
||||||
#ifdef TCP_SIGNATURE
|
#ifdef TCP_SIGNATURE
|
||||||
if (sc->sc_flags & SCF_SIGNATURE)
|
if (sc->sc_flags & SCF_SIGNATURE)
|
||||||
tcp_signature_compute(m, 0, 0, optlen,
|
tcp_signature_do_compute(m, 0, optlen,
|
||||||
to.to_signature, IPSEC_DIR_OUTBOUND);
|
to.to_signature, sav);
|
||||||
#endif
|
#endif
|
||||||
#ifdef INET6
|
#ifdef INET6
|
||||||
if (sc->sc_inc.inc_flags & INC_ISIPV6)
|
if (sc->sc_inc.inc_flags & INC_ISIPV6)
|
||||||
|
@ -685,9 +685,15 @@ int tcp_twcheck(struct inpcb *, struct tcpopt *, struct tcphdr *,
|
|||||||
struct mbuf *, int);
|
struct mbuf *, int);
|
||||||
void tcp_setpersist(struct tcpcb *);
|
void tcp_setpersist(struct tcpcb *);
|
||||||
#ifdef TCP_SIGNATURE
|
#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_compute(struct mbuf *, int, int, int, u_char *, u_int);
|
||||||
int tcp_signature_verify(struct mbuf *, int, int, int, struct tcpopt *,
|
int tcp_signature_verify(struct mbuf *, int, int, int, struct tcpopt *,
|
||||||
struct tcphdr *, u_int);
|
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
|
#endif
|
||||||
void tcp_slowtimo(void);
|
void tcp_slowtimo(void);
|
||||||
struct tcptemp *
|
struct tcptemp *
|
||||||
|
Loading…
x
Reference in New Issue
Block a user