Received: by 2002:a05:6a10:eb17:0:0:0:0 with SMTP id hx23csp3754914pxb; Tue, 7 Sep 2021 06:58:54 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwbhwuz6jmkgBprYXHE9JjqxhrTdrtb6UhKtVUZlxD5OHryA0P6sv6sBaBmtMaHCqX2eFqM X-Received: by 2002:a17:906:a24c:: with SMTP id bi12mr17875328ejb.530.1631023134549; Tue, 07 Sep 2021 06:58:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1631023134; cv=none; d=google.com; s=arc-20160816; b=nbNq6qGRitytbAbjERjUXkUc6yEcU22G4/yVLYsQJisklj0oFxnbvnMo+x0K45Sxdt QWVDKekJxObdEsOrJAW9n7wir9B7bc9PLHi2nVU0UWku/Kaz1XwNcYflg8oOZ8zcvNF9 lZKVp1/xbsmb8BZw4O2g98v0nlho9wLDSEECCsPAzoj8yX2IlYyWPUGmK5JxxoRF5Psy fgg7dRpQSAP4I7hLz4tx9KFAMJYhzZMIXywlsZc66xHkgFxaFXv3oTTjBvCODEtcep+B RfBfzHeCro9FozXyJoOCMiLgU1KcSYVvtZH6oB7Kmgg6bksU40xqxhSvYdkbGLjVh+Sx 71Xw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:user-agent:in-reply-to:content-disposition :mime-version:references:message-id:subject:cc:to:from:date; bh=Zo4kvi0PcnqgoH+OR6AR5iEvEg2SJJWm4OKBjEz7IOY=; b=dqz3SWh9hK8qvS9A5pful4EY6u92eIu8kZupCyw6cNn3S8f+F6TJ4LNruliILzzIM8 72HCuZq/tDBPusrLMdj+jTYkfKSeL8PdRm6jEL1BtZJ3rBh2Mf5OvTyBJ7OCVP+R8NWH w0yJIKgpbSyc3lseIkH1ItnpHlcqS7+MXoeZ1p3Ew8dL1E3w1akKWSp68CwEzjnaUnoL xoUV8lAtsJohVxmEWxlpcm7tMwYN9/Tof/VTa73J2zK6PJJLGMIo7MEUmND9nmfzWFFX N3px539E8F0hNA12lcTp7tLbz9CN6XxyI/ZQqcBpV1WRKE/uM3r9UG2ObXWMwrv5E4c/ /FsA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id l12si12217009ejo.331.2021.09.07.06.58.29; Tue, 07 Sep 2021 06:58:54 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231513AbhIGN4P (ORCPT + 99 others); Tue, 7 Sep 2021 09:56:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35144 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229792AbhIGN4P (ORCPT ); Tue, 7 Sep 2021 09:56:15 -0400 Received: from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc [IPv6:2a0a:51c0:0:12e:520::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E0C11C061575; Tue, 7 Sep 2021 06:55:08 -0700 (PDT) Received: from fw by Chamillionaire.breakpoint.cc with local (Exim 4.92) (envelope-from ) id 1mNbYw-0007OY-Kd; Tue, 07 Sep 2021 15:54:58 +0200 Date: Tue, 7 Sep 2021 15:54:58 +0200 From: Florian Westphal To: Cole Dishington Cc: pablo@netfilter.org, kadlec@netfilter.org, fw@strlen.de, davem@davemloft.net, kuba@kernel.org, shuah@kernel.org, linux-kernel@vger.kernel.org, netfilter-devel@vger.kernel.org, coreteam@netfilter.org, netdev@vger.kernel.org, Anthony Lineham , Scott Parlane , Blair Steven Subject: Re: [PATCH net v2] net: netfilter: Fix port selection of FTP for NF_NAT_RANGE_PROTO_SPECIFIED Message-ID: <20210907135458.GF23554@breakpoint.cc> References: <20210907021415.962-1-Cole.Dishington@alliedtelesis.co.nz> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20210907021415.962-1-Cole.Dishington@alliedtelesis.co.nz> User-Agent: Mutt/1.10.1 (2018-07-13) Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Cole Dishington wrote: > index aace6768a64e..cf675dc589be 100644 > --- a/net/netfilter/nf_nat_ftp.c > +++ b/net/netfilter/nf_nat_ftp.c > @@ -17,6 +17,10 @@ > #include > #include > #include > +void nf_nat_l4proto_unique_tuple(struct nf_conntrack_tuple *tuple, > + const struct nf_nat_range2 *range, > + enum nf_nat_manip_type maniptype, > + const struct nf_conn *ct); Please add this to a header, e.g. include/net/netfilter/nf_nat.h. > - /* Try to get same port: if not, try to change it. */ > - for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) { > - int ret; > + if (htons(nat->range_info.min_proto.all) == 0 || > + htons(nat->range_info.max_proto.all) == 0) { Either use if (nat->range_info.min_proto.all || ... or use ntohs(). I will leave it up to you if you prefer ntohs(nat->range_info.min_proto.all) == 0 or nat->range_info.min_proto.all == ntohs(0). (Use of htons here will trigger endian warnings from sparse tool). > - exp->tuple.dst.u.tcp.port = htons(port); > + /* Try to get same port if it matches NAT rule: if not, try to change it. */ > + ret = -1; > + port = ntohs(exp->tuple.dst.u.tcp.port); > + if (port != 0 && ntohs(range.min_proto.all) <= port && > + port <= ntohs(range.max_proto.all)) { > ret = nf_ct_expect_related(exp, 0); > - if (ret == 0) > - break; > - else if (ret != -EBUSY) { > - port = 0; > - break; > + } > + if (ret != 0 || port == 0) { > + if (!dir) { > + nf_nat_l4proto_unique_tuple(&exp->tuple, &range, > + NF_NAT_MANIP_DST, > + ct); A small comment that explains why nf_nat_l4proto_unique_tuple() is called conditionally would be good. I don't understand this new logic, can you explain? Old: for (port = expr>tuple.port ; port > 0 ;port++) nf_ct_expect_related(exp, 0); if (success || fatal_error) break; New: port = exp->tuple.port; if (port && min <= port && port <= max) // in which case is port 0 here? ret = nf_ct_expect_related(); if (fatal_error || port == 0) // how can port be 0? if (!dir) { nf_nat_l4proto_unique_tuple(); ret = nf_ct_expect_related(); } } How can this work? This removes the loop and relies on nf_nat_l4proto_unique_tuple(), but NF_NAT_MANIP_DST doesn't support port rewrite in !NF_NAT_RANGE_PROTO_SPECIFIED case. Plus, it restricts nf_nat_l4proto_unique_tuple to !dir case, which I don't understand either. > + port = ntohs(exp->tuple.dst.u.tcp.port); > + ret = nf_ct_expect_related(exp, 0); > } > - > - if (port == 0) { > + if (ret != 0 || port == 0) { How can port be 0? In the old code, it becomes 0 if all attempts to find unused port failed, but after the rewrite I don't see how it can happen. > @@ -188,6 +188,16 @@ void nf_nat_follow_master(struct nf_conn *ct, > range.flags = NF_NAT_RANGE_MAP_IPS; > range.min_addr = range.max_addr > = ct->master->tuplehash[!exp->dir].tuple.dst.u3; > + if (exp->master && !exp->dir) { AFAIK exp->master can't be NULL. > + struct nf_conn_nat *nat = nfct_nat(exp->master); > + > + if (nat && nat->range_info.min_proto.all != 0 && > + nat->range_info.max_proto.all != 0) { > + range.min_proto = nat->range_info.min_proto; > + range.max_proto = nat->range_info.max_proto; > + range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; > + } > + } !expr->dir means REPLY, i.e. new connection is reversed compared to the master connection (from responder back to initiator). So, why are we munging range in this case? I would have expected exp->dir == IP_CT_DIR_ORIGINAL for your use case (original connection subject to masquerade and source ports mangled to fall into special range, so related conntion should also be mangled to match said range).