aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_ipv4.c
diff options
context:
space:
mode:
authorShawn Lu <shawn.lu@ericsson.com>2012-01-31 17:35:48 -0500
committerDavid S. Miller <davem@davemloft.net>2012-02-01 12:43:54 -0500
commit658ddaaf6694adf63f67451dec9ddeb87a7cb2d7 (patch)
tree33f917f23d7faa78e8dc9a23a57b7265facd2638 /net/ipv4/tcp_ipv4.c
parent5b11b2e4bdef20e839d90dce96c5bbeafaf9616c (diff)
tcp: md5: RST: getting md5 key from listener
TCP RST mechanism is broken in TCP md5(RFC2385). When connection is gone, md5 key is lost, sending RST without md5 hash is deem to ignored by peer. This can be a problem since RST help protocal like bgp to fast recove from peer crash. In most case, users of tcp md5, such as bgp and ldp, have listener on both sides to accept connection from peer. md5 keys for peers are saved in listening socket. There are two cases in finding md5 key when connection is lost: 1.Passive receive RST: The message is send to well known port, tcp will associate it with listner. md5 key is gotten from listener. 2.Active receive RST (no sock): The message is send to ative side, there is no socket associated with the message. In this case, finding listener from source port, then find md5 key from listener. we are not loosing sercuriy here: packet is checked with md5 hash. No RST is generated if md5 hash doesn't match or no md5 key can be found. Signed-off-by: Shawn Lu <shawn.lu@ericsson.com> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
-rw-r--r--net/ipv4/tcp_ipv4.c45
1 files changed, 42 insertions, 3 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 567cca9b30df..90e47931e217 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -593,6 +593,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
593 struct ip_reply_arg arg; 593 struct ip_reply_arg arg;
594#ifdef CONFIG_TCP_MD5SIG 594#ifdef CONFIG_TCP_MD5SIG
595 struct tcp_md5sig_key *key; 595 struct tcp_md5sig_key *key;
596 const __u8 *hash_location = NULL;
597 unsigned char newhash[16];
598 int genhash;
599 struct sock *sk1 = NULL;
596#endif 600#endif
597 struct net *net; 601 struct net *net;
598 602
@@ -623,9 +627,36 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
623 arg.iov[0].iov_len = sizeof(rep.th); 627 arg.iov[0].iov_len = sizeof(rep.th);
624 628
625#ifdef CONFIG_TCP_MD5SIG 629#ifdef CONFIG_TCP_MD5SIG
626 key = sk ? tcp_md5_do_lookup(sk, 630 hash_location = tcp_parse_md5sig_option(th);
627 (union tcp_md5_addr *)&ip_hdr(skb)->saddr, 631 if (!sk && hash_location) {
628 AF_INET) : NULL; 632 /*
633 * active side is lost. Try to find listening socket through
634 * source port, and then find md5 key through listening socket.
635 * we are not loose security here:
636 * Incoming packet is checked with md5 hash with finding key,
637 * no RST generated if md5 hash doesn't match.
638 */
639 sk1 = __inet_lookup_listener(dev_net(skb_dst(skb)->dev),
640 &tcp_hashinfo, ip_hdr(skb)->daddr,
641 ntohs(th->source), inet_iif(skb));
642 /* don't send rst if it can't find key */
643 if (!sk1)
644 return;
645 rcu_read_lock();
646 key = tcp_md5_do_lookup(sk1, (union tcp_md5_addr *)
647 &ip_hdr(skb)->saddr, AF_INET);
648 if (!key)
649 goto release_sk1;
650
651 genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, NULL, skb);
652 if (genhash || memcmp(hash_location, newhash, 16) != 0)
653 goto release_sk1;
654 } else {
655 key = sk ? tcp_md5_do_lookup(sk, (union tcp_md5_addr *)
656 &ip_hdr(skb)->saddr,
657 AF_INET) : NULL;
658 }
659
629 if (key) { 660 if (key) {
630 rep.opt[0] = htonl((TCPOPT_NOP << 24) | 661 rep.opt[0] = htonl((TCPOPT_NOP << 24) |
631 (TCPOPT_NOP << 16) | 662 (TCPOPT_NOP << 16) |
@@ -653,6 +684,14 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
653 684
654 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); 685 TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS);
655 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS); 686 TCP_INC_STATS_BH(net, TCP_MIB_OUTRSTS);
687
688#ifdef CONFIG_TCP_MD5SIG
689release_sk1:
690 if (sk1) {
691 rcu_read_unlock();
692 sock_put(sk1);
693 }
694#endif
656} 695}
657 696
658/* The code following below sending ACKs in SYN-RECV and TIME-WAIT states 697/* The code following below sending ACKs in SYN-RECV and TIME-WAIT states