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_input.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_input.c')
-rw-r--r-- | sys/netinet/tcp_input.c | 103 |
1 files changed, 99 insertions, 4 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index cb9453f..cf1daa8 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -215,6 +215,12 @@ static void tcp_pulloutofband(struct socket *, struct tcphdr *, struct mbuf *, int); static void tcp_xmit_timer(struct tcpcb *, int); static void tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *); +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 static void inline cc_ack_received(struct tcpcb *tp, struct tcphdr *th, uint16_t type); static void inline cc_conn_init(struct tcpcb *tp); @@ -440,6 +446,40 @@ cc_post_recovery(struct tcpcb *tp, struct tcphdr *th) tp->t_bytes_acked = 0; } +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) \ @@ -519,6 +559,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 @@ -676,10 +719,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. @@ -861,8 +901,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. */ @@ -1021,6 +1077,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 @@ -1225,6 +1301,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 |