svn commit: r221705 - stable/8/sys/netinet
Attilio Rao
attilio at FreeBSD.org
Mon May 9 18:29:49 UTC 2011
Author: attilio
Date: Mon May 9 18:29:48 2011
New Revision: 221705
URL: http://svn.freebsd.org/changeset/base/221705
Log:
MFC r221023:
Add the possibility to verify MD5 hash of incoming TCP packets.
Sponsored by: Sandvine Incorporated
Modified:
stable/8/sys/netinet/tcp_input.c
stable/8/sys/netinet/tcp_subr.c
stable/8/sys/netinet/tcp_syncache.c
stable/8/sys/netinet/tcp_var.h
Directory Properties:
stable/8/sys/ (props changed)
stable/8/sys/amd64/include/xen/ (props changed)
stable/8/sys/cddl/contrib/opensolaris/ (props changed)
stable/8/sys/contrib/dev/acpica/ (props changed)
stable/8/sys/contrib/pf/ (props changed)
Modified: stable/8/sys/netinet/tcp_input.c
==============================================================================
--- stable/8/sys/netinet/tcp_input.c Mon May 9 18:05:13 2011 (r221704)
+++ stable/8/sys/netinet/tcp_input.c Mon May 9 18:29:48 2011 (r221705)
@@ -205,6 +205,12 @@ static void tcp_xmit_timer(struct tcpcb
static void tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *);
static void inline
tcp_congestion_exp(struct tcpcb *);
+static void inline tcp_fields_to_host(struct tcphdr *);
+#ifdef TCP_SIGNATURE
+static void inline tcp_fields_to_net(struct tcphdr *);
+static int inline tcp_signature_verify_input(struct mbuf *, int, int,
+ int, struct tcpopt *, struct tcphdr *, u_int);
+#endif
/*
* Kernel module interface for updating tcpstat. The argument is an index
@@ -236,6 +242,40 @@ tcp_congestion_exp(struct tcpcb *tp)
tp->t_flags |= TF_ECN_SND_CWR;
}
+static inline void
+tcp_fields_to_host(struct tcphdr *th)
+{
+
+ th->th_seq = ntohl(th->th_seq);
+ th->th_ack = ntohl(th->th_ack);
+ th->th_win = ntohs(th->th_win);
+ th->th_urp = ntohs(th->th_urp);
+}
+
+#ifdef TCP_SIGNATURE
+static inline void
+tcp_fields_to_net(struct tcphdr *th)
+{
+
+ th->th_seq = htonl(th->th_seq);
+ th->th_ack = htonl(th->th_ack);
+ th->th_win = htons(th->th_win);
+ th->th_urp = htons(th->th_urp);
+}
+
+static inline int
+tcp_signature_verify_input(struct mbuf *m, int off0, int tlen, int optlen,
+ struct tcpopt *to, struct tcphdr *th, u_int tcpbflag)
+{
+ int ret;
+
+ tcp_fields_to_net(th);
+ ret = tcp_signature_verify(m, off0, tlen, optlen, to, th, tcpbflag);
+ tcp_fields_to_host(th);
+ return (ret);
+}
+#endif
+
/* Neighbor Discovery, Neighbor Unreachability Detection Upper layer hint. */
#ifdef INET6
#define ND6_HINT(tp) \
@@ -315,6 +355,9 @@ tcp_input(struct mbuf *m, int off0)
int thflags;
int rstreason = 0; /* For badport_bandlim accounting purposes */
uint8_t iptos;
+#ifdef TCP_SIGNATURE
+ uint8_t sig_checked = 0;
+#endif
#ifdef IPFIREWALL_FORWARD
struct m_tag *fwd_tag;
#endif
@@ -472,10 +515,7 @@ tcp_input(struct mbuf *m, int off0)
/*
* Convert TCP protocol specific fields to host format.
*/
- th->th_seq = ntohl(th->th_seq);
- th->th_ack = ntohl(th->th_ack);
- th->th_win = ntohs(th->th_win);
- th->th_urp = ntohs(th->th_urp);
+ tcp_fields_to_host(th);
/*
* Delay dropping TCP, IP headers, IPv6 ext headers, and TCP options.
@@ -657,8 +697,24 @@ relocked:
}
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
+#ifdef TCP_SIGNATURE
+ tcp_dooptions(&to, optp, optlen,
+ (thflags & TH_SYN) ? TO_SYN : 0);
+ if (sig_checked == 0) {
+ tp = intotcpcb(inp);
+ if (tp == NULL || tp->t_state == TCPS_CLOSED) {
+ rstreason = BANDLIM_RST_CLOSEDPORT;
+ goto dropwithreset;
+ }
+ if (!tcp_signature_verify_input(m, off0, tlen, optlen,
+ &to, th, tp->t_flags))
+ goto dropunlock;
+ sig_checked = 1;
+ }
+#else
if (thflags & TH_SYN)
tcp_dooptions(&to, optp, optlen, TO_SYN);
+#endif
/*
* NB: tcp_twcheck unlocks the INP and frees the mbuf.
*/
@@ -817,6 +873,26 @@ relocked:
tp = intotcpcb(inp);
KASSERT(tp->t_state == TCPS_SYN_RECEIVED,
("%s: ", __func__));
+#ifdef TCP_SIGNATURE
+ if (sig_checked == 0) {
+ tcp_dooptions(&to, optp, optlen,
+ (thflags & TH_SYN) ? TO_SYN : 0);
+ if (!tcp_signature_verify_input(m, off0, tlen,
+ optlen, &to, th, tp->t_flags)) {
+
+ /*
+ * In SYN_SENT state if it receives an
+ * RST, it is allowed for further
+ * processing.
+ */
+ if ((thflags & TH_RST) == 0 ||
+ (tp->t_state == TCPS_SYN_SENT) == 0)
+ goto dropunlock;
+ }
+ sig_checked = 1;
+ }
+#endif
+
/*
* Process the segment and the data it
* contains. tcp_do_segment() consumes
@@ -1021,6 +1097,25 @@ relocked:
return;
}
+#ifdef TCP_SIGNATURE
+ if (sig_checked == 0) {
+ tcp_dooptions(&to, optp, optlen,
+ (thflags & TH_SYN) ? TO_SYN : 0);
+ if (!tcp_signature_verify_input(m, off0, tlen, optlen, &to,
+ th, tp->t_flags)) {
+
+ /*
+ * In SYN_SENT state if it receives an RST, it is
+ * allowed for further processing.
+ */
+ if ((thflags & TH_RST) == 0 ||
+ (tp->t_state == TCPS_SYN_SENT) == 0)
+ goto dropunlock;
+ }
+ sig_checked = 1;
+ }
+#endif
+
/*
* Segment belongs to a connection in SYN_SENT, ESTABLISHED or later
* state. tcp_do_segment() always consumes the mbuf chain, unlocks
Modified: stable/8/sys/netinet/tcp_subr.c
==============================================================================
--- stable/8/sys/netinet/tcp_subr.c Mon May 9 18:05:13 2011 (r221704)
+++ stable/8/sys/netinet/tcp_subr.c Mon May 9 18:29:48 2011 (r221705)
@@ -257,6 +257,12 @@ SYSCTL_VNET_INT(_net_inet_tcp_inflight,
&VNET_NAME(tcp_inflight_stab), 0,
"Inflight Algorithm Stabilization 20 = 2 packets");
+#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)
@@ -2084,6 +2090,66 @@ tcp_signature_compute(struct mbuf *m, in
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
Modified: stable/8/sys/netinet/tcp_syncache.c
==============================================================================
--- stable/8/sys/netinet/tcp_syncache.c Mon May 9 18:05:13 2011 (r221704)
+++ stable/8/sys/netinet/tcp_syncache.c Mon May 9 18:29:48 2011 (r221705)
@@ -1010,7 +1010,8 @@ _syncache_add(struct in_conninfo *inc, s
struct syncache_head *sch;
struct mbuf *ipopts = NULL;
u_int32_t flowtmp;
- int win, sb_hiwat, ip_ttl, ip_tos, noopt;
+ u_int ltflags;
+ int win, sb_hiwat, ip_ttl, ip_tos;
char *s;
#ifdef INET6
int autoflowlabel = 0;
@@ -1043,7 +1044,7 @@ _syncache_add(struct in_conninfo *inc, s
ip_tos = inp->inp_ip_tos;
win = sbspace(&so->so_rcv);
sb_hiwat = so->so_rcv.sb_hiwat;
- noopt = (tp->t_flags & TF_NOOPT);
+ ltflags = (tp->t_flags & (TF_NOOPT | TF_SIGNATURE));
/* By the time we drop the lock these should no longer be used. */
so = NULL;
@@ -1238,14 +1239,14 @@ _syncache_add(struct in_conninfo *inc, s
* XXX: Currently we always record the option by default and will
* attempt to use it in syncache_respond().
*/
- if (to->to_flags & TOF_SIGNATURE)
+ if (to->to_flags & TOF_SIGNATURE || ltflags & TF_SIGNATURE)
sc->sc_flags |= SCF_SIGNATURE;
#endif
if (to->to_flags & TOF_SACKPERM)
sc->sc_flags |= SCF_SACK;
if (to->to_flags & TOF_MSS)
sc->sc_peer_mss = to->to_mss; /* peer mss may be zero */
- if (noopt)
+ if (ltflags & TF_NOOPT)
sc->sc_flags |= SCF_NOOPT;
if ((th->th_flags & (TH_ECE|TH_CWR)) && V_tcp_do_ecn)
sc->sc_flags |= SCF_ECN;
Modified: stable/8/sys/netinet/tcp_var.h
==============================================================================
--- stable/8/sys/netinet/tcp_var.h Mon May 9 18:05:13 2011 (r221704)
+++ stable/8/sys/netinet/tcp_var.h Mon May 9 18:29:48 2011 (r221705)
@@ -470,7 +470,14 @@ struct tcpstat {
u_long tcps_ecn_shs; /* ECN successful handshakes */
u_long tcps_ecn_rcwnd; /* # times ECN reduced the cwnd */
- u_long _pad[12]; /* 6 UTO, 6 TBD */
+ /* TCP_SIGNATURE related stats */
+ u_long tcps_sig_rcvgoodsig; /* Total matching signature received */
+ u_long tcps_sig_rcvbadsig; /* Total bad signature received */
+ u_long tcps_sig_err_buildsig; /* Mismatching signature received */
+ u_long tcps_sig_err_sigopt; /* No signature expected by socket */
+ u_long tcps_sig_err_nosigopt; /* No signature provided by segment */
+
+ u_long _pad[7]; /* 6 UTO, 1 TBD */
};
#ifdef _KERNEL
@@ -638,6 +645,8 @@ int tcp_twrespond(struct tcptw *, int);
void tcp_setpersist(struct tcpcb *);
#ifdef TCP_SIGNATURE
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);
#endif
void tcp_slowtimo(void);
struct tcptemp *
More information about the svn-src-stable-8
mailing list