|
@@ -923,6 +923,13 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
|
|
|
const struct tcphdr *th = tcp_hdr(skb);
|
|
|
u32 seq = 0, ack_seq = 0;
|
|
|
struct tcp_md5sig_key *key = NULL;
|
|
|
+#ifdef CONFIG_TCP_MD5SIG
|
|
|
+ const __u8 *hash_location = NULL;
|
|
|
+ struct ipv6hdr *ipv6h = ipv6_hdr(skb);
|
|
|
+ unsigned char newhash[16];
|
|
|
+ int genhash;
|
|
|
+ struct sock *sk1 = NULL;
|
|
|
+#endif
|
|
|
|
|
|
if (th->rst)
|
|
|
return;
|
|
@@ -931,8 +938,32 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
|
|
|
return;
|
|
|
|
|
|
#ifdef CONFIG_TCP_MD5SIG
|
|
|
- if (sk)
|
|
|
- key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr);
|
|
|
+ hash_location = tcp_parse_md5sig_option(th);
|
|
|
+ if (!sk && hash_location) {
|
|
|
+ /*
|
|
|
+ * active side is lost. Try to find listening socket through
|
|
|
+ * source port, and then find md5 key through listening socket.
|
|
|
+ * we are not loose security here:
|
|
|
+ * Incoming packet is checked with md5 hash with finding key,
|
|
|
+ * no RST generated if md5 hash doesn't match.
|
|
|
+ */
|
|
|
+ sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev),
|
|
|
+ &tcp_hashinfo, &ipv6h->daddr,
|
|
|
+ ntohs(th->source), inet6_iif(skb));
|
|
|
+ if (!sk1)
|
|
|
+ return;
|
|
|
+
|
|
|
+ rcu_read_lock();
|
|
|
+ key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr);
|
|
|
+ if (!key)
|
|
|
+ goto release_sk1;
|
|
|
+
|
|
|
+ genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, NULL, skb);
|
|
|
+ if (genhash || memcmp(hash_location, newhash, 16) != 0)
|
|
|
+ goto release_sk1;
|
|
|
+ } else {
|
|
|
+ key = sk ? tcp_v6_md5_do_lookup(sk, &ipv6h->saddr) : NULL;
|
|
|
+ }
|
|
|
#endif
|
|
|
|
|
|
if (th->ack)
|
|
@@ -942,6 +973,14 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
|
|
|
(th->doff << 2);
|
|
|
|
|
|
tcp_v6_send_response(skb, seq, ack_seq, 0, 0, key, 1, 0);
|
|
|
+
|
|
|
+#ifdef CONFIG_TCP_MD5SIG
|
|
|
+release_sk1:
|
|
|
+ if (sk1) {
|
|
|
+ rcu_read_unlock();
|
|
|
+ sock_put(sk1);
|
|
|
+ }
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
|