Re: [PATCH nf] conntrack: RFC5961 challenge ACK confuse conntrack LAST-ACK transition

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Thu, 7 May 2015, Jesper Dangaard Brouer wrote:

> In compliance with RFC5961, the network stack send challenge ACK in
> response to spurious SYN packets, since commit 0c228e833c88 ("tcp:
> Restore RFC5961-compliant behavior for SYN packets").
> 
> This pose a problem for netfilter conntrack in state LAST_ACK, because
> this challenge ACK is (falsely) seen as ACKing last FIN, causing a
> false state transition (into TIME_WAIT).
> 
> The challenge ACK is hard to distinguish from real last ACK.  Thus,
> solution introduce a flag that tracks the potential for seeing a
> challenge ACK, in case a SYN packet is let through and current state
> is LAST_ACK.
> 
> When conntrack transition LAST_ACK to TIME_WAIT happens, this flag is
> used for determining if we are expecting a challenge ACK.
> 
> Scapy based reproducer script avail here:
>  https://github.com/netoptimizer/network-testing/blob/master/scapy/tcp_hacks_3WHS_LAST_ACK.py
> 
> Fixes: 0c228e833c88 ("tcp: Restore RFC5961-compliant behavior for SYN packets")
> Signed-off-by: Jesper Dangaard Brouer <brouer@xxxxxxxxxx>

The patch looks OK to me, thanks Jesper.

Acked-by: Jozsef Kadlecsik <kadlec@xxxxxxxxxxxxxxxxx>

Best regards,
Jozsef
> ---
> 
>  include/uapi/linux/netfilter/nf_conntrack_tcp.h |    3 ++
>  net/netfilter/nf_conntrack_proto_tcp.c          |   35 +++++++++++++++++++++--
>  2 files changed, 35 insertions(+), 3 deletions(-)
> 
> diff --git a/include/uapi/linux/netfilter/nf_conntrack_tcp.h b/include/uapi/linux/netfilter/nf_conntrack_tcp.h
> index 9993a42..ef9f80f 100644
> --- a/include/uapi/linux/netfilter/nf_conntrack_tcp.h
> +++ b/include/uapi/linux/netfilter/nf_conntrack_tcp.h
> @@ -42,6 +42,9 @@ enum tcp_conntrack {
>  /* The field td_maxack has been set */
>  #define IP_CT_TCP_FLAG_MAXACK_SET		0x20
>  
> +/* Marks possibility for expected RFC5961 challenge ACK */
> +#define IP_CT_EXP_CHALLENGE_ACK 		0x40
> +
>  struct nf_ct_tcp_flags {
>  	__u8 flags;
>  	__u8 mask;
> diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
> index 5caa0c4..ad0db66 100644
> --- a/net/netfilter/nf_conntrack_proto_tcp.c
> +++ b/net/netfilter/nf_conntrack_proto_tcp.c
> @@ -202,7 +202,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
>   *	sES -> sES	:-)
>   *	sFW -> sCW	Normal close request answered by ACK.
>   *	sCW -> sCW
> - *	sLA -> sTW	Last ACK detected.
> + *	sLA -> sTW	Last ACK detected (RFC5961 challenged)
>   *	sTW -> sTW	Retransmitted last ACK. Remain in the same state.
>   *	sCL -> sCL
>   */
> @@ -261,7 +261,7 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
>   *	sES -> sES	:-)
>   *	sFW -> sCW	Normal close request answered by ACK.
>   *	sCW -> sCW
> - *	sLA -> sTW	Last ACK detected.
> + *	sLA -> sTW	Last ACK detected (RFC5961 challenged)
>   *	sTW -> sTW	Retransmitted last ACK.
>   *	sCL -> sCL
>   */
> @@ -906,6 +906,7 @@ static int tcp_packet(struct nf_conn *ct,
>  					1 : ct->proto.tcp.last_win;
>  			ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_scale =
>  				ct->proto.tcp.last_wscale;
> +			ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK;
>  			ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags =
>  				ct->proto.tcp.last_flags;
>  			memset(&ct->proto.tcp.seen[dir], 0,
> @@ -923,7 +924,9 @@ static int tcp_packet(struct nf_conn *ct,
>  		 * may be in sync but we are not. In that case, we annotate
>  		 * the TCP options and let the packet go through. If it is a
>  		 * valid SYN packet, the server will reply with a SYN/ACK, and
> -		 * then we'll get in sync. Otherwise, the server ignores it. */
> +		 * then we'll get in sync. Otherwise, the server potentially
> +		 * respons with a challenge ACK if implementing RFC5961.
> +		 */
>  		if (index == TCP_SYN_SET && dir == IP_CT_DIR_ORIGINAL) {
>  			struct ip_ct_tcp_state seen = {};
>  
> @@ -939,6 +942,13 @@ static int tcp_packet(struct nf_conn *ct,
>  				ct->proto.tcp.last_flags |=
>  					IP_CT_TCP_FLAG_SACK_PERM;
>  			}
> +			/* Mark the potential for RFC5961 challenge ACK,
> +			 * this pose a special problem for LAST_ACK state
> +			 * as ACK is intrepretated as ACKing last FIN.
> +			 */
> +			if (old_state == TCP_CONNTRACK_LAST_ACK)
> +				ct->proto.tcp.last_flags |=
> +					IP_CT_EXP_CHALLENGE_ACK;
>  		}
>  		spin_unlock_bh(&ct->lock);
>  		if (LOG_INVALID(net, IPPROTO_TCP))
> @@ -970,6 +980,25 @@ static int tcp_packet(struct nf_conn *ct,
>  			nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
>  				  "nf_ct_tcp: invalid state ");
>  		return -NF_ACCEPT;
> +	case TCP_CONNTRACK_TIME_WAIT:
> +		/* RFC5961 compliance cause stack to send "challenge-ACK"
> +		 * e.g. in response to spurious SYNs.  Conntrack MUST
> +		 * not believe this ACK is acking last FIN.
> +		 */
> +		if (old_state == TCP_CONNTRACK_LAST_ACK
> +		    && index == TCP_ACK_SET
> +		    && ct->proto.tcp.last_dir != dir
> +		    && ct->proto.tcp.last_index == TCP_SYN_SET
> +		    && (ct->proto.tcp.last_flags & IP_CT_EXP_CHALLENGE_ACK)) {
> +			/* Detected RFC5961 challenge ACK */
> +			ct->proto.tcp.last_flags &= ~IP_CT_EXP_CHALLENGE_ACK;
> +			spin_unlock_bh(&ct->lock);
> +			if (LOG_INVALID(net, IPPROTO_TCP))
> +				nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
> +				      "nf_ct_tcp: challenge-ACK ignored ");
> +			return NF_ACCEPT; /* Don't change state */
> +		}
> +		break;
>  	case TCP_CONNTRACK_CLOSE:
>  		if (index == TCP_RST_SET
>  		    && (ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_MAXACK_SET)
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-
E-mail  : kadlec@xxxxxxxxxxxxxxxxx, kadlecsik.jozsef@xxxxxxxxxxxxx
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : Wigner Research Centre for Physics, Hungarian Academy of Sciences
          H-1525 Budapest 114, POB. 49, Hungary
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux