summaryrefslogtreecommitdiffstats
path: root/sys/netinet/tcp_subr.c
diff options
context:
space:
mode:
authorattilio <attilio@FreeBSD.org>2011-04-25 17:13:40 +0000
committerattilio <attilio@FreeBSD.org>2011-04-25 17:13:40 +0000
commit2e19c21f223f834300d9e8b7fc46636902205453 (patch)
treea9b2378f15a6b24078acade80e7136f7779e5dbb /sys/netinet/tcp_subr.c
parent99f9647714747def6d98acca6bfe0f865c0d2f1c (diff)
downloadFreeBSD-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.c66
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
OpenPOWER on IntegriCloud