mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-05 05:42:36 +00:00
[TCP]: MD5 Signature Option (RFC2385) support.
Based on implementation by Rick Payne. Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
bf6bce71ea
commit
cfb6eeb4c8
15 changed files with 1714 additions and 64 deletions
|
@ -270,7 +270,7 @@ static u16 tcp_select_window(struct sock *sk)
|
|||
}
|
||||
|
||||
static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp,
|
||||
__u32 tstamp)
|
||||
__u32 tstamp, __u8 **md5_hash)
|
||||
{
|
||||
if (tp->rx_opt.tstamp_ok) {
|
||||
*ptr++ = htonl((TCPOPT_NOP << 24) |
|
||||
|
@ -298,16 +298,29 @@ static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp,
|
|||
tp->rx_opt.eff_sacks--;
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
if (md5_hash) {
|
||||
*ptr++ = htonl((TCPOPT_NOP << 24) |
|
||||
(TCPOPT_NOP << 16) |
|
||||
(TCPOPT_MD5SIG << 8) |
|
||||
TCPOLEN_MD5SIG);
|
||||
*md5_hash = (__u8 *)ptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Construct a tcp options header for a SYN or SYN_ACK packet.
|
||||
* If this is every changed make sure to change the definition of
|
||||
* MAX_SYN_SIZE to match the new maximum number of options that you
|
||||
* can generate.
|
||||
*
|
||||
* Note - that with the RFC2385 TCP option, we make room for the
|
||||
* 16 byte MD5 hash. This will be filled in later, so the pointer for the
|
||||
* location to be filled is passed back up.
|
||||
*/
|
||||
static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack,
|
||||
int offer_wscale, int wscale, __u32 tstamp,
|
||||
__u32 ts_recent)
|
||||
__u32 ts_recent, __u8 **md5_hash)
|
||||
{
|
||||
/* We always get an MSS option.
|
||||
* The option bytes which will be seen in normal data
|
||||
|
@ -346,6 +359,20 @@ static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack,
|
|||
(TCPOPT_WINDOW << 16) |
|
||||
(TCPOLEN_WINDOW << 8) |
|
||||
(wscale));
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
/*
|
||||
* If MD5 is enabled, then we set the option, and include the size
|
||||
* (always 18). The actual MD5 hash is added just before the
|
||||
* packet is sent.
|
||||
*/
|
||||
if (md5_hash) {
|
||||
*ptr++ = htonl((TCPOPT_NOP << 24) |
|
||||
(TCPOPT_NOP << 16) |
|
||||
(TCPOPT_MD5SIG << 8) |
|
||||
TCPOLEN_MD5SIG);
|
||||
*md5_hash = (__u8 *) ptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This routine actually transmits TCP packets queued in by
|
||||
|
@ -366,6 +393,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
|
|||
struct tcp_sock *tp;
|
||||
struct tcp_skb_cb *tcb;
|
||||
int tcp_header_size;
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
struct tcp_md5sig_key *md5;
|
||||
__u8 *md5_hash_location;
|
||||
#endif
|
||||
struct tcphdr *th;
|
||||
int sysctl_flags;
|
||||
int err;
|
||||
|
@ -424,6 +455,16 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
|
|||
if (tcp_packets_in_flight(tp) == 0)
|
||||
tcp_ca_event(sk, CA_EVENT_TX_START);
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
/*
|
||||
* Are we doing MD5 on this segment? If so - make
|
||||
* room for it.
|
||||
*/
|
||||
md5 = tp->af_specific->md5_lookup(sk, sk);
|
||||
if (md5)
|
||||
tcp_header_size += TCPOLEN_MD5SIG_ALIGNED;
|
||||
#endif
|
||||
|
||||
th = (struct tcphdr *) skb_push(skb, tcp_header_size);
|
||||
skb->h.th = th;
|
||||
|
||||
|
@ -460,13 +501,34 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
|
|||
(sysctl_flags & SYSCTL_FLAG_WSCALE),
|
||||
tp->rx_opt.rcv_wscale,
|
||||
tcb->when,
|
||||
tp->rx_opt.ts_recent);
|
||||
tp->rx_opt.ts_recent,
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
md5 ? &md5_hash_location :
|
||||
#endif
|
||||
NULL);
|
||||
} else {
|
||||
tcp_build_and_update_options((__be32 *)(th + 1),
|
||||
tp, tcb->when);
|
||||
tp, tcb->when,
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
md5 ? &md5_hash_location :
|
||||
#endif
|
||||
NULL);
|
||||
TCP_ECN_send(sk, tp, skb, tcp_header_size);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
/* Calculate the MD5 hash, as we have all we need now */
|
||||
if (md5) {
|
||||
tp->af_specific->calc_md5_hash(md5_hash_location,
|
||||
md5,
|
||||
sk, NULL, NULL,
|
||||
skb->h.th,
|
||||
sk->sk_protocol,
|
||||
skb->len);
|
||||
}
|
||||
#endif
|
||||
|
||||
icsk->icsk_af_ops->send_check(sk, skb->len, skb);
|
||||
|
||||
if (likely(tcb->flags & TCPCB_FLAG_ACK))
|
||||
|
@ -840,6 +902,11 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed)
|
|||
mss_now -= (TCPOLEN_SACK_BASE_ALIGNED +
|
||||
(tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK));
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
if (tp->af_specific->md5_lookup(sk, sk))
|
||||
mss_now -= TCPOLEN_MD5SIG_ALIGNED;
|
||||
#endif
|
||||
|
||||
xmit_size_goal = mss_now;
|
||||
|
||||
if (doing_tso) {
|
||||
|
@ -2033,6 +2100,10 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
|
|||
struct tcphdr *th;
|
||||
int tcp_header_size;
|
||||
struct sk_buff *skb;
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
struct tcp_md5sig_key *md5;
|
||||
__u8 *md5_hash_location;
|
||||
#endif
|
||||
|
||||
skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC);
|
||||
if (skb == NULL)
|
||||
|
@ -2048,6 +2119,13 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
|
|||
(ireq->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) +
|
||||
/* SACK_PERM is in the place of NOP NOP of TS */
|
||||
((ireq->sack_ok && !ireq->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0));
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
/* Are we doing MD5 on this segment? If so - make room for it */
|
||||
md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req);
|
||||
if (md5)
|
||||
tcp_header_size += TCPOLEN_MD5SIG_ALIGNED;
|
||||
#endif
|
||||
skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size);
|
||||
|
||||
memset(th, 0, sizeof(struct tcphdr));
|
||||
|
@ -2085,11 +2163,29 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
|
|||
tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok,
|
||||
ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale,
|
||||
TCP_SKB_CB(skb)->when,
|
||||
req->ts_recent);
|
||||
req->ts_recent,
|
||||
(
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
md5 ? &md5_hash_location :
|
||||
#endif
|
||||
NULL)
|
||||
);
|
||||
|
||||
skb->csum = 0;
|
||||
th->doff = (tcp_header_size >> 2);
|
||||
TCP_INC_STATS(TCP_MIB_OUTSEGS);
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
/* Okay, we have all we need - do the md5 hash if needed */
|
||||
if (md5) {
|
||||
tp->af_specific->calc_md5_hash(md5_hash_location,
|
||||
md5,
|
||||
NULL, dst, req,
|
||||
skb->h.th, sk->sk_protocol,
|
||||
skb->len);
|
||||
}
|
||||
#endif
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
|
@ -2108,6 +2204,11 @@ static void tcp_connect_init(struct sock *sk)
|
|||
tp->tcp_header_len = sizeof(struct tcphdr) +
|
||||
(sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0);
|
||||
|
||||
#ifdef CONFIG_TCP_MD5SIG
|
||||
if (tp->af_specific->md5_lookup(sk, sk) != NULL)
|
||||
tp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED;
|
||||
#endif
|
||||
|
||||
/* If user gave his TCP_MAXSEG, record it to clamp */
|
||||
if (tp->rx_opt.user_mss)
|
||||
tp->rx_opt.mss_clamp = tp->rx_opt.user_mss;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue