diff options
author | attilio <attilio@FreeBSD.org> | 2011-04-25 17:13:40 +0000 |
---|---|---|
committer | attilio <attilio@FreeBSD.org> | 2011-04-25 17:13:40 +0000 |
commit | 2e19c21f223f834300d9e8b7fc46636902205453 (patch) | |
tree | a9b2378f15a6b24078acade80e7136f7779e5dbb /sys/netinet/tcp_subr.c | |
parent | 99f9647714747def6d98acca6bfe0f865c0d2f1c (diff) | |
download | FreeBSD-src-2e19c21f223f834300d9e8b7fc46636902205453.zip FreeBSD-src-2e19c21f223f834300d9e8b7fc46636902205453.tar.gz |
Add the possibility to verify MD5 hash of incoming TCP packets.
As long as this is a costy function, even when compiled in (along with
the option TCP_SIGNATURE), it can be disabled via the
net.inet.tcp.signature_verify_input sysctl.
Sponsored by: Sandvine Incorporated
Reviewed by: emaste, bz
MFC after: 2 weeks
Diffstat (limited to 'sys/netinet/tcp_subr.c')
-rw-r--r-- | sys/netinet/tcp_subr.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 909381a..f106b2d 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -213,6 +213,12 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, soreceive_stream, CTLFLAG_RDTUN, &tcp_soreceive_stream, 0, "Using soreceive_stream for TCP sockets"); #endif +#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) @@ -1998,6 +2004,66 @@ tcp_signature_compute(struct mbuf *m, int _unused, int len, int optlen, 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 |