Skip to contentSkip to conversation

netfilter: IPv6 NAT

PATCH Applied [email protected] 11 participants 67 messages Aug 9, 2012 – Aug 29, 2012

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

cover netfilter: IPv6 NAT

The following patches contain an updated version of IPv6 NAT against Linus' current tree.

The series is organized as follows:

- Patches 01-03 contain bugfixes for SIP helper bugs/regressions present in the current kernel

- Patches 04-06 improve conntrack fragmentation handling, the IPv6 parts are also a precondition for IPv6 NAT

- Patches 07 and 08 prepare the current NAT code for conversion to an address family independant core, but contain no functional changes

- Patch 09 adds the address family independant NAT core and converts the existing IPv4-only NAT code to an AF-specific module

- Patches 10 and 11 add some infrastructure for IPv6 NAT

- Patch 12 adds IPv6 NAT support

- Patches 13-15 add IPv6 specific NAT targets

- Patches 16-19 add some IPv6-capable ports of existing NAT helpers

- Patch 19 is independant of the IPv6 NAT code and adds support for stateless IPv6 prefix translation, just to relieve my conscience ;)

Since the last posting numerous bugs have been fixed, I don't remember all of them, the more important ones include:

- automatic NAT module loading in ctnetlink

- address selection when mapping to IPv6 ranges

- handling of IPv6 fragments

- NAT handling of ICMPv6 error messages

Besides implementing IPv6 NAT, there are no known bugs left. Userspace patches will follow shortly.

The entire patchset is also available at

git://github.com/kaber/nf-nat-ipv6.git master

Comments, questions and test results welcome.

#1 lore raw

PATCH 1/19 netfilter: nf_ct_sip: fix helper name

From: Patrick McHardy <[email protected]>

Commit 3a8fc53a (netfilter: nf_ct_helper: allocate 16 bytes for the helper and policy names) introduced a bug in the SIP helper, the helper name is sprinted to the sip_names array instead of instead of into the helper structure. This breaks the helper match and the /proc/net/nf_conntrack_expect output.

---
 net/netfilter/nf_conntrack_sip.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)
net/netfilter/nf_conntrack_sip.c +2 -3
index 758a1ba..2fb6669 100644
@@ -1515,7 +1515,6 @@ static int sip_help_udp(struct sk_buff *skb, unsigned int protoff,
 }
 
 static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly;
-static char sip_names[MAX_PORTS][4][sizeof("sip-65535")] __read_mostly;
 
 static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = {
 	[SIP_EXPECT_SIGNALLING] = {
@@ -1585,9 +1584,9 @@ static int __init nf_conntrack_sip_init(void)
 			sip[i][j].me = THIS_MODULE;
 
 			if (ports[i] == SIP_PORT)
-				sprintf(sip_names[i][j], "sip");
+				sprintf(sip[i][j].name, "sip");
 			else
-				sprintf(sip_names[i][j], "sip-%u", i);
+				sprintf(sip[i][j].name, "sip-%u", i);
 
 			pr_debug("port #%u: %u\n", i, ports[i]);
 
Signature · 1 line
1.7.1
maintainer Applied
#2 lore raw

Re: [PATCH 01/19] netfilter: nf_ct_sip: fix helper name

Quoted 7 lines · On Thu, Aug 09, 2012 at 10:08:45PM +0200, [email protected] wrote:

From: Patrick McHardy <[email protected]>

Commit 3a8fc53a (netfilter: nf_ct_helper: allocate 16 bytes for the helper and policy names) introduced a bug in the SIP helper, the helper name is sprinted to the sip_names array instead of instead of into the helper structure. This breaks the helper match and the /proc/net/nf_conntrack_expect output.

Applied, thanks Patrick.

#3 lore raw

PATCH 2/19 netfilter: nf_ct_sip: fix IPv6 address parsing

In reply to [email protected]

From: Patrick McHardy <[email protected]>

Within SIP messages IPv6 addresses are enclosed in square brackets in most cases, with the exception of the "received=" header parameter. Currently the helper fails to parse enclosed addresses.

This patch:

- changes the SIP address parsing function to enforce square brackets when required, and accept them when not required but present, as recommended by RFC 5118.

- adds a new SDP address parsing function that never accepts square brackets since SDP doesn't use them.

With these changes, the SIP helper correctly parses all test messages from RFC 5118 (Session Initiation Protocol (SIP) Torture Test Messages for Internet Protocol Version 6 (IPv6)).

---
 include/linux/netfilter/nf_conntrack_sip.h |    2 +-
 net/ipv4/netfilter/nf_nat_sip.c            |    4 +-
 net/netfilter/nf_conntrack_sip.c           |   87 ++++++++++++++++++++++------
 3 files changed, 73 insertions(+), 20 deletions(-)
include/linux/netfilter/nf_conntrack_sip.h +1 -1
index 0dfc8b7..89f2a62 100644
@@ -164,7 +164,7 @@ extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr
 				      unsigned int dataoff, unsigned int datalen,
 				      const char *name,
 				      unsigned int *matchoff, unsigned int *matchlen,
-				      union nf_inet_addr *addr);
+				      union nf_inet_addr *addr, bool delim);
 extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
 					unsigned int off, unsigned int datalen,
 					const char *name,
net/ipv4/netfilter/nf_nat_sip.c +2 -2
index ea4a238..eef8f29 100644
@@ -173,7 +173,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
 		 * the reply. */
 		if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
 					       "maddr=", &poff, &plen,
-					       &addr) > 0 &&
+					       &addr, true) > 0 &&
 		    addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
 		    addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
 			buflen = sprintf(buffer, "%pI4",
@@ -187,7 +187,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
 		 * from which the server received the request. */
 		if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
 					       "received=", &poff, &plen,
-					       &addr) > 0 &&
+					       &addr, false) > 0 &&
 		    addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
 		    addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
 			buflen = sprintf(buffer, "%pI4",
net/netfilter/nf_conntrack_sip.c +70 -17

157 lines not on this page · raw message

Signature · 1 line
1.7.1
maintainer Applied
#4 lore raw

Re: [PATCH 02/19] netfilter: nf_ct_sip: fix IPv6 address parsing

Quoted 12 lines · On Thu, Aug 09, 2012 at 10:08:46PM +0200, [email protected] wrote:

From: Patrick McHardy <[email protected]>

Within SIP messages IPv6 addresses are enclosed in square brackets in most cases, with the exception of the "received=" header parameter. Currently the helper fails to parse enclosed addresses.

This patch:

- changes the SIP address parsing function to enforce square brackets when required, and accept them when not required but present, as recommended by RFC 5118.

Quoted 6 lines

- adds a new SDP address parsing function that never accepts square brackets since SDP doesn't use them.

With these changes, the SIP helper correctly parses all test messages from RFC 5118 (Session Initiation Protocol (SIP) Torture Test Messages for Internet Protocol Version 6 (IPv6)).

Applied, thanks Patrick.

#5 lore raw

PATCH 3/19 netfilter: nf_nat_sip: fix via header translation with multiple parameters

In reply to [email protected]

From: Patrick McHardy <[email protected]>

Via-headers are parsed beginning at the first character after the Via-address. When the address is translated first and its length decreases, the offset to start parsing at is incorrect and header parameters might be missed.

Update the offset after translating the Via-address to fix this.

---
 net/ipv4/netfilter/nf_nat_sip.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)
net/ipv4/netfilter/nf_nat_sip.c +3 -2
index eef8f29..4ad9cf1 100644
@@ -148,7 +148,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
 	if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
 				    hdr, NULL, &matchoff, &matchlen,
 				    &addr, &port) > 0) {
-		unsigned int matchend, poff, plen, buflen, n;
+		unsigned int olen, matchend, poff, plen, buflen, n;
 		char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
 
 		/* We're only interested in headers related to this
@@ -163,11 +163,12 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
 				goto next;
 		}
 
+		olen = *datalen;
 		if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
 			      &addr, port))
 			return NF_DROP;
 
-		matchend = matchoff + matchlen;
+		matchend = matchoff + matchlen + *datalen - olen;
 
 		/* The maddr= parameter (RFC 2361) specifies where to send
 		 * the reply. */
Signature · 1 line
1.7.1
maintainer Applied
#6 lore raw

Re: [PATCH 03/19] netfilter: nf_nat_sip: fix via header translation with multiple parameters

Quoted 7 lines · On Thu, Aug 09, 2012 at 10:08:47PM +0200, [email protected] wrote:

From: Patrick McHardy <[email protected]>

Via-headers are parsed beginning at the first character after the Via-address. When the address is translated first and its length decreases, the offset to start parsing at is incorrect and header parameters might be missed.

Update the offset after translating the Via-address to fix this.

Applied, thanks Patrick.

#7 lore raw

Re: [PATCH 03/19] netfilter: nf_nat_sip: fix via header translation with multiple parameters

Quoted 10 lines · Pablo Neira Ayuso
Quoted 7 lines · On Thu, Aug 09, 2012 at 10:08:47PM +0200, [email protected] wrote:

From: Patrick McHardy <[email protected]>

Via-headers are parsed beginning at the first character after the Via-address. When the address is translated first and its length decreases, the offset to start parsing at is incorrect and header parameters might be missed.

Update the offset after translating the Via-address to fix this.

Applied, thanks Patrick.

Thanks Pablo. I'll submit the final IPv6-NAT patches once these three patches have made it into net-next/nf-next.

#8 lore raw

PATCH 4/19 ipv4: fix path MTU discovery with connection tracking

In reply to [email protected]

From: Patrick McHardy <[email protected]>

IPv4 conntrack defragments incoming packet at the PRE_ROUTING hook and (in case of forwarded packets) refragments them at POST_ROUTING independant of the IP_DF flag. Refragmentation uses the dst_mtu() of the local route without caring about the original fragment sizes, thereby breaking PMTUD.

This patch fixes this by keeping track of the largest received fragment with IP_DF set and generates an ICMP fragmentation required error during refragmentation if that size exceeds the MTU.

---
 include/net/inet_frag.h |    2 ++
 include/net/ip.h        |    2 ++
 net/ipv4/ip_fragment.c  |    8 +++++++-
 net/ipv4/ip_output.c    |    4 +++-
 4 files changed, 14 insertions(+), 2 deletions(-)
include/net/inet_frag.h +2 -0
index 2431cf8..5098ee7 100644
@@ -29,6 +29,8 @@ struct inet_frag_queue {
 #define INET_FRAG_COMPLETE	4
 #define INET_FRAG_FIRST_IN	2
 #define INET_FRAG_LAST_IN	1
+
+	u16			max_size;
 };
 
 #define INETFRAGS_HASHSZ		64
include/net/ip.h +2 -0
index bd5e444..613053e 100644
@@ -42,6 +42,8 @@ struct inet_skb_parm {
 #define IPSKB_XFRM_TRANSFORMED	4
 #define IPSKB_FRAG_COMPLETE	8
 #define IPSKB_REROUTED		16
+
+	u16			frag_max_size;
 };
 
 static inline unsigned int ip_hdrlen(const struct sk_buff *skb)
net/ipv4/ip_fragment.c +7 -1
index 8d07c97..fa6a12c 100644
@@ -523,6 +523,10 @@ found:
 	if (offset == 0)
 		qp->q.last_in |= INET_FRAG_FIRST_IN;
 
+	if (ip_hdr(skb)->frag_off & htons(IP_DF) &&
+	    skb->len + ihl > qp->q.max_size)
+		qp->q.max_size = skb->len + ihl;
+
 	if (qp->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
 	    qp->q.meat == qp->q.len)
 		return ip_frag_reasm(qp, prev, dev);
@@ -646,9 +650,11 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
 	head->next = NULL;
 	head->dev = dev;
 	head->tstamp = qp->q.stamp;
+	IPCB(head)->frag_max_size = qp->q.max_size;
 
 	iph = ip_hdr(head);
-	iph->frag_off = 0;
+	/* max_size != 0 implies at least one fragment had IP_DF set */
+	iph->frag_off = qp->q.max_size ? htons(IP_DF) : 0;
 	iph->tot_len = htons(len);
 	iph->tos |= ecn;
 	IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
net/ipv4/ip_output.c +3 -1
index 76dde25..ae33b99 100644
@@ -467,7 +467,9 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 
 	iph = ip_hdr(skb);
 
-	if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) {
+	if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->local_df) ||
+		     (IPCB(skb)->frag_max_size &&
+		      IPCB(skb)->frag_max_size > dst_mtu(&rt->dst)))) {
 		IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
 		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
 			  htonl(ip_skb_dst_mtu(skb)));
Signature · 1 line
1.7.1
#9 lore raw

PATCH 5/19 netfilter: nf_conntrack_ipv6: improve fragmentation handling

In reply to [email protected]

From: Patrick McHardy <[email protected]>

The IPv6 conntrack fragmentation currently has a couple of shortcomings. Fragmentes are collected in PREROUTING/OUTPUT, are defragmented, the defragmented packet is then passed to conntrack, the resulting conntrack information is attached to each original fragment and the fragments then continue their way through the stack.

Helper invocation occurs in the POSTROUTING hook, at which point only the original fragments are available. The result of this is that fragmented packets are never passed to helpers.

This patch improves the situation in the following way:

- If a reassembled packet belongs to a connection that has a helper assigned, the reassembled packet is passed through the stack instead of the original fragments.

- During defragmentation, the largest received fragment size is stored. On output, the packet is refragmented if required. If the largest received fragment size exceeds the outgoing MTU, a "packet too big" message is generated, thus behaving as if the original fragments were passed through the stack from an outside point of view.

- The ipv6_helper() hook function can't receive fragments anymore for connections using a helper, so it is switched to use ipv6_skip_exthdr() instead of the netfilter specific nf_ct_ipv6_skip_exthdr() and the reassembled packets are passed to connection tracking helpers.

The result of this is that we can properly track fragmented packets, but still generate ICMPv6 Packet too big messages if we would have before.

This patch is also required as a precondition for IPv6 NAT, where NAT helpers might enlarge packets up to a point that they require fragmentation. In that case we can't generate Packet too big messages since the proper MTU can't be calculated in all cases (f.i. when changing textual representation of a variable amount of addresses), so the packet is transparently fragmented iff the original packet or fragments would have fit the outgoing MTU.

---
 include/linux/ipv6.h                           |    1 +
 net/ipv6/ip6_output.c                          |    7 +++-
 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |   37 ++++++++++++++++++------
 net/ipv6/netfilter/nf_conntrack_reasm.c        |   19 ++++++++++--
 4 files changed, 50 insertions(+), 14 deletions(-)
include/linux/ipv6.h +1 -0
index 879db26..0b94e91 100644
@@ -256,6 +256,7 @@ struct inet6_skb_parm {
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
 	__u16			dsthao;
 #endif
+	__u16			frag_max_size;
 
 #define IP6SKB_XFRM_TRANSFORMED	1
 #define IP6SKB_FORWARDED	2
net/ipv6/ip6_output.c +5 -2
index 5b2d63e..a4f6263 100644
@@ -493,7 +493,8 @@ int ip6_forward(struct sk_buff *skb)
 	if (mtu < IPV6_MIN_MTU)
 		mtu = IPV6_MIN_MTU;
 
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) ||
+	    (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) {
 		/* Again, force OUTPUT device used as source address */
 		skb->dev = dst->dev;
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
@@ -636,7 +637,9 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 	/* We must not fragment if the socket is set to force MTU discovery
 	 * or if the skb it not generated by a local socket.
 	 */
-	if (unlikely(!skb->local_df && skb->len > mtu)) {
+	if (unlikely(!skb->local_df && skb->len > mtu) ||
+		     (IP6CB(skb)->frag_max_size &&
+		      IP6CB(skb)->frag_max_size > mtu)) {
 		if (skb->sk && dst_allfrag(skb_dst(skb)))
 			sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
 
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +28 -9
index 4794f96..560d823 100644
@@ -153,10 +153,10 @@ static unsigned int ipv6_helper(unsigned int hooknum,
 	const struct nf_conn_help *help;
 	const struct nf_conntrack_helper *helper;
 	enum ip_conntrack_info ctinfo;
-	unsigned int ret, protoff;
-	unsigned int extoff = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
-	unsigned char pnum = ipv6_hdr(skb)->nexthdr;
-
+	unsigned int ret;
+	__be16 frag_off;
+	int protoff;
+	u8 nexthdr;
 
 	/* This is where we call the helper: as the packet goes out. */
 	ct = nf_ct_get(skb, &ctinfo);
@@ -171,9 +171,10 @@ static unsigned int ipv6_helper(unsigned int hooknum,
 	if (!helper)
 		return NF_ACCEPT;
 
-	protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum,
-					 skb->len - extoff);
-	if (protoff > skb->len || pnum == NEXTHDR_FRAGMENT) {
+	nexthdr = ipv6_hdr(skb)->nexthdr;
+	protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
+				   &frag_off);
+	if (protoff < 0 || (frag_off & ntohs(~0x7)) != 0) {
 		pr_debug("proto header not found\n");
 		return NF_ACCEPT;
 	}
@@ -199,9 +200,13 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
 static unsigned int __ipv6_conntrack_in(struct net *net,
 					unsigned int hooknum,
 					struct sk_buff *skb,
+					const struct net_device *in,
+					const struct net_device *out,
 					int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *reasm = skb->nfct_reasm;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
 
 	/* This packet is fragmented and has reassembled packet. */
 	if (reasm) {
@@ -213,6 +218,20 @@ static unsigned int __ipv6_conntrack_in(struct net *net,
 			if (ret != NF_ACCEPT)
 				return ret;
 		}
+
+		/* Conntrack helpers need the entire reassembled packet in the
+		 * POST_ROUTING hook.
+		 */
+		ct = nf_ct_get(reasm, &ctinfo);
+		if (ct != NULL && test_bit(IPS_HELPER_BIT, &ct->status)) {
+			nf_conntrack_get_reasm(skb);
+			NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
+				       (struct net_device *)in,
+				       (struct net_device *)out,
+				       okfn, NF_IP6_PRI_CONNTRACK + 1);
+			return NF_DROP_ERR(-ECANCELED);
+		}
+
 		nf_conntrack_get(reasm->nfct);
 		skb->nfct = reasm->nfct;
 		skb->nfctinfo = reasm->nfctinfo;
@@ -228,7 +247,7 @@ static unsigned int ipv6_conntrack_in(unsigned int hooknum,
 				      const struct net_device *out,
 				      int (*okfn)(struct sk_buff *))
 {
-	return __ipv6_conntrack_in(dev_net(in), hooknum, skb, okfn);
+	return __ipv6_conntrack_in(dev_net(in), hooknum, skb, in, out, okfn);
 }
 
 static unsigned int ipv6_conntrack_local(unsigned int hooknum,
@@ -242,7 +261,7 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum,
 		net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
 		return NF_ACCEPT;
 	}
-	return __ipv6_conntrack_in(dev_net(out), hooknum, skb, okfn);
+	return __ipv6_conntrack_in(dev_net(out), hooknum, skb, in, out, okfn);
 }
 
 static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
net/ipv6/netfilter/nf_conntrack_reasm.c +16 -3
index c9c78c2..f94fb3a 100644
@@ -190,6 +190,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 			     const struct frag_hdr *fhdr, int nhoff)
 {
 	struct sk_buff *prev, *next;
+	unsigned int payload_len;
 	int offset, end;
 
 	if (fq->q.last_in & INET_FRAG_COMPLETE) {
@@ -197,8 +198,10 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 		goto err;
 	}
 
+	payload_len = ntohs(ipv6_hdr(skb)->payload_len);
+
 	offset = ntohs(fhdr->frag_off) & ~0x7;
-	end = offset + (ntohs(ipv6_hdr(skb)->payload_len) -
+	end = offset + (payload_len -
 			((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));
 
 	if ((unsigned int)end > IPV6_MAXPLEN) {
@@ -307,6 +310,8 @@ found:
 	skb->dev = NULL;
 	fq->q.stamp = skb->tstamp;
 	fq->q.meat += skb->len;
+	if (payload_len > fq->q.max_size)
+		fq->q.max_size = payload_len;
 	atomic_add(skb->truesize, &nf_init_frags.mem);
 
 	/* The first fragment.
@@ -412,10 +417,12 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 	}
 	atomic_sub(head->truesize, &nf_init_frags.mem);
 
+	head->local_df = 1;
 	head->next = NULL;
 	head->dev = dev;
 	head->tstamp = fq->q.stamp;
 	ipv6_hdr(head)->payload_len = htons(payload_len);
+	IP6CB(head)->frag_max_size = sizeof(struct ipv6hdr) + fq->q.max_size;
 
 	/* Yes, and fold redundant checksum back. 8) */
 	if (head->ip_summed == CHECKSUM_COMPLETE)
@@ -592,6 +599,7 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
 			int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *s, *s2;
+	unsigned int ret = 0;
 
 	for (s = NFCT_FRAG6_CB(skb)->orig; s;) {
 		nf_conntrack_put_reasm(s->nfct_reasm);
@@ -601,8 +609,13 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
 		s2 = s->next;
 		s->next = NULL;
 
-		NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s, in, out, okfn,
-			       NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
+		if (ret != -ECANCELED)
+			ret = NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s,
+					     in, out, okfn,
+					     NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
+		else
+			kfree_skb(s);
+
 		s = s2;
 	}
 	nf_conntrack_put_reasm(skb);
Signature · 1 line
1.7.1
#10 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

Quoted 12 lines · On Thu, 2012-08-09 at 22:08 +0200, [email protected] wrote:

From: Patrick McHardy <[email protected]>

The IPv6 conntrack fragmentation currently has a couple of shortcomings. Fragmentes are collected in PREROUTING/OUTPUT, are defragmented, the defragmented packet is then passed to conntrack, the resulting conntrack information is attached to each original fragment and the fragments then continue their way through the stack.

Helper invocation occurs in the POSTROUTING hook, at which point only the original fragments are available. The result of this is that fragmented packets are never passed to helpers.

Quoted 5 lines

This patch improves the situation in the following way:

- If a reassembled packet belongs to a connection that has a helper assigned, the reassembled packet is passed through the stack instead of the original fragments.

I'm working on IPv6 fragment handling for IPVS, and are taking advantage of the "replay" by nf_ct_frag6_output() at hook prio -399 (NF_IP6_PRI_CONNTRACK_DEFRAG + 1).
By making a hook at NF_INET_PRE_ROUTING at prio -99 (NF_IP6_PRI_NAT_DST
+ 1).

I can see that the code path can be changed (with this patch), if a helper is assigned. Then the "replay" starts at prio -199 (NF_IP6_PRI_CONNTRACK + 1), I guess I'm safe as I run at -99.

I have tested that your patchset works, with my ipvs patches, but would like the trigger the changed code path, to make sure.

Could you provide an iptables command/rule, that trigger this code path?

[cut]

Quoted 19 lines
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +5 -0
@@ -199,9 +200,13 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
 static unsigned int __ipv6_conntrack_in(struct net *net,
 					unsigned int hooknum,
 					struct sk_buff *skb,
+					const struct net_device *in,
+					const struct net_device *out,
 					int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *reasm = skb->nfct_reasm;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
 
 	/* This packet is fragmented and has reassembled packet. */
 	if (reasm) {
@@ -213,6 +218,20 @@ static unsigned int __ipv6_conntrack_in(struct net *net,
 			if (ret != NF_ACCEPT)
 				return ret;
 		}
+

net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c static unsigned int __ipv6_conntrack_in(struct net *net, · line 231

Quoted 10 lines
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +10 -0
+		/* Conntrack helpers need the entire reassembled packet in the
+		 * POST_ROUTING hook.
+		 */
+		ct = nf_ct_get(reasm, &ctinfo);
+		if (ct != NULL && test_bit(IPS_HELPER_BIT, &ct->status)) {
+			nf_conntrack_get_reasm(skb);
+			NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
+				       (struct net_device *)in,
+				       (struct net_device *)out,
+				       okfn, NF_IP6_PRI_CONNTRACK + 1);

Hook prio change to NF_IP6_PRI_CONNTRACK + 1

Quoted 2 lines
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +2 -0
+			return NF_DROP_ERR(-ECANCELED);
+		}

[cut]

Quoted 9 lines
net/ipv6/netfilter/nf_conntrack_reasm.c +1 -0
@@ -592,6 +599,7 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
 			int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *s, *s2;
+	unsigned int ret = 0;
 
 	for (s = NFCT_FRAG6_CB(skb)->orig; s;) {
 		nf_conntrack_put_reasm(s->nfct_reasm);

net/ipv6/netfilter/nf_conntrack_reasm.c void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, · line 615

Quoted 9 lines
net/ipv6/netfilter/nf_conntrack_reasm.c +4 -2
@@ -601,8 +609,13 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
 		s2 = s->next;
 		s->next = NULL;
 
-		NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s, in, out, okfn,
-			       NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
+		if (ret != -ECANCELED)
+			ret = NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s,
+					     in, out, okfn,
+					     NF_IP6_PRI_CONNTRACK_DEFRAG + 1);

Old hook prio

Quoted 6 lines
net/ipv6/netfilter/nf_conntrack_reasm.c +3 -0
+		else
+			kfree_skb(s);
+
 		s = s2;
 	}
 	nf_conntrack_put_reasm(skb);
#11 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

Quoted 25 lines · Jesper Dangaard Brouer
Quoted 12 lines · On Thu, 2012-08-09 at 22:08 +0200, [email protected] wrote:

From: Patrick McHardy <[email protected]>

The IPv6 conntrack fragmentation currently has a couple of shortcomings. Fragmentes are collected in PREROUTING/OUTPUT, are defragmented, the defragmented packet is then passed to conntrack, the resulting conntrack information is attached to each original fragment and the fragments then continue their way through the stack.

Helper invocation occurs in the POSTROUTING hook, at which point only the original fragments are available. The result of this is that fragmented packets are never passed to helpers.

Quoted 5 lines

This patch improves the situation in the following way:

- If a reassembled packet belongs to a connection that has a helper assigned, the reassembled packet is passed through the stack instead of the original fragments.

I'm working on IPv6 fragment handling for IPVS, and are taking advantage of the "replay" by nf_ct_frag6_output() at hook prio -399 (NF_IP6_PRI_CONNTRACK_DEFRAG + 1).
By making a hook at NF_INET_PRE_ROUTING at prio -99 (NF_IP6_PRI_NAT_DST
+ 1).

Quoted 8 lines

I can see that the code path can be changed (with this patch), if a helper is assigned. Then the "replay" starts at prio -199 (NF_IP6_PRI_CONNTRACK + 1), I guess I'm safe as I run at -99.

I have tested that your patchset works, with my ipvs patches, but would like the trigger the changed code path, to make sure.

Could you provide an iptables command/rule, that trigger this code path?

The easiest way is a large ping with the NAT patches also applied, in that case we also pass the first packet of a connection through the stack reassembled.

Quoted 23 lines
Quoted 23 lines
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +9 -0
@@ -199,9 +200,13 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
 static unsigned int __ipv6_conntrack_in(struct net *net,
 					unsigned int hooknum,
 					struct sk_buff *skb,
+					const struct net_device *in,
+					const struct net_device *out,
 					int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *reasm = skb->nfct_reasm;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
 
 	/* This packet is fragmented and has reassembled packet. */
 	if (reasm) {
@@ -213,6 +218,20 @@ static unsigned int __ipv6_conntrack_in(struct net *net,
 			if (ret != NF_ACCEPT)
 				return ret;
 		}
+
+		/* Conntrack helpers need the entire reassembled packet in the
+		 * POST_ROUTING hook.
+		 */
+		ct = nf_ct_get(reasm, &ctinfo);
Quoted 8 lines

net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c static unsigned int __ipv6_conntrack_in(struct net *net, · line 231

Quoted 6 lines
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +6 -0
+		if (ct != NULL && test_bit(IPS_HELPER_BIT, &ct->status)) {
+			nf_conntrack_get_reasm(skb);
+			NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
+				       (struct net_device *)in,
+				       (struct net_device *)out,
+				       okfn, NF_IP6_PRI_CONNTRACK + 1);

Hook prio change to NF_IP6_PRI_CONNTRACK + 1

I didn't get this part, you want to change to PRE_CONNTRACK + 1? What about raw and SELinux?

#12 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

Quoted 31 lines · Patrick McHardy
Quoted 29 lines · Jesper Dangaard Brouer
Quoted 12 lines · On Thu, 2012-08-09 at 22:08 +0200, [email protected] wrote:

From: Patrick McHardy <[email protected]>

The IPv6 conntrack fragmentation currently has a couple of shortcomings. Fragmentes are collected in PREROUTING/OUTPUT, are defragmented, the defragmented packet is then passed to conntrack, the resulting conntrack information is attached to each original fragment and the fragments then continue their way through the stack.

Helper invocation occurs in the POSTROUTING hook, at which point only the original fragments are available. The result of this is that fragmented packets are never passed to helpers.

Quoted 5 lines

This patch improves the situation in the following way:

- If a reassembled packet belongs to a connection that has a helper assigned, the reassembled packet is passed through the stack instead of the original fragments.

I'm working on IPv6 fragment handling for IPVS, and are taking advantage of the "replay" by nf_ct_frag6_output() at hook prio -399 (NF_IP6_PRI_CONNTRACK_DEFRAG + 1).
By making a hook at NF_INET_PRE_ROUTING at prio -99 (NF_IP6_PRI_NAT_DST
+ 1).

I can see that the code path can be changed (with this patch), if a helper is assigned. Then the "replay" starts at prio -199 (NF_IP6_PRI_CONNTRACK + 1), I guess I'm safe as I run at -99.

Quoted 8 lines
Quoted 4 lines

I have tested that your patchset works, with my ipvs patches, but would like the trigger the changed code path, to make sure.

Could you provide an iptables command/rule, that trigger this code path?

The easiest way is a large ping with the NAT patches also applied, in that case we also pass the first packet of a connection through the stack reassembled.

So, a fragmented IPv6 ICMPv6 packet, I assume?

Don't I need to load some of the helper modules, or just the nf_conntrack_ipv6 module, or perhaps only nf_defrag_ipv6 ?

Quoted 32 lines
Quoted 23 lines
Quoted 23 lines
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +9 -0
@@ -199,9 +200,13 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
 static unsigned int __ipv6_conntrack_in(struct net *net,
 					unsigned int hooknum,
 					struct sk_buff *skb,
+					const struct net_device *in,
+					const struct net_device *out,
 					int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *reasm = skb->nfct_reasm;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
 
 	/* This packet is fragmented and has reassembled packet. */
 	if (reasm) {
@@ -213,6 +218,20 @@ static unsigned int __ipv6_conntrack_in(struct net *net,
 			if (ret != NF_ACCEPT)
 				return ret;
 		}
+
+		/* Conntrack helpers need the entire reassembled packet in the
+		 * POST_ROUTING hook.
+		 */
+		ct = nf_ct_get(reasm, &ctinfo);
Quoted 8 lines

net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c static unsigned int __ipv6_conntrack_in(struct net *net, · line 231

Quoted 6 lines
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +6 -0
+		if (ct != NULL && test_bit(IPS_HELPER_BIT, &ct->status)) {
+			nf_conntrack_get_reasm(skb);
+			NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
+				       (struct net_device *)in,
+				       (struct net_device *)out,
+				       okfn, NF_IP6_PRI_CONNTRACK + 1);

Hook prio change to NF_IP6_PRI_CONNTRACK + 1

Quoted 2 lines

I didn't get this part, you want to change to PRE_CONNTRACK + 1? What about raw and SELinux?

No - I don't want any changes.

I was just pointing out *where* the changes occur in your patch. This is just a "service" to other email readers, so they can spot the changes faster, I were referring to.

Signature · 5 lines
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Sr. Network Kernel Developer at Red Hat
  Author of http://www.iptv-analyzer.org
  LinkedIn: http://www.linkedin.com/in/brouer
#13 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

Quoted 9 lines · Jesper Dangaard Brouer
Quoted 6 lines · Patrick McHardy
Quoted 2 lines

Could you provide an iptables command/rule, that trigger this code path?

The easiest way is a large ping with the NAT patches also applied, in that case we also pass the first packet of a connection through the stack reassembled.

So, a fragmented IPv6 ICMPv6 packet, I assume?

Correct.

Quoted 2 lines

Don't I need to load some of the helper modules, or just the nf_conntrack_ipv6 module, or perhaps only nf_defrag_ipv6 ?

Not with the entire patchset, just IPv6 conntrack is enough. Aith IPv6 NAT the first packet of a connection must always be defragemented, independant of an assigned helper.

Quoted 32 lines
Quoted 32 lines
Quoted 31 lines
Quoted 19 lines
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +5 -0
@@ -199,9 +200,13 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
 static unsigned int __ipv6_conntrack_in(struct net *net,
 					unsigned int hooknum,
 					struct sk_buff *skb,
+					const struct net_device *in,
+					const struct net_device *out,
 					int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *reasm = skb->nfct_reasm;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
 
 	/* This packet is fragmented and has reassembled packet. */
 	if (reasm) {
@@ -213,6 +218,20 @@ static unsigned int __ipv6_conntrack_in(struct net *net,
 			if (ret != NF_ACCEPT)
 				return ret;
 		}
+

net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c static unsigned int __ipv6_conntrack_in(struct net *net, · line 231

Quoted 10 lines
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +10 -0
+		/* Conntrack helpers need the entire reassembled packet in the
+		 * POST_ROUTING hook.
+		 */
+		ct = nf_ct_get(reasm, &ctinfo);
+		if (ct != NULL && test_bit(IPS_HELPER_BIT, &ct->status)) {
+			nf_conntrack_get_reasm(skb);
+			NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
+				       (struct net_device *)in,
+				       (struct net_device *)out,
+				       okfn, NF_IP6_PRI_CONNTRACK + 1);

Hook prio change to NF_IP6_PRI_CONNTRACK + 1

Quoted 8 lines
Quoted 2 lines

I didn't get this part, you want to change to PRE_CONNTRACK + 1? What about raw and SELinux?

No - I don't want any changes.

I was just pointing out *where* the changes occur in your patch. This is just a "service" to other email readers, so they can spot the changes faster, I were referring to.

Could you send me your patch so I get a better picture of what you're doing exactly?

#14 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

Quoted 2 lines · Patrick McHardy

Could you send me your patch so I get a better picture of what you're doing exactly?

Okay, just posted the patchset.

Specifically look at patch:
[PATCH 3/3] ipvs: Complete IPv6 fragment handling for IPVS

Where I use the hook to copy the fw mark from the reasm SKB packet to the SKB fragments. (Perhaps, this could be done else were in the netfilter framework).

--Jesper Brouer

#15 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

Quoted 5 lines · Jesper Dangaard Brouer
Quoted 2 lines · Patrick McHardy

Could you send me your patch so I get a better picture of what you're doing exactly?

Quoted 8 lines

Okay, just posted the patchset.

Specifically look at patch:
[PATCH 3/3] ipvs: Complete IPv6 fragment handling for IPVS

Where I use the hook to copy the fw mark from the reasm SKB packet to the SKB fragments. (Perhaps, this could be done else were in the netfilter framework).

Thanks, I'll have a look at this tommorrow.

#16 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

In reply to Patrick McHardy
Quoted 2 lines · Patrick McHardy
Quoted 1 line · Jesper Dangaard Brouer

On Sat, 2012-08-18 at 14:26 +0200, Patrick McHardy wrote:

[...]

Quoted 6 lines
Quoted 2 lines

Don't I need to load some of the helper modules, or just the nf_conntrack_ipv6 module, or perhaps only nf_defrag_ipv6 ?

Not with the entire patchset, just IPv6 conntrack is enough. Aith IPv6 NAT the first packet of a connection must always be defragemented, independant of an assigned helper.

When loading "nf_conntrack_ipv6" I run into issues.

When sending a fragmented UDP packet. With these patches, the IPVS stack will no longer see the fragmented packets, but instead see one large SKB. This will trigger a MTU path check in e.g. ip_vs_dr_xmit_v6() and an ICMPv6 too big packet is send back.

IPVS: ip_vs_dr_xmit_v6(): frag needed

Perhaps we could change/fix the MTU check in IPVS?
(This would also solve issues I've seen with TSO/GSO frames, hitting this code path).

Signature · 5 lines
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Sr. Network Kernel Developer at Red Hat
  Author of http://www.iptv-analyzer.org
  LinkedIn: http://www.linkedin.com/in/brouer
#17 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

Quoted 19 lines · Jesper Dangaard Brouer
Quoted 2 lines · Patrick McHardy
Quoted 1 line · Jesper Dangaard Brouer

On Sat, 2012-08-18 at 14:26 +0200, Patrick McHardy wrote:

[...]

Quoted 6 lines
Quoted 2 lines

Don't I need to load some of the helper modules, or just the nf_conntrack_ipv6 module, or perhaps only nf_defrag_ipv6 ?

Not with the entire patchset, just IPv6 conntrack is enough. Aith IPv6 NAT the first packet of a connection must always be defragemented, independant of an assigned helper.

When loading "nf_conntrack_ipv6" I run into issues.

When sending a fragmented UDP packet. With these patches, the IPVS stack will no longer see the fragmented packets, but instead see one large SKB. This will trigger a MTU path check in e.g. ip_vs_dr_xmit_v6() and an ICMPv6 too big packet is send back.

Quoted 5 lines

IPVS: ip_vs_dr_xmit_v6(): frag needed

Perhaps we could change/fix the MTU check in IPVS?
(This would also solve issues I've seen with TSO/GSO frames, hitting this code path).

I guess this should use the same check as in IPv6 output, check whether IP6CB(skb)->max_frag_size is != 0 and > MTU and only send an ICMPv6 error in that case.

#18 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

Quoted 23 lines · Patrick McHardy
Quoted 21 lines · Jesper Dangaard Brouer
Quoted 2 lines · Patrick McHardy
Quoted 1 line · Jesper Dangaard Brouer

On Sat, 2012-08-18 at 14:26 +0200, Patrick McHardy wrote:

[...]

Quoted 6 lines
Quoted 2 lines

Don't I need to load some of the helper modules, or just the nf_conntrack_ipv6 module, or perhaps only nf_defrag_ipv6 ?

Not with the entire patchset, just IPv6 conntrack is enough. Aith IPv6 NAT the first packet of a connection must always be defragemented, independant of an assigned helper.

When loading "nf_conntrack_ipv6" I run into issues.

When sending a fragmented UDP packet. With these patches, the IPVS stack will no longer see the fragmented packets, but instead see one large SKB. This will trigger a MTU path check in e.g. ip_vs_dr_xmit_v6() and an ICMPv6 too big packet is send back.

IPVS: ip_vs_dr_xmit_v6(): frag needed

Quoted 7 lines
Quoted 3 lines

Perhaps we could change/fix the MTU check in IPVS?
(This would also solve issues I've seen with TSO/GSO frames, hitting this code path).

I guess this should use the same check as in IPv6 output, check whether IP6CB(skb)->max_frag_size is != 0 and > MTU and only send an ICMPv6 error in that case.

Hans have (already) proposed this solution:

  if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) ||
      (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) {

And I have tested it works.
But I'm not sure about, if we really need the "!skb->local_df" check ?

Thus, we should extend you patchset with a patch, that also address the MTU checks in IPVS.

Signature · 5 lines
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Sr. Network Kernel Developer at Red Hat
  Author of http://www.iptv-analyzer.org
  LinkedIn: http://www.linkedin.com/in/brouer
#19 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

Quoted 17 lines · Jesper Dangaard Brouer
Quoted 9 lines
Quoted 9 lines

When loading "nf_conntrack_ipv6" I run into issues.

When sending a fragmented UDP packet. With these patches, the IPVS stack will no longer see the fragmented packets, but instead see one large SKB. This will trigger a MTU path check in e.g. ip_vs_dr_xmit_v6() and an ICMPv6 too big packet is send back.

IPVS: ip_vs_dr_xmit_v6(): frag needed

Quoted 7 lines
Quoted 3 lines

Perhaps we could change/fix the MTU check in IPVS?
(This would also solve issues I've seen with TSO/GSO frames, hitting this code path).

I guess this should use the same check as in IPv6 output, check whether IP6CB(skb)->max_frag_size is != 0 and > MTU and only send an ICMPv6 error in that case.

Quoted 7 lines

Hans have (already) proposed this solution:

if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) ||

     (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) {

And I have tested it works.
But I'm not sure about, if we really need the "!skb->local_df" check ?

Not necessarily, alternatively you could use:

if ((!IP6CB(skb)->frag_max_size &&

     (skb->len > mtu && !skb_is_gso(skb)) ||
    IP6CB(skb)->frag_max_size > mtu)

We just need to make sure that if frag_max_size is set that skb->len is ignored. Either way is fine, but I'd suggest to keep it similar to the variant used in IPv6.

Quoted 2 lines

Thus, we should extend you patchset with a patch, that also address the MTU checks in IPVS.

Can you send over a patch for inclusion in the patchset? Besides this, its ready for submission.

#20 lore raw

cover net: ipvs and netfilter IPv6 defrag MTU handling

The following patchset makes IPVS compatible with Patrick McHardys IPv6 NAT patchset: http://thread.gmane.org/gmane.linux.network/239615

Specifically the part that improves defragmentation.

Patch01: Cleanup (and fixes a bug) in IPVS MTU IPv6 handling

Patch02: Extend MTU check to account for IPv6 NAT defrag changes

This patchset is based upon:
Homes ipvs-next tree:
git://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs-next.git

BUT with Patrick McHardy's IPv6 NAT patchset applied first, on top of
commit: 3654e61137db891f5312e6dd813b961484b5fdf3
title: "ipvs: add pmtu_disc option to disable IP DF for TUN packets"

Send due to request by Patrick:
http://thread.gmane.org/gmane.linux.network/239615/focus=43870

---

Jesper Dangaard Brouer (2):
ipvs: Extend MTU check to account for IPv6 NAT defrag changes
ipvs: IPv6 MTU checking cleanup and bugfix

 net/netfilter/ipvs/ip_vs_xmit.c |   32 ++++++++++++++++++++++++++------
 1 files changed, 26 insertions(+), 6 deletions(-)

--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Sr. Network Kernel Developer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer

#21 lore raw

PATCH 1/2 ipvs: IPv6 MTU checking cleanup and bugfix

Cleaning up the IPv6 MTU checking in the IPVS xmit code, by using a common helper function __mtu_check_toobig_v6(). The MTU check for tunnel mode is special, and does not use this helper.

Notice, this also fixes a bug, as the the MTU check in ip_vs_dr_xmit_v6() were missing a check for skb_is_gso().

This e.g. caused issues for KVM IPVS setups, where different Segmentation Offloading techniques are utilized, between guests, via the virtio driver. This resulted in very bad performance, due to the ICMPv6 "too big" messages didn't affect the sender.

---

 net/netfilter/ipvs/ip_vs_xmit.c |   18 ++++++++++++++----
 1 files changed, 14 insertions(+), 4 deletions(-)
net/netfilter/ipvs/ip_vs_xmit.c +14 -4
index 543a554..e56f0df 100644
@@ -85,6 +85,15 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
 	return dst;
 }
 
+static inline bool
+__mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
+{
+	if (skb->len > mtu && !skb_is_gso(skb)) {
+		return true; /* Packet size violate MTU size */
+	}
+	return false;
+}
+
 /* Get route to daddr, update *saddr, optionally bind route to saddr */
 static struct rtable *do_output_route4(struct net *net, __be32 daddr,
 				       u32 rtos, int rt_mode, __be32 *saddr)
@@ -491,7 +500,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->dst);
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if (__mtu_check_toobig_v6(skb, mtu)) {
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);
 
@@ -712,7 +721,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->dst);
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if (__mtu_check_toobig_v6(skb, mtu)) {
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);
 
@@ -946,6 +955,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 	if (skb_dst(skb))
 		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
 
+	/* MTU checking: Special for tunnel mode */
 	if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
 	    !skb_is_gso(skb)) {
 		if (!skb->dev) {
@@ -1113,7 +1123,7 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->dst);
-	if (skb->len > mtu) {
+	if (__mtu_check_toobig_v6(skb, mtu)) {
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);
 
@@ -1349,7 +1359,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->dst);
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if (__mtu_check_toobig_v6(skb, mtu)) {
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);
 
#22 lore raw

PATCH 2/2 ipvs: Extend MTU check to account for IPv6 NAT defrag changes

In reply to Jesper Dangaard Brouer

This patch is necessary, to make IPVS work, after Patrick McHardys IPv6 NAT defragmentation changes.

---

I would appriciate, if someone (e.g. Julian) double check the tunnel mode code. --Jesper

 net/netfilter/ipvs/ip_vs_xmit.c |   16 +++++++++++++---
 1 files changed, 13 insertions(+), 3 deletions(-)
net/netfilter/ipvs/ip_vs_xmit.c +13 -3
index e56f0df..20763de 100644
@@ -88,7 +88,14 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
 static inline bool
 __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
 {
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if (IP6CB(skb)->frag_max_size) {
+		/* frag_max_size tell us that, this packet have been
+		 * defragmented by netfilter IPv6 conntrack module.
+		 */
+		if (IP6CB(skb)->frag_max_size > mtu)
+			return true; /* largest fragment violate MTU */
+	}
+	else if (skb->len > mtu && !skb_is_gso(skb)) {
 		return true; /* Packet size violate MTU size */
 	}
 	return false;
@@ -956,8 +963,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
 
 	/* MTU checking: Special for tunnel mode */
-	if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
-	    !skb_is_gso(skb)) {
+	if ((!IP6CB(skb)->frag_max_size &&
+	     (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
+	      !skb_is_gso(skb)))
+	    || IP6CB(skb)->frag_max_size + sizeof(struct ipv6hdr) > mtu) {
+
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);
 
maintainer
#23 lore raw

Re: [PATCH 2/2] ipvs: Extend MTU check to account for IPv6 NAT defrag changes

Hello,

Quoted 7 lines · Jesper Dangaard Brouer

This patch is necessary, to make IPVS work, after Patrick McHardys IPv6 NAT defragmentation changes.

---

I would appriciate, if someone (e.g. Julian) double check the tunnel mode code.

Sure

Quoted 6 lines

--Jesper

 net/netfilter/ipvs/ip_vs_xmit.c |   16 +++++++++++++---
 1 files changed, 13 insertions(+), 3 deletions(-)

net/netfilter/ipvs/ip_vs_xmit.c ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, · line 970

Quoted 10 lines
net/netfilter/ipvs/ip_vs_xmit.c +5 -2
@@ -956,8 +963,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
 
 	/* MTU checking: Special for tunnel mode */
-	if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
-	    !skb_is_gso(skb)) {
+	if ((!IP6CB(skb)->frag_max_size &&
+	     (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
+	      !skb_is_gso(skb)))
+	    || IP6CB(skb)->frag_max_size + sizeof(struct ipv6hdr) > mtu) {
+

mtu is already reduced with the new outer header size,
may be we can just call __mtu_check_toobig_v6 with mtu?

net/netfilter/ipvs/ip_vs_xmit.c ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, · line 972

Quoted 2 lines
net/netfilter/ipvs/ip_vs_xmit.c +0 -0
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);

All other changes in patch 1 and 2 look ok and
I'll ack them next time.

Regards

--
Julian Anastasov <[email protected]>

#24 lore raw

Re: [PATCH 2/2] ipvs: Extend MTU check to account for IPv6 NAT defrag changes

Quoted 35 lines · Julian Anastasov

Hello,

Quoted 7 lines · Jesper Dangaard Brouer

This patch is necessary, to make IPVS work, after Patrick McHardys IPv6 NAT defragmentation changes.

---

I would appriciate, if someone (e.g. Julian) double check the tunnel mode code.

Sure

Quoted 6 lines

--Jesper

 net/netfilter/ipvs/ip_vs_xmit.c |   16 +++++++++++++---
 1 files changed, 13 insertions(+), 3 deletions(-)

net/netfilter/ipvs/ip_vs_xmit.c ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, · line 970

Quoted 10 lines
net/netfilter/ipvs/ip_vs_xmit.c +5 -2
@@ -956,8 +963,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
 
 	/* MTU checking: Special for tunnel mode */
-	if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
-	    !skb_is_gso(skb)) {
+	if ((!IP6CB(skb)->frag_max_size &&
+	     (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
+	      !skb_is_gso(skb)))
+	    || IP6CB(skb)->frag_max_size + sizeof(struct ipv6hdr) > mtu) {
+

mtu is already reduced with the new outer header size,
may be we can just call __mtu_check_toobig_v6 with mtu?

Quoted 5 lines

net/netfilter/ipvs/ip_vs_xmit.c ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, · line 972

Quoted 2 lines
net/netfilter/ipvs/ip_vs_xmit.c +0 -0
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);

All other changes in patch 1 and 2 look ok and
I'll ack them next time.

I'd like to take the final patches through my nat-ipv6 tree in order to avoid temporary regressions. Please let me know when they're ready for applying.

maintainer
#25 lore raw

Re: [PATCH 2/2] ipvs: Extend MTU check to account for IPv6 NAT defrag changes

Quoted 40 lines · Patrick McHardy
Quoted 38 lines · Julian Anastasov

Hello,

Quoted 7 lines · Jesper Dangaard Brouer

This patch is necessary, to make IPVS work, after Patrick McHardys IPv6 NAT defragmentation changes.

---

I would appriciate, if someone (e.g. Julian) double check the tunnel mode code.

Sure

Quoted 6 lines

--Jesper

net/netfilter/ipvs/ip_vs_xmit.c | 16 +++++++++++++---

1 files changed, 13 insertions(+), 3 deletions(-)

net/netfilter/ipvs/ip_vs_xmit.c ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, · line 970

Quoted 10 lines
net/netfilter/ipvs/ip_vs_xmit.c +5 -2
@@ -956,8 +963,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
 
 	/* MTU checking: Special for tunnel mode */
-	if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
-	    !skb_is_gso(skb)) {
+	if ((!IP6CB(skb)->frag_max_size &&
+	     (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
+	      !skb_is_gso(skb)))
+	    || IP6CB(skb)->frag_max_size + sizeof(struct ipv6hdr) > mtu) {
+

mtu is already reduced with the new outer header size,
may be we can just call __mtu_check_toobig_v6 with mtu?

Quoted 2 lines
net/netfilter/ipvs/ip_vs_xmit.c +0 -0
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);
Quoted 6 lines
Quoted 2 lines

All other changes in patch 1 and 2 look ok and
I'll ack them next time.

I'd like to take the final patches through my nat-ipv6 tree in order to avoid temporary regressions. Please let me know when they're ready for applying.

I'm fine with these changes going through your tree (rather than my IPVS tree) once they are ready.

#26 lore raw

v2 cover net: ipvs and netfilter IPv6 defrag MTU handling

In reply to Patrick McHardy

The following patchset V2 makes IPVS compatible with Patrick McHardys IPv6 NAT patchset: http://thread.gmane.org/gmane.linux.network/239615

Specifically the part that improves defragmentation.

Patch01: Cleanup (and fixes a bug) in IPVS MTU IPv6 handling
In V2: we also handle tunnel mode, to use the common helper

Patch02: Extend MTU check to account for IPv6 NAT defrag changes
In V2: the tunnel mode is no longer a special case.

This patchset is based upon:
Homes ipvs-next tree:
git://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs-next.git

BUT with Patrick McHardy's IPv6 NAT patchset applied first, on top of
commit: 3654e61137db891f5312e6dd813b961484b5fdf3
title: "ipvs: add pmtu_disc option to disable IP DF for TUN packets"

---

Jesper Dangaard Brouer (2):
ipvs: Extend MTU check to account for IPv6 NAT defrag changes
ipvs: IPv6 MTU checking cleanup and bugfix

 net/netfilter/ipvs/ip_vs_xmit.c |   28 ++++++++++++++++++++++------
 1 files changed, 22 insertions(+), 6 deletions(-)

--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Sr. Network Kernel Developer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer

#27 lore raw

PATCH v2 1/2 ipvs: IPv6 MTU checking cleanup and bugfix

Cleaning up the IPv6 MTU checking in the IPVS xmit code, by using a common helper function __mtu_check_toobig_v6().

The MTU check for tunnel mode can also use this helper as ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) is qual to skb->len. And the 'mtu' variable have been adjusted before calling helper.

Notice, this also fixes a bug, as the the MTU check in ip_vs_dr_xmit_v6() were missing a check for skb_is_gso().

This bug e.g. caused issues for KVM IPVS setups, where different Segmentation Offloading techniques are utilized, between guests, via the virtio driver. This resulted in very bad performance, due to the ICMPv6 "too big" messages didn't affect the sender.

---
In V2: we also make tunnel mode use the common helper

 net/netfilter/ipvs/ip_vs_xmit.c |   21 +++++++++++++++------
 1 files changed, 15 insertions(+), 6 deletions(-)
net/netfilter/ipvs/ip_vs_xmit.c +15 -6
index 543a554..67a3978 100644
@@ -85,6 +85,15 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
 	return dst;
 }
 
+static inline bool
+__mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
+{
+	if (skb->len > mtu && !skb_is_gso(skb)) {
+		return true; /* Packet size violate MTU size */
+	}
+	return false;
+}
+
 /* Get route to daddr, update *saddr, optionally bind route to saddr */
 static struct rtable *do_output_route4(struct net *net, __be32 daddr,
 				       u32 rtos, int rt_mode, __be32 *saddr)
@@ -491,7 +500,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->dst);
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if (__mtu_check_toobig_v6(skb, mtu)) {
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);
 
@@ -712,7 +721,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->dst);
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if (__mtu_check_toobig_v6(skb, mtu)) {
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);
 
@@ -946,8 +955,8 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 	if (skb_dst(skb))
 		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
 
-	if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
-	    !skb_is_gso(skb)) {
+	/* MTU checking: Notice that 'mtu' have been adjusted before hand */
+	if (__mtu_check_toobig_v6(skb, mtu)) {
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);
 
@@ -1113,7 +1122,7 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->dst);
-	if (skb->len > mtu) {
+	if (__mtu_check_toobig_v6(skb, mtu)) {
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);
 
@@ -1349,7 +1358,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 
 	/* MTU checking */
 	mtu = dst_mtu(&rt->dst);
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if (__mtu_check_toobig_v6(skb, mtu)) {
 		if (!skb->dev) {
 			struct net *net = dev_net(skb_dst(skb)->dev);
 
author Applied
#28 lore raw

Re: [PATCH V2 1/2] ipvs: IPv6 MTU checking cleanup and bugfix

Quoted 11 lines · Jesper Dangaard Brouer

Cleaning up the IPv6 MTU checking in the IPVS xmit code, by using a common helper function __mtu_check_toobig_v6().

The MTU check for tunnel mode can also use this helper as ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) is qual to skb->len. And the 'mtu' variable have been adjusted before calling helper.

Notice, this also fixes a bug, as the the MTU check in ip_vs_dr_xmit_v6() were missing a check for skb_is_gso().

Quoted 6 lines

This bug e.g. caused issues for KVM IPVS setups, where different Segmentation Offloading techniques are utilized, between guests, via the virtio driver. This resulted in very bad performance, due to the ICMPv6 "too big" messages didn't affect the sender.

Applied to my nf-nat-ipv6 tree.

#29 lore raw

PATCH v2 2/2 ipvs: Extend MTU check to account for IPv6 NAT defrag changes

In reply to Jesper Dangaard Brouer

This patch is necessary, to make IPVS work, after Patrick McHardys IPv6 NAT defragmentation changes.

---
In V2: the tunnel mode is no longer a special case.

 net/netfilter/ipvs/ip_vs_xmit.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
net/netfilter/ipvs/ip_vs_xmit.c +8 -1
index 67a3978..56f6d5d 100644
@@ -88,7 +88,14 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
 static inline bool
 __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
 {
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if (IP6CB(skb)->frag_max_size) {
+		/* frag_max_size tell us that, this packet have been
+		 * defragmented by netfilter IPv6 conntrack module.
+		 */
+		if (IP6CB(skb)->frag_max_size > mtu)
+			return true; /* largest fragment violate MTU */
+	}
+	else if (skb->len > mtu && !skb_is_gso(skb)) {
 		return true; /* Packet size violate MTU size */
 	}
 	return false;
#30 lore raw

Re: [PATCH V2 2/2] ipvs: Extend MTU check to account for IPv6 NAT defrag changes

Quoted 19 lines · Jesper Dangaard Brouer

This patch is necessary, to make IPVS work, after Patrick McHardys IPv6 NAT defragmentation changes.

---
In V2: the tunnel mode is no longer a special case.

 net/netfilter/ipvs/ip_vs_xmit.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
net/netfilter/ipvs/ip_vs_xmit.c +0 -1
index 67a3978..56f6d5d 100644
@@ -88,7 +88,14 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
 static inline bool
 __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
 {
-	if (skb->len > mtu && !skb_is_gso(skb)) {

net/netfilter/ipvs/ip_vs_xmit.c __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos) · line 100

Quoted 10 lines
net/netfilter/ipvs/ip_vs_xmit.c +8 -0
+	if (IP6CB(skb)->frag_max_size) {
+		/* frag_max_size tell us that, this packet have been
+		 * defragmented by netfilter IPv6 conntrack module.
+		 */
+		if (IP6CB(skb)->frag_max_size > mtu)
+			return true; /* largest fragment violate MTU */
+	}
+	else if (skb->len > mtu && !skb_is_gso(skb)) {
 		return true; /* Packet size violate MTU size */
 	}

Couldnt you use a single test ?

if (IP6CB(skb)->frag_max_size > mtu)

	return true;

if (skb->len > mtu && !skb_is_gso(skb))

	return true;
#31 lore raw

Re: [PATCH V2 2/2] ipvs: Extend MTU check to account for IPv6 NAT defrag changes

Quoted 11 lines · Eric Dumazet
Quoted 10 lines · Jesper Dangaard Brouer

This patch is necessary, to make IPVS work, after Patrick McHardys IPv6 NAT defragmentation changes.

---
In V2: the tunnel mode is no longer a special case.

 net/netfilter/ipvs/ip_vs_xmit.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
Quoted 15 lines
Quoted 5 lines
net/netfilter/ipvs/ip_vs_xmit.c +0 -0
index 67a3978..56f6d5d 100644

net/netfilter/ipvs/ip_vs_xmit.c __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos) · line 96

Quoted 10 lines
net/netfilter/ipvs/ip_vs_xmit.c +6 -1
@@ -88,7 +88,14 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
 static inline bool
 __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
 {
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if (IP6CB(skb)->frag_max_size) {
+		/* frag_max_size tell us that, this packet have been
+		 * defragmented by netfilter IPv6 conntrack module.
+		 */
+		if (IP6CB(skb)->frag_max_size > mtu)
+			return true; /* largest fragment violate MTU */

Implicit: else
return false

(if it makes it more clear, not sure)

Quoted 7 lines

net/netfilter/ipvs/ip_vs_xmit.c __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos) · line 100

Quoted 4 lines
net/netfilter/ipvs/ip_vs_xmit.c +2 -0
+	}
+	else if (skb->len > mtu && !skb_is_gso(skb)) {
 		return true; /* Packet size violate MTU size */
 	}

Couldnt you use a single test ?

Quoted 6 lines

if (IP6CB(skb)->frag_max_size > mtu)

	return true;

if (skb->len > mtu && !skb_is_gso(skb))

	return true;

Nope, this will not work.

If (IP6CB(skb)->frag_max_size > 0) then we have a defragmented packet, this means that skb->len cannot be used for MTU checking, because skb->len is now the total length of all the fragments (which your solution will fall-through to)

The unreadable version of the function is:

static inline bool
__mtu_check_toobig_v6_unreadable(const struct sk_buff *skb, u32 mtu)

{
       return !!((!IP6CB(skb)->frag_max_size &&
                  (skb->len > mtu && !skb_is_gso(skb)))
                 || IP6CB(skb)->frag_max_size > mtu);
}

Perhaps you like this version better (you seem to use constructions like this), but I really dislike it, because I (personally) find it harder/slower to read this kind of code, and I also believe its more error prone when someone needs to extend this.

Signature · 5 lines
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Sr. Network Kernel Developer at Red Hat
  Author of http://www.iptv-analyzer.org
  LinkedIn: http://www.linkedin.com/in/brouer
#32 lore raw

Re: [PATCH V2 2/2] ipvs: Extend MTU check to account for IPv6 NAT defrag changes

Quoted 45 lines · Jesper Dangaard Brouer
Quoted 11 lines · Eric Dumazet
Quoted 10 lines · Jesper Dangaard Brouer

This patch is necessary, to make IPVS work, after Patrick McHardys IPv6 NAT defragmentation changes.

---
In V2: the tunnel mode is no longer a special case.

 net/netfilter/ipvs/ip_vs_xmit.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
Quoted 15 lines
Quoted 5 lines
net/netfilter/ipvs/ip_vs_xmit.c +0 -0
index 67a3978..56f6d5d 100644

net/netfilter/ipvs/ip_vs_xmit.c __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos) · line 96

Quoted 10 lines
net/netfilter/ipvs/ip_vs_xmit.c +6 -1
@@ -88,7 +88,14 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
 static inline bool
 __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
 {
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if (IP6CB(skb)->frag_max_size) {
+		/* frag_max_size tell us that, this packet have been
+		 * defragmented by netfilter IPv6 conntrack module.
+		 */
+		if (IP6CB(skb)->frag_max_size > mtu)
+			return true; /* largest fragment violate MTU */

Implicit: else
return false

(if it makes it more clear, not sure)

Quoted 7 lines

net/netfilter/ipvs/ip_vs_xmit.c __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos) · line 100

Quoted 4 lines
net/netfilter/ipvs/ip_vs_xmit.c +2 -0
+	}
+	else if (skb->len > mtu && !skb_is_gso(skb)) {
 		return true; /* Packet size violate MTU size */
 	}

Couldnt you use a single test ?

Quoted 6 lines

if (IP6CB(skb)->frag_max_size > mtu)

	return true;

if (skb->len > mtu && !skb_is_gso(skb))

	return true;
Quoted 7 lines

Nope, this will not work.

If (IP6CB(skb)->frag_max_size > 0) then we have a defragmented packet, this means that skb->len cannot be used for MTU checking, because skb->len is now the total length of all the fragments (which your solution will fall-through to)

If the packet was not fragmented, its was a single frame.

But if this frame length is above mtu, packet is not too big ?

Sorry if its a stupid question.

#33 lore raw

Re: [PATCH V2 2/2] ipvs: Extend MTU check to account for IPv6 NAT defrag changes

Quoted 54 lines · Eric Dumazet
Quoted 45 lines · Jesper Dangaard Brouer
Quoted 11 lines · Eric Dumazet
Quoted 10 lines · Jesper Dangaard Brouer

This patch is necessary, to make IPVS work, after Patrick McHardys IPv6 NAT defragmentation changes.

---
In V2: the tunnel mode is no longer a special case.

 net/netfilter/ipvs/ip_vs_xmit.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
Quoted 15 lines
Quoted 5 lines
net/netfilter/ipvs/ip_vs_xmit.c +0 -0
index 67a3978..56f6d5d 100644

net/netfilter/ipvs/ip_vs_xmit.c __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos) · line 96

Quoted 10 lines
net/netfilter/ipvs/ip_vs_xmit.c +6 -1
@@ -88,7 +88,14 @@ __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos)
 static inline bool
 __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
 {
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if (IP6CB(skb)->frag_max_size) {
+		/* frag_max_size tell us that, this packet have been
+		 * defragmented by netfilter IPv6 conntrack module.
+		 */
+		if (IP6CB(skb)->frag_max_size > mtu)
+			return true; /* largest fragment violate MTU */

Implicit: else
return false

(if it makes it more clear, not sure)

Quoted 7 lines

net/netfilter/ipvs/ip_vs_xmit.c __ip_vs_dst_check(struct ip_vs_dest *dest, u32 rtos) · line 100

Quoted 4 lines
net/netfilter/ipvs/ip_vs_xmit.c +2 -0
+	}
+	else if (skb->len > mtu && !skb_is_gso(skb)) {
 		return true; /* Packet size violate MTU size */
 	}

Couldnt you use a single test ?

Quoted 6 lines

if (IP6CB(skb)->frag_max_size > mtu)

	return true;

if (skb->len > mtu && !skb_is_gso(skb))

	return true;
Quoted 7 lines

Nope, this will not work.

If (IP6CB(skb)->frag_max_size > 0) then we have a defragmented packet, this means that skb->len cannot be used for MTU checking, because skb->len is now the total length of all the fragments (which your solution will fall-through to)

Quoted 3 lines

If the packet was not fragmented, its was a single frame.

But if this frame length is above mtu, packet is not too big ?

Nope... not if its a defragmented/reassembled packet.

Quoted 1 line

Sorry if its a stupid question.

These changes have to be seen together with Patrick's patch:
"netfilter: nf_conntrack_ipv6: improve fragmentation handling"
http://thread.gmane.org/gmane.linux.network/241517/focus=241518

The IPv6 packet arriving have been defragmented/reassembled by the nf_conntrack_ipv6 module. Thus, they look like a normal, but big,
packet to us. We let it through, because it will be re-fragmented
again later, but first we need to check if the largest fragment would violate the MTU.

Hope it makes it more clear.

#35 lore raw

Re: [PATCH 2/2] ipvs: Extend MTU check to account for IPv6 NAT defrag changes

In reply to Julian Anastasov
Quoted 16 lines · Julian Anastasov

Hello,

Quoted 7 lines · Jesper Dangaard Brouer

This patch is necessary, to make IPVS work, after Patrick McHardys IPv6 NAT defragmentation changes.

---

I would appriciate, if someone (e.g. Julian) double check the tunnel mode code.

Sure

Quoted 2 lines

--Jesper

Quoted 8 lines

net/netfilter/ipvs/ip_vs_xmit.c ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, · line 959

Quoted 8 lines
 net/netfilter/ipvs/ip_vs_xmit.c |   16 +++++++++++++---
 1 files changed, 13 insertions(+), 3 deletions(-)
net/netfilter/ipvs/ip_vs_xmit.c +0 -1
@@ -956,8 +963,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
 
 	/* MTU checking: Special for tunnel mode */
-	if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&

I guess:
ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)
Is the same as:
skb->len

Quoted 9 lines

net/netfilter/ipvs/ip_vs_xmit.c ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, · line 969

Quoted 5 lines
net/netfilter/ipvs/ip_vs_xmit.c +4 -1
-	    !skb_is_gso(skb)) {
+	if ((!IP6CB(skb)->frag_max_size &&
+	     (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
+	      !skb_is_gso(skb)))
+	    || IP6CB(skb)->frag_max_size + sizeof(struct ipv6hdr) > mtu) {

mtu is already reduced with the new outer header size,
may be we can just call __mtu_check_toobig_v6 with mtu?

To Julian, is the extra sizeof(struct ipv6hdr) addition to frag_max_size, wrong? (as the mtu is already reduced)

If above statements hold, I think we can simply use __mtu_check_toobig_v6() also for the tunnel case :-)

--Jesper

maintainer
#36 lore raw

Re: [PATCH 2/2] ipvs: Extend MTU check to account for IPv6 NAT defrag changes

Hello,

Quoted 5 lines · Jesper Dangaard Brouer
Quoted 4 lines · Julian Anastasov
Quoted 4 lines
net/netfilter/ipvs/ip_vs_xmit.c +0 -0
@@ -956,8 +963,11 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
 
Quoted 7 lines
Quoted 2 lines

net/netfilter/ipvs/ip_vs_xmit.c ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, · line 959

Quoted 2 lines
net/netfilter/ipvs/ip_vs_xmit.c +0 -1
 	/* MTU checking: Special for tunnel mode */
-	if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&

I guess:
ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)
Is the same as:
skb->len

I think so. You can think of this in different way:
all transmitters are called from same place, there is no difference in the packets we see. When we can use __mtu_check_toobig_v6 for other methods relying on skb->len being correct, we can do the same for tunnels, only that tunnels have lower MTU, that is the only difference.

Quoted 10 lines
Quoted 9 lines

net/netfilter/ipvs/ip_vs_xmit.c ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, · line 969

Quoted 5 lines
net/netfilter/ipvs/ip_vs_xmit.c +4 -1
-	    !skb_is_gso(skb)) {
+	if ((!IP6CB(skb)->frag_max_size &&
+	     (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr) &&
+	      !skb_is_gso(skb)))
+	    || IP6CB(skb)->frag_max_size + sizeof(struct ipv6hdr) > mtu) {

mtu is already reduced with the new outer header size,
may be we can just call __mtu_check_toobig_v6 with mtu?

Quoted 2 lines

To Julian, is the extra sizeof(struct ipv6hdr) addition to frag_max_size, wrong? (as the mtu is already reduced)

Yes, sizeof(struct ipv6hdr) is needed only together
with payload_len because payload_len does not include the first header.

Quoted 2 lines

If above statements hold, I think we can simply use __mtu_check_toobig_v6() also for the tunnel case :-)

Yep

Quoted 1 line

--Jesper

Regards

--
Julian Anastasov <[email protected]>

#37 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

In reply to [email protected]
Quoted 133 lines · On Thu, Aug 09, 2012 at 10:08:49PM +0200, [email protected] wrote:

From: Patrick McHardy <[email protected]>

The IPv6 conntrack fragmentation currently has a couple of shortcomings. Fragmentes are collected in PREROUTING/OUTPUT, are defragmented, the defragmented packet is then passed to conntrack, the resulting conntrack information is attached to each original fragment and the fragments then continue their way through the stack.

Helper invocation occurs in the POSTROUTING hook, at which point only the original fragments are available. The result of this is that fragmented packets are never passed to helpers.

This patch improves the situation in the following way:

- If a reassembled packet belongs to a connection that has a helper assigned, the reassembled packet is passed through the stack instead of the original fragments.

- During defragmentation, the largest received fragment size is stored. On output, the packet is refragmented if required. If the largest received fragment size exceeds the outgoing MTU, a "packet too big" message is generated, thus behaving as if the original fragments were passed through the stack from an outside point of view.

- The ipv6_helper() hook function can't receive fragments anymore for connections using a helper, so it is switched to use ipv6_skip_exthdr() instead of the netfilter specific nf_ct_ipv6_skip_exthdr() and the reassembled packets are passed to connection tracking helpers.

The result of this is that we can properly track fragmented packets, but still generate ICMPv6 Packet too big messages if we would have before.

This patch is also required as a precondition for IPv6 NAT, where NAT helpers might enlarge packets up to a point that they require fragmentation. In that case we can't generate Packet too big messages since the proper MTU can't be calculated in all cases (f.i. when changing textual representation of a variable amount of addresses), so the packet is transparently fragmented iff the original packet or fragments would have fit the outgoing MTU.

---
 include/linux/ipv6.h                           |    1 +
 net/ipv6/ip6_output.c                          |    7 +++-
 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |   37 ++++++++++++++++++------
 net/ipv6/netfilter/nf_conntrack_reasm.c        |   19 ++++++++++--
 4 files changed, 50 insertions(+), 14 deletions(-)
include/linux/ipv6.h +1 -0
index 879db26..0b94e91 100644
@@ -256,6 +256,7 @@ struct inet6_skb_parm {
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
 	__u16			dsthao;
 #endif
+	__u16			frag_max_size;
 
 #define IP6SKB_XFRM_TRANSFORMED	1
 #define IP6SKB_FORWARDED	2
net/ipv6/ip6_output.c +5 -2
index 5b2d63e..a4f6263 100644
@@ -493,7 +493,8 @@ int ip6_forward(struct sk_buff *skb)
 	if (mtu < IPV6_MIN_MTU)
 		mtu = IPV6_MIN_MTU;
 
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) ||
+	    (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) {
 		/* Again, force OUTPUT device used as source address */
 		skb->dev = dst->dev;
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
@@ -636,7 +637,9 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 	/* We must not fragment if the socket is set to force MTU discovery
 	 * or if the skb it not generated by a local socket.
 	 */
-	if (unlikely(!skb->local_df && skb->len > mtu)) {
+	if (unlikely(!skb->local_df && skb->len > mtu) ||
+		     (IP6CB(skb)->frag_max_size &&
+		      IP6CB(skb)->frag_max_size > mtu)) {
 		if (skb->sk && dst_allfrag(skb_dst(skb)))
 			sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
 
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +12 -7
index 4794f96..560d823 100644
@@ -153,10 +153,10 @@ static unsigned int ipv6_helper(unsigned int hooknum,
 	const struct nf_conn_help *help;
 	const struct nf_conntrack_helper *helper;
 	enum ip_conntrack_info ctinfo;
-	unsigned int ret, protoff;
-	unsigned int extoff = (u8 *)(ipv6_hdr(skb) + 1) - skb->data;
-	unsigned char pnum = ipv6_hdr(skb)->nexthdr;
-
+	unsigned int ret;
+	__be16 frag_off;
+	int protoff;
+	u8 nexthdr;
 
 	/* This is where we call the helper: as the packet goes out. */
 	ct = nf_ct_get(skb, &ctinfo);
@@ -171,9 +171,10 @@ static unsigned int ipv6_helper(unsigned int hooknum,
 	if (!helper)
 		return NF_ACCEPT;
 
-	protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum,
-					 skb->len - extoff);
-	if (protoff > skb->len || pnum == NEXTHDR_FRAGMENT) {
+	nexthdr = ipv6_hdr(skb)->nexthdr;
+	protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
+				   &frag_off);
+	if (protoff < 0 || (frag_off & ntohs(~0x7)) != 0) {
 		pr_debug("proto header not found\n");
 		return NF_ACCEPT;
 	}
@@ -199,9 +200,13 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
 static unsigned int __ipv6_conntrack_in(struct net *net,
 					unsigned int hooknum,
 					struct sk_buff *skb,
+					const struct net_device *in,
+					const struct net_device *out,
 					int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *reasm = skb->nfct_reasm;
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
 
 	/* This packet is fragmented and has reassembled packet. */
 	if (reasm) {

net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c static unsigned int __ipv6_conntrack_in(struct net *net, · line 226

Quoted 9 lines
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +6 -0
@@ -213,6 +218,20 @@ static unsigned int __ipv6_conntrack_in(struct net *net,
 			if (ret != NF_ACCEPT)
 				return ret;
 		}
+
+		/* Conntrack helpers need the entire reassembled packet in the
+		 * POST_ROUTING hook.
+		 */
+		ct = nf_ct_get(reasm, &ctinfo);
+		if (ct != NULL && test_bit(IPS_HELPER_BIT, &ct->status)) {

Two things regarding the line above:

- I think this also need to check for !nf_ct_is_untracked(ct)

- IPS_HELPER_BIT is only set if the CT target is used to attach helpers. I know, this behaviour may seem confusing, but I didn't find any better way to avoid that NAT removes the helper explicitly attached via CT.

So basically now that status bit means: "this helper has been attached via CT".

Setting it inconditionally in __nf_ct_try_assign_helper would break the magic auto-assign helper code.

On the other hand, the automatic helper assignment is scheduled to be removed (well, it would still take at least one 1.5/2 years before we do so). At that time, we'll be able to say that all conntrack with IPS_HELPER really has one helper. But now I think that you'll have to use for nfct_help instead to check if that ct has a helper.

Quoted 106 lines
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +10 -2
+			nf_conntrack_get_reasm(skb);
+			NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
+				       (struct net_device *)in,
+				       (struct net_device *)out,
+				       okfn, NF_IP6_PRI_CONNTRACK + 1);
+			return NF_DROP_ERR(-ECANCELED);
+		}
+
 		nf_conntrack_get(reasm->nfct);
 		skb->nfct = reasm->nfct;
 		skb->nfctinfo = reasm->nfctinfo;
@@ -228,7 +247,7 @@ static unsigned int ipv6_conntrack_in(unsigned int hooknum,
 				      const struct net_device *out,
 				      int (*okfn)(struct sk_buff *))
 {
-	return __ipv6_conntrack_in(dev_net(in), hooknum, skb, okfn);
+	return __ipv6_conntrack_in(dev_net(in), hooknum, skb, in, out, okfn);
 }
 
 static unsigned int ipv6_conntrack_local(unsigned int hooknum,
@@ -242,7 +261,7 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum,
 		net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
 		return NF_ACCEPT;
 	}
-	return __ipv6_conntrack_in(dev_net(out), hooknum, skb, okfn);
+	return __ipv6_conntrack_in(dev_net(out), hooknum, skb, in, out, okfn);
 }
 
 static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
net/ipv6/netfilter/nf_conntrack_reasm.c +16 -3
index c9c78c2..f94fb3a 100644
@@ -190,6 +190,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 			     const struct frag_hdr *fhdr, int nhoff)
 {
 	struct sk_buff *prev, *next;
+	unsigned int payload_len;
 	int offset, end;
 
 	if (fq->q.last_in & INET_FRAG_COMPLETE) {
@@ -197,8 +198,10 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 		goto err;
 	}
 
+	payload_len = ntohs(ipv6_hdr(skb)->payload_len);
+
 	offset = ntohs(fhdr->frag_off) & ~0x7;
-	end = offset + (ntohs(ipv6_hdr(skb)->payload_len) -
+	end = offset + (payload_len -
 			((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));
 
 	if ((unsigned int)end > IPV6_MAXPLEN) {
@@ -307,6 +310,8 @@ found:
 	skb->dev = NULL;
 	fq->q.stamp = skb->tstamp;
 	fq->q.meat += skb->len;
+	if (payload_len > fq->q.max_size)
+		fq->q.max_size = payload_len;
 	atomic_add(skb->truesize, &nf_init_frags.mem);
 
 	/* The first fragment.
@@ -412,10 +417,12 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 	}
 	atomic_sub(head->truesize, &nf_init_frags.mem);
 
+	head->local_df = 1;
 	head->next = NULL;
 	head->dev = dev;
 	head->tstamp = fq->q.stamp;
 	ipv6_hdr(head)->payload_len = htons(payload_len);
+	IP6CB(head)->frag_max_size = sizeof(struct ipv6hdr) + fq->q.max_size;
 
 	/* Yes, and fold redundant checksum back. 8) */
 	if (head->ip_summed == CHECKSUM_COMPLETE)
@@ -592,6 +599,7 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
 			int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *s, *s2;
+	unsigned int ret = 0;
 
 	for (s = NFCT_FRAG6_CB(skb)->orig; s;) {
 		nf_conntrack_put_reasm(s->nfct_reasm);
@@ -601,8 +609,13 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
 		s2 = s->next;
 		s->next = NULL;
 
-		NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s, in, out, okfn,
-			       NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
+		if (ret != -ECANCELED)
+			ret = NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s,
+					     in, out, okfn,
+					     NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
+		else
+			kfree_skb(s);
+
 		s = s2;
 	}
 	nf_conntrack_put_reasm(skb);
Signature · 6 lines
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#38 lore raw

Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling

Quoted 11 lines · Pablo Neira Ayuso

Review

Quoted 6 lines · On Thu, Aug 09, 2012 at 10:08:49PM +0200, [email protected] wrote:
(quoted diff) +6 -0
+
+		/* Conntrack helpers need the entire reassembled packet in the
+		 * POST_ROUTING hook.
+		 */
+		ct = nf_ct_get(reasm, &ctinfo);
+		if (ct != NULL && test_bit(IPS_HELPER_BIT, &ct->status)) {

Two things regarding the line above:

- I think this also need to check for !nf_ct_is_untracked(ct)

Fixed, thanks.

Quoted 12 lines

- IPS_HELPER_BIT is only set if the CT target is used to attach helpers. I know, this behaviour may seem confusing, but I didn't find any better way to avoid that NAT removes the helper explicitly attached via CT.

So basically now that status bit means: "this helper has been attached via CT".

Setting it inconditionally in __nf_ct_try_assign_helper would break the magic auto-assign helper code.

Quoted 6 lines

On the other hand, the automatic helper assignment is scheduled to be removed (well, it would still take at least one 1.5/2 years before we do so). At that time, we'll be able to say that all conntrack with IPS_HELPER really has one helper. But now I think that you'll have to use for nfct_help instead to check if that ct has a helper.

I see. Also fixed, thanks. New patch attached.

commit f4266409e20dc0d2d22447aa7935c997f38914a1

Author: Patrick McHardy <[email protected]>
Date:   Tue Aug 14 15:27:55 2012 +0200

netfilter: nf_conntrack_ipv6: improve fragmentation handling

The IPv6 conntrack fragmentation currently has a couple of shortcomings. Fragmentes are collected in PREROUTING/OUTPUT, are defragmented, the defragmented packet is then passed to conntrack, the resulting conntrack information is attached to each original fragment and the fragments then continue their way through the stack.

Helper invocation occurs in the POSTROUTING hook, at which point only the original fragments are available. The result of this is that fragmented packets are never passed to helpers.

This patch improves the situation in the following way:

- If a reassembled packet belongs to a connection that has a helper assigned, the reassembled packet is passed through the stack instead of the original fragments.

- During defragmentation, the largest received fragment size is stored. On output, the packet is refragmented if required. If the largest received fragment size exceeds the outgoing MTU, a "packet too big" message is generated, thus behaving as if the original fragments were passed through the stack from an outside point of view.

- The ipv6_helper() hook function can't receive fragments anymore for connections using a helper, so it is switched to use ipv6_skip_exthdr() instead of the netfilter specific nf_ct_ipv6_skip_exthdr() and the reassembled packets are passed to connection tracking helpers.

The result of this is that we can properly track fragmented packets, but still generate ICMPv6 Packet too big messages if we would have before.

This patch is also required as a precondition for IPv6 NAT, where NAT helpers might enlarge packets up to a point that they require fragmentation. In that case we can't generate Packet too big messages since the proper MTU can't be calculated in all cases (f.i. when changing textual representation of a variable amount of addresses), so the packet is transparently fragmented iff the original packet or fragments would have fit the outgoing MTU.

include/linux/ipv6.h +1 -0
index 879db26..0b94e91 100644
@@ -256,6 +256,7 @@ struct inet6_skb_parm {
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
 	__u16			dsthao;
 #endif
+	__u16			frag_max_size;
 
 #define IP6SKB_XFRM_TRANSFORMED	1
 #define IP6SKB_FORWARDED	2
net/ipv6/ip6_output.c +5 -2
index 5b2d63e..a4f6263 100644
@@ -493,7 +493,8 @@ int ip6_forward(struct sk_buff *skb)
 	if (mtu < IPV6_MIN_MTU)
 		mtu = IPV6_MIN_MTU;
 
-	if (skb->len > mtu && !skb_is_gso(skb)) {
+	if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) ||
+	    (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) {
 		/* Again, force OUTPUT device used as source address */
 		skb->dev = dst->dev;
 		icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
@@ -636,7 +637,9 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 	/* We must not fragment if the socket is set to force MTU discovery
 	 * or if the skb it not generated by a local socket.
 	 */
-	if (unlikely(!skb->local_df && skb->len > mtu)) {
+	if (unlikely(!skb->local_df && skb->len > mtu) ||
+		     (IP6CB(skb)->frag_max_size &&
+		      IP6CB(skb)->frag_max_size > mtu)) {
 		if (skb->sk && dst_allfrag(skb_dst(skb)))
 			sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
 
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +32 -9

80 lines not on this page · raw message

net/ipv6/netfilter/nf_conntrack_reasm.c +16 -3
index c9c78c2..f94fb3a 100644
@@ -190,6 +190,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 			     const struct frag_hdr *fhdr, int nhoff)
 {
 	struct sk_buff *prev, *next;
+	unsigned int payload_len;
 	int offset, end;
 
 	if (fq->q.last_in & INET_FRAG_COMPLETE) {
@@ -197,8 +198,10 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 		goto err;
 	}
 
+	payload_len = ntohs(ipv6_hdr(skb)->payload_len);
+
 	offset = ntohs(fhdr->frag_off) & ~0x7;
-	end = offset + (ntohs(ipv6_hdr(skb)->payload_len) -
+	end = offset + (payload_len -
 			((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));
 
 	if ((unsigned int)end > IPV6_MAXPLEN) {
@@ -307,6 +310,8 @@ found:
 	skb->dev = NULL;
 	fq->q.stamp = skb->tstamp;
 	fq->q.meat += skb->len;
+	if (payload_len > fq->q.max_size)
+		fq->q.max_size = payload_len;
 	atomic_add(skb->truesize, &nf_init_frags.mem);
 
 	/* The first fragment.
@@ -412,10 +417,12 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 	}
 	atomic_sub(head->truesize, &nf_init_frags.mem);
 
+	head->local_df = 1;
 	head->next = NULL;
 	head->dev = dev;
 	head->tstamp = fq->q.stamp;
 	ipv6_hdr(head)->payload_len = htons(payload_len);
+	IP6CB(head)->frag_max_size = sizeof(struct ipv6hdr) + fq->q.max_size;
 
 	/* Yes, and fold redundant checksum back. 8) */
 	if (head->ip_summed == CHECKSUM_COMPLETE)
@@ -592,6 +599,7 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
 			int (*okfn)(struct sk_buff *))
 {
 	struct sk_buff *s, *s2;
+	unsigned int ret = 0;
 
 	for (s = NFCT_FRAG6_CB(skb)->orig; s;) {
 		nf_conntrack_put_reasm(s->nfct_reasm);
@@ -601,8 +609,13 @@ void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
 		s2 = s->next;
 		s->next = NULL;
 
-		NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s, in, out, okfn,
-			       NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
+		if (ret != -ECANCELED)
+			ret = NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s,
+					     in, out, okfn,
+					     NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
+		else
+			kfree_skb(s);
+
 		s = s2;
 	}
 	nf_conntrack_put_reasm(skb);
#39 lore raw

PATCH 6/19 netfilter: nf_conntrack_ipv6: fix tracking of ICMPv6 error messages containing fragments

In reply to [email protected]

From: Patrick McHardy <[email protected]>

ICMPv6 error messages are tracked by extracting the conntrack tuple of the inner packet and looking up the corresponding conntrack entry. Tuple extraction uses the ->get_l4proto() callback, which in case of fragments returns NEXTHDR_FRAGMENT instead of the upper protocol, even for the first fragment when the entire next header is present, resulting in a failure to find the correct connection tracking entry.

This patch changes ipv6_get_l4proto() to use ipv6_skip_exthdr() instead of nf_ct_ipv6_skip_exthdr() in order to skip fragment headers when the fragment offset is zero.

---
 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |   63 ++---------------------
 1 files changed, 6 insertions(+), 57 deletions(-)
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +6 -57
index 560d823..4d92ea6 100644
@@ -64,82 +64,31 @@ static int ipv6_print_tuple(struct seq_file *s,
 			  tuple->src.u3.ip6, tuple->dst.u3.ip6);
 }
 
-/*
- * Based on ipv6_skip_exthdr() in net/ipv6/exthdr.c
- *
- * This function parses (probably truncated) exthdr set "hdr"
- * of length "len". "nexthdrp" initially points to some place,
- * where type of the first header can be found.
- *
- * It skips all well-known exthdrs, and returns pointer to the start
- * of unparsable area i.e. the first header with unknown type.
- * if success, *nexthdr is updated by type/protocol of this header.
- *
- * NOTES: - it may return pointer pointing beyond end of packet,
- *          if the last recognized header is truncated in the middle.
- *        - if packet is truncated, so that all parsed headers are skipped,
- *          it returns -1.
- *        - if packet is fragmented, return pointer of the fragment header.
- *        - ESP is unparsable for now and considered like
- *          normal payload protocol.
- *        - Note also special handling of AUTH header. Thanks to IPsec wizards.
- */
-
-static int nf_ct_ipv6_skip_exthdr(const struct sk_buff *skb, int start,
-				  u8 *nexthdrp, int len)
-{
-	u8 nexthdr = *nexthdrp;
-
-	while (ipv6_ext_hdr(nexthdr)) {
-		struct ipv6_opt_hdr hdr;
-		int hdrlen;
-
-		if (len < (int)sizeof(struct ipv6_opt_hdr))
-			return -1;
-		if (nexthdr == NEXTHDR_NONE)
-			break;
-		if (nexthdr == NEXTHDR_FRAGMENT)
-			break;
-		if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
-			BUG();
-		if (nexthdr == NEXTHDR_AUTH)
-			hdrlen = (hdr.hdrlen+2)<<2;
-		else
-			hdrlen = ipv6_optlen(&hdr);
-
-		nexthdr = hdr.nexthdr;
-		len -= hdrlen;
-		start += hdrlen;
-	}
-
-	*nexthdrp = nexthdr;
-	return start;
-}
-
 static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
 			    unsigned int *dataoff, u_int8_t *protonum)
 {
 	unsigned int extoff = nhoff + sizeof(struct ipv6hdr);
-	unsigned char pnum;
+	__be16 frag_off;
 	int protoff;
+	u8 nexthdr;
 
 	if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr),
-			  &pnum, sizeof(pnum)) != 0) {
+			  &nexthdr, sizeof(nexthdr)) != 0) {
 		pr_debug("ip6_conntrack_core: can't get nexthdr\n");
 		return -NF_ACCEPT;
 	}
-	protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum, skb->len - extoff);
+	protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off);
 	/*
 	 * (protoff == skb->len) mean that the packet doesn't have no data
 	 * except of IPv6 & ext headers. but it's tracked anyway. - YK
 	 */
-	if ((protoff < 0) || (protoff > skb->len)) {
+	if (protoff < 0 || (frag_off & ntohs(~0x7)) != 0) {
 		pr_debug("ip6_conntrack_core: can't find proto in pkt\n");
 		return -NF_ACCEPT;
 	}
 
 	*dataoff = protoff;
-	*protonum = pnum;
+	*protonum = nexthdr;
 	return NF_ACCEPT;
 }
 
Signature · 1 line
1.7.1
#40 lore raw

PATCH 7/19 netfilter: nf_conntrack: restrict NAT helper invocation to IPv4

In reply to [email protected]

From: Patrick McHardy <[email protected]>

The NAT helpers currently only handle IPv4 packets correctly. Restrict invocation of the helpers to IPv4 in preparation of IPv6 NAT.

---
 net/netfilter/nf_conntrack_amanda.c    |    3 +-
 net/netfilter/nf_conntrack_ftp.c       |    3 +-
 net/netfilter/nf_conntrack_h323_main.c |   41 ++++++++++++++++++++++---------
 net/netfilter/nf_conntrack_irc.c       |    3 +-
 net/netfilter/nf_conntrack_sip.c       |   18 +++++++++----
 net/netfilter/nf_conntrack_tftp.c      |    3 +-
 6 files changed, 49 insertions(+), 22 deletions(-)
net/netfilter/nf_conntrack_amanda.c +2 -1
index f2de8c5..184c0dc 100644
@@ -154,7 +154,8 @@ static int amanda_help(struct sk_buff *skb,
 				  IPPROTO_TCP, NULL, &port);
 
 		nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook);
-		if (nf_nat_amanda && ct->status & IPS_NAT_MASK)
+		if (nf_nat_amanda && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+		    ct->status & IPS_NAT_MASK)
 			ret = nf_nat_amanda(skb, ctinfo, off - dataoff,
 					    len, exp);
 		else if (nf_ct_expect_related(exp) != 0)
net/netfilter/nf_conntrack_ftp.c +2 -1
index 4bb771d..3e1587e 100644
@@ -487,7 +487,8 @@ static int help(struct sk_buff *skb,
 	/* Now, NAT might want to mangle the packet, and register the
 	 * (possibly changed) expectation itself. */
 	nf_nat_ftp = rcu_dereference(nf_nat_ftp_hook);
-	if (nf_nat_ftp && ct->status & IPS_NAT_MASK)
+	if (nf_nat_ftp && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+	    ct->status & IPS_NAT_MASK)
 		ret = nf_nat_ftp(skb, ctinfo, search[dir][i].ftptype,
 				 matchoff, matchlen, exp);
 	else {
net/netfilter/nf_conntrack_h323_main.c +29 -12

143 lines not on this page · raw message

net/netfilter/nf_conntrack_irc.c +2 -1
index 009c52c..e06dc2f 100644
@@ -204,7 +204,8 @@ static int help(struct sk_buff *skb, unsigned int protoff,
 					  IPPROTO_TCP, NULL, &port);
 
 			nf_nat_irc = rcu_dereference(nf_nat_irc_hook);
-			if (nf_nat_irc && ct->status & IPS_NAT_MASK)
+			if (nf_nat_irc && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+			    ct->status & IPS_NAT_MASK)
 				ret = nf_nat_irc(skb, ctinfo,
 						 addr_beg_p - ib_ptr,
 						 addr_end_p - addr_beg_p,
net/netfilter/nf_conntrack_sip.c +12 -6
index 5c0a112..d08e0ba 100644
@@ -981,7 +981,8 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int dataoff,
 			  IPPROTO_UDP, NULL, &rtcp_port);
 
 	nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook);
-	if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp)
+	if (nf_nat_sdp_media && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+	    ct->status & IPS_NAT_MASK && !direct_rtp)
 		ret = nf_nat_sdp_media(skb, dataoff, dptr, datalen,
 				       rtp_exp, rtcp_exp,
 				       mediaoff, medialen, daddr);
@@ -1104,7 +1105,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int dataoff,
 			return ret;
 
 		/* Update media connection address if present */
-		if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
+		if (maddr_len && nf_nat_sdp_addr &&
+		    nf_ct_l3num(ct) == NFPROTO_IPV4 && ct->status & IPS_NAT_MASK) {
 			ret = nf_nat_sdp_addr(skb, dataoff, dptr, datalen,
 					      mediaoff, c_hdr, SDP_HDR_MEDIA,
 					      &rtp_addr);
@@ -1116,7 +1118,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int dataoff,
 
 	/* Update session connection and owner addresses */
 	nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook);
-	if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK)
+	if (nf_nat_sdp_session && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+	    ct->status & IPS_NAT_MASK)
 		ret = nf_nat_sdp_session(skb, dataoff, dptr, datalen, sdpoff,
 					 &rtp_addr);
 
@@ -1275,7 +1278,8 @@ static int process_register_request(struct sk_buff *skb, unsigned int dataoff,
 	exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
 
 	nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook);
-	if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK)
+	if (nf_nat_sip_expect && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+	    ct->status & IPS_NAT_MASK)
 		ret = nf_nat_sip_expect(skb, dataoff, dptr, datalen, exp,
 					matchoff, matchlen);
 	else {
@@ -1453,7 +1457,8 @@ static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct,
 	else
 		ret = process_sip_response(skb, dataoff, dptr, datalen);
 
-	if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
+	if (ret == NF_ACCEPT && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+	    ct->status & IPS_NAT_MASK) {
 		nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
 		if (nf_nat_sip && !nf_nat_sip(skb, dataoff, dptr, datalen))
 			ret = NF_DROP;
@@ -1534,7 +1539,8 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
 		datalen  = datalen + diff - msglen;
 	}
 
-	if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
+	if (ret == NF_ACCEPT && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+	    ct->status & IPS_NAT_MASK) {
 		nf_nat_sip_seq_adjust = rcu_dereference(nf_nat_sip_seq_adjust_hook);
 		if (nf_nat_sip_seq_adjust)
 			nf_nat_sip_seq_adjust(skb, tdiff);
net/netfilter/nf_conntrack_tftp.c +2 -1
index 81fc61c..9363e1c 100644
@@ -72,7 +72,8 @@ static int tftp_help(struct sk_buff *skb,
 		nf_ct_dump_tuple(&exp->tuple);
 
 		nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook);
-		if (nf_nat_tftp && ct->status & IPS_NAT_MASK)
+		if (nf_nat_tftp && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
+		    ct->status & IPS_NAT_MASK)
 			ret = nf_nat_tftp(skb, ctinfo, exp);
 		else if (nf_ct_expect_related(exp) != 0)
 			ret = NF_DROP;
Signature · 1 line
1.7.1
#41 lore raw

PATCH 8/19 netfilter: nf_nat: add protoff argument to packet mangling functions

In reply to [email protected]

From: Patrick McHardy <[email protected]>

For mangling IPv6 packets the protocol header offset needs to be known by the NAT packet mangling functions. Add a so far unused protoff argument and convert the conntrack and NAT helpers to use it in preparation of IPv6 NAT.

---
 include/linux/netfilter/nf_conntrack_amanda.h  |    1 +
 include/linux/netfilter/nf_conntrack_ftp.h     |    1 +
 include/linux/netfilter/nf_conntrack_h323.h    |   15 ++-
 include/linux/netfilter/nf_conntrack_irc.h     |    1 +
 include/linux/netfilter/nf_conntrack_pptp.h    |    2 +
 include/linux/netfilter/nf_conntrack_sip.h     |   12 ++-
 include/net/netfilter/nf_nat_helper.h          |   11 +-
 net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c |    6 +-
 net/ipv4/netfilter/nf_nat_amanda.c             |    3 +-
 net/ipv4/netfilter/nf_nat_ftp.c                |    3 +-
 net/ipv4/netfilter/nf_nat_h323.c               |   48 ++++---
 net/ipv4/netfilter/nf_nat_helper.c             |    9 +-
 net/ipv4/netfilter/nf_nat_irc.c                |    3 +-
 net/ipv4/netfilter/nf_nat_pptp.c               |    6 +-
 net/ipv4/netfilter/nf_nat_sip.c                |   96 +++++++-----
 net/netfilter/ipvs/ip_vs_ftp.c                 |    1 +
 net/netfilter/nf_conntrack_amanda.c            |    5 +-
 net/netfilter/nf_conntrack_ftp.c               |    3 +-
 net/netfilter/nf_conntrack_h323_main.c         |  191 +++++++++++++++---------
 net/netfilter/nf_conntrack_irc.c               |    3 +-
 net/netfilter/nf_conntrack_pptp.c              |   18 ++-
 net/netfilter/nf_conntrack_sip.c               |   95 +++++++-----
 22 files changed, 328 insertions(+), 205 deletions(-)
include/linux/netfilter/nf_conntrack_amanda.h +1 -0
index 0bb5a69..4b59a15 100644
@@ -4,6 +4,7 @@
 
 extern unsigned int (*nf_nat_amanda_hook)(struct sk_buff *skb,
 					  enum ip_conntrack_info ctinfo,
+					  unsigned int protoff,
 					  unsigned int matchoff,
 					  unsigned int matchlen,
 					  struct nf_conntrack_expect *exp);
include/linux/netfilter/nf_conntrack_ftp.h +1 -0
index 3e3aa08..28f18df 100644
@@ -34,6 +34,7 @@ struct nf_conntrack_expect;
 extern unsigned int (*nf_nat_ftp_hook)(struct sk_buff *skb,
 				       enum ip_conntrack_info ctinfo,
 				       enum nf_ct_ftp_type type,
+				       unsigned int protoff,
 				       unsigned int matchoff,
 				       unsigned int matchlen,
 				       struct nf_conntrack_expect *exp);
include/linux/netfilter/nf_conntrack_h323.h +10 -5
index 26f9226..f381020 100644
@@ -36,12 +36,12 @@ extern void nf_conntrack_h245_expect(struct nf_conn *new,
 				     struct nf_conntrack_expect *this);
 extern void nf_conntrack_q931_expect(struct nf_conn *new,
 				     struct nf_conntrack_expect *this);
-extern int (*set_h245_addr_hook) (struct sk_buff *skb,
+extern int (*set_h245_addr_hook) (struct sk_buff *skb, unsigned int protoff,
 				  unsigned char **data, int dataoff,
 				  H245_TransportAddress *taddr,
 				  union nf_inet_addr *addr,
 				  __be16 port);
-extern int (*set_h225_addr_hook) (struct sk_buff *skb,
+extern int (*set_h225_addr_hook) (struct sk_buff *skb, unsigned int protoff,
 				  unsigned char **data, int dataoff,
 				  TransportAddress *taddr,
 				  union nf_inet_addr *addr,
@@ -49,40 +49,45 @@ extern int (*set_h225_addr_hook) (struct sk_buff *skb,
 extern int (*set_sig_addr_hook) (struct sk_buff *skb,
 				 struct nf_conn *ct,
 				 enum ip_conntrack_info ctinfo,
-				 unsigned char **data,
+				 unsigned int protoff, unsigned char **data,
 				 TransportAddress *taddr, int count);
 extern int (*set_ras_addr_hook) (struct sk_buff *skb,
 				 struct nf_conn *ct,
 				 enum ip_conntrack_info ctinfo,
-				 unsigned char **data,
+				 unsigned int protoff, unsigned char **data,
 				 TransportAddress *taddr, int count);
 extern int (*nat_rtp_rtcp_hook) (struct sk_buff *skb,
 				 struct nf_conn *ct,
 				 enum ip_conntrack_info ctinfo,
-				 unsigned char **data, int dataoff,
+				 unsigned int protoff, unsigned char **data,
+				 int dataoff,
 				 H245_TransportAddress *taddr,
 				 __be16 port, __be16 rtp_port,
 				 struct nf_conntrack_expect *rtp_exp,
 				 struct nf_conntrack_expect *rtcp_exp);
 extern int (*nat_t120_hook) (struct sk_buff *skb, struct nf_conn *ct,
 			     enum ip_conntrack_info ctinfo,
+			     unsigned int protoff,
 			     unsigned char **data, int dataoff,
 			     H245_TransportAddress *taddr, __be16 port,
 			     struct nf_conntrack_expect *exp);
 extern int (*nat_h245_hook) (struct sk_buff *skb, struct nf_conn *ct,
 			     enum ip_conntrack_info ctinfo,
+			     unsigned int protoff,
 			     unsigned char **data, int dataoff,
 			     TransportAddress *taddr, __be16 port,
 			     struct nf_conntrack_expect *exp);
 extern int (*nat_callforwarding_hook) (struct sk_buff *skb,
 				       struct nf_conn *ct,
 				       enum ip_conntrack_info ctinfo,
+				       unsigned int protoff,
 				       unsigned char **data, int dataoff,
 				       TransportAddress *taddr,
 				       __be16 port,
 				       struct nf_conntrack_expect *exp);
 extern int (*nat_q931_hook) (struct sk_buff *skb, struct nf_conn *ct,
 			     enum ip_conntrack_info ctinfo,
+			     unsigned int protoff,
 			     unsigned char **data, TransportAddress *taddr,
 			     int idx, __be16 port,
 			     struct nf_conntrack_expect *exp);
include/linux/netfilter/nf_conntrack_irc.h +1 -0
index 36282bf..4bb9bae 100644
@@ -7,6 +7,7 @@
 
 extern unsigned int (*nf_nat_irc_hook)(struct sk_buff *skb,
 				       enum ip_conntrack_info ctinfo,
+				       unsigned int protoff,
 				       unsigned int matchoff,
 				       unsigned int matchlen,
 				       struct nf_conntrack_expect *exp);
include/linux/netfilter/nf_conntrack_pptp.h +2 -0
index 3bbde0c..2ab2830 100644
@@ -303,12 +303,14 @@ struct nf_conntrack_expect;
 extern int
 (*nf_nat_pptp_hook_outbound)(struct sk_buff *skb,
 			     struct nf_conn *ct, enum ip_conntrack_info ctinfo,
+			     unsigned int protoff,
 			     struct PptpControlHeader *ctlh,
 			     union pptp_ctrl_union *pptpReq);
 
 extern int
 (*nf_nat_pptp_hook_inbound)(struct sk_buff *skb,
 			    struct nf_conn *ct, enum ip_conntrack_info ctinfo,
+			    unsigned int protoff,
 			    struct PptpControlHeader *ctlh,
 			    union pptp_ctrl_union *pptpReq);
 
include/linux/netfilter/nf_conntrack_sip.h +10 -2
index 89f2a62..1afc669 100644
@@ -37,10 +37,12 @@ struct sdp_media_type {
 struct sip_handler {
 	const char	*method;
 	unsigned int	len;
-	int		(*request)(struct sk_buff *skb, unsigned int dataoff,
+	int		(*request)(struct sk_buff *skb, unsigned int protoff,
+				   unsigned int dataoff,
 				   const char **dptr, unsigned int *datalen,
 				   unsigned int cseq);
-	int		(*response)(struct sk_buff *skb, unsigned int dataoff,
+	int		(*response)(struct sk_buff *skb, unsigned int protoff,
+				    unsigned int dataoff,
 				    const char **dptr, unsigned int *datalen,
 				    unsigned int cseq, unsigned int code);
 };
@@ -105,11 +107,13 @@ enum sdp_header_types {
 };
 
 extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
+				       unsigned int protoff,
 				       unsigned int dataoff,
 				       const char **dptr,
 				       unsigned int *datalen);
 extern void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, s16 off);
 extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
+					      unsigned int protoff,
 					      unsigned int dataoff,
 					      const char **dptr,
 					      unsigned int *datalen,
@@ -117,6 +121,7 @@ extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
 					      unsigned int matchoff,
 					      unsigned int matchlen);
 extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
+					    unsigned int protoff,
 					    unsigned int dataoff,
 					    const char **dptr,
 					    unsigned int *datalen,
@@ -125,6 +130,7 @@ extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
 					    enum sdp_header_types term,
 					    const union nf_inet_addr *addr);
 extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
+					    unsigned int protoff,
 					    unsigned int dataoff,
 					    const char **dptr,
 					    unsigned int *datalen,
@@ -132,12 +138,14 @@ extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
 					    unsigned int matchlen,
 					    u_int16_t port);
 extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
+					       unsigned int protoff,
 					       unsigned int dataoff,
 					       const char **dptr,
 					       unsigned int *datalen,
 					       unsigned int sdpoff,
 					       const union nf_inet_addr *addr);
 extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb,
+					     unsigned int protoff,
 					     unsigned int dataoff,
 					     const char **dptr,
 					     unsigned int *datalen,
include/net/netfilter/nf_nat_helper.h +8 -3
index 7d8fb7b..b4d6bfc 100644
@@ -10,6 +10,7 @@ struct sk_buff;
 extern int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
 				      struct nf_conn *ct,
 				      enum ip_conntrack_info ctinfo,
+				      unsigned int protoff,
 				      unsigned int match_offset,
 				      unsigned int match_len,
 				      const char *rep_buffer,
@@ -18,12 +19,13 @@ extern int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
 static inline int nf_nat_mangle_tcp_packet(struct sk_buff *skb,
 					   struct nf_conn *ct,
 					   enum ip_conntrack_info ctinfo,
+					   unsigned int protoff,
 					   unsigned int match_offset,
 					   unsigned int match_len,
 					   const char *rep_buffer,
 					   unsigned int rep_len)
 {
-	return __nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
+	return __nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff,
 					  match_offset, match_len,
 					  rep_buffer, rep_len, true);
 }
@@ -31,6 +33,7 @@ static inline int nf_nat_mangle_tcp_packet(struct sk_buff *skb,
 extern int nf_nat_mangle_udp_packet(struct sk_buff *skb,
 				    struct nf_conn *ct,
 				    enum ip_conntrack_info ctinfo,
+				    unsigned int protoff,
 				    unsigned int match_offset,
 				    unsigned int match_len,
 				    const char *rep_buffer,
@@ -41,10 +44,12 @@ extern void nf_nat_set_seq_adjust(struct nf_conn *ct,
 				  __be32 seq, s16 off);
 extern int nf_nat_seq_adjust(struct sk_buff *skb,
 			     struct nf_conn *ct,
-			     enum ip_conntrack_info ctinfo);
+			     enum ip_conntrack_info ctinfo,
+			     unsigned int protoff);
 extern int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
 				     struct nf_conn *ct,
-				     enum ip_conntrack_info ctinfo);
+				     enum ip_conntrack_info ctinfo,
+				     unsigned int protoff);
 
 /* Setup NAT on this expected conntrack so it follows master, but goes
  * to port ct->master->saved_proto. */
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +4 -2
index e7ff2dc..4ada329 100644
@@ -31,7 +31,8 @@
 
 int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
 			      struct nf_conn *ct,
-			      enum ip_conntrack_info ctinfo);
+			      enum ip_conntrack_info ctinfo,
+			      unsigned int protoff);
 EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook);
 
 static bool ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
@@ -149,7 +150,8 @@ static unsigned int ipv4_confirm(unsigned int hooknum,
 		typeof(nf_nat_seq_adjust_hook) seq_adjust;
 
 		seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
-		if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) {
+		if (!seq_adjust ||
+		    !seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) {
 			NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
 			return NF_DROP;
 		}
net/ipv4/netfilter/nf_nat_amanda.c +2 -1
index 3c04d24..75464b6 100644
@@ -26,6 +26,7 @@ MODULE_ALIAS("ip_nat_amanda");
 
 static unsigned int help(struct sk_buff *skb,
 			 enum ip_conntrack_info ctinfo,
+			 unsigned int protoff,
 			 unsigned int matchoff,
 			 unsigned int matchlen,
 			 struct nf_conntrack_expect *exp)
@@ -61,7 +62,7 @@ static unsigned int help(struct sk_buff *skb,
 
 	sprintf(buffer, "%u", port);
 	ret = nf_nat_mangle_udp_packet(skb, exp->master, ctinfo,
-				       matchoff, matchlen,
+				       protoff, matchoff, matchlen,
 				       buffer, strlen(buffer));
 	if (ret != NF_ACCEPT)
 		nf_ct_unexpect_related(exp);
net/ipv4/netfilter/nf_nat_ftp.c +2 -1
index e462a95..5589f3a 100644
@@ -55,6 +55,7 @@ static int nf_nat_ftp_fmt_cmd(enum nf_ct_ftp_type type,
 static unsigned int nf_nat_ftp(struct sk_buff *skb,
 			       enum ip_conntrack_info ctinfo,
 			       enum nf_ct_ftp_type type,
+			       unsigned int protoff,
 			       unsigned int matchoff,
 			       unsigned int matchlen,
 			       struct nf_conntrack_expect *exp)
@@ -100,7 +101,7 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb,
 
 	pr_debug("calling nf_nat_mangle_tcp_packet\n");
 
-	if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff,
+	if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff, matchoff,
 				      matchlen, buffer, buflen))
 		goto out;
 
net/ipv4/netfilter/nf_nat_h323.c +26 -22

180 lines not on this page · raw message

net/ipv4/netfilter/nf_nat_helper.c +6 -3
index 2e59ad0..2fefec5 100644
@@ -206,6 +206,7 @@ static void nf_nat_csum(struct sk_buff *skb, const struct iphdr *iph, void *data
 int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
 			       struct nf_conn *ct,
 			       enum ip_conntrack_info ctinfo,
+			       unsigned int protoff,
 			       unsigned int match_offset,
 			       unsigned int match_len,
 			       const char *rep_buffer,
@@ -257,6 +258,7 @@ int
 nf_nat_mangle_udp_packet(struct sk_buff *skb,
 			 struct nf_conn *ct,
 			 enum ip_conntrack_info ctinfo,
+			 unsigned int protoff,
 			 unsigned int match_offset,
 			 unsigned int match_len,
 			 const char *rep_buffer,
@@ -387,7 +389,8 @@ nf_nat_sack_adjust(struct sk_buff *skb,
 int
 nf_nat_seq_adjust(struct sk_buff *skb,
 		  struct nf_conn *ct,
-		  enum ip_conntrack_info ctinfo)
+		  enum ip_conntrack_info ctinfo,
+		  unsigned int protoff)
 {
 	struct tcphdr *tcph;
 	int dir;
@@ -401,10 +404,10 @@ nf_nat_seq_adjust(struct sk_buff *skb,
 	this_way = &nat->seq[dir];
 	other_way = &nat->seq[!dir];
 
-	if (!skb_make_writable(skb, ip_hdrlen(skb) + sizeof(*tcph)))
+	if (!skb_make_writable(skb, protoff + sizeof(*tcph)))
 		return 0;
 
-	tcph = (void *)skb->data + ip_hdrlen(skb);
+	tcph = (void *)skb->data + protoff;
 	if (after(ntohl(tcph->seq), this_way->correction_pos))
 		seqoff = this_way->offset_after;
 	else
net/ipv4/netfilter/nf_nat_irc.c +2 -1
index 979ae16..5b0c20a 100644
@@ -29,6 +29,7 @@ MODULE_ALIAS("ip_nat_irc");
 
 static unsigned int help(struct sk_buff *skb,
 			 enum ip_conntrack_info ctinfo,
+			 unsigned int protoff,
 			 unsigned int matchoff,
 			 unsigned int matchlen,
 			 struct nf_conntrack_expect *exp)
@@ -66,7 +67,7 @@ static unsigned int help(struct sk_buff *skb,
 		 buffer, &ip, port);
 
 	ret = nf_nat_mangle_tcp_packet(skb, exp->master, ctinfo,
-				       matchoff, matchlen, buffer,
+				       protoff, matchoff, matchlen, buffer,
 				       strlen(buffer));
 	if (ret != NF_ACCEPT)
 		nf_ct_unexpect_related(exp);
net/ipv4/netfilter/nf_nat_pptp.c +4 -2
index 3881408..31ef890 100644
@@ -113,6 +113,7 @@ static int
 pptp_outbound_pkt(struct sk_buff *skb,
 		  struct nf_conn *ct,
 		  enum ip_conntrack_info ctinfo,
+		  unsigned int protoff,
 		  struct PptpControlHeader *ctlh,
 		  union pptp_ctrl_union *pptpReq)
 
@@ -175,7 +176,7 @@ pptp_outbound_pkt(struct sk_buff *skb,
 		 ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid));
 
 	/* mangle packet */
-	if (nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
+	if (nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff,
 				     cid_off + sizeof(struct pptp_pkt_hdr) +
 				     sizeof(struct PptpControlHeader),
 				     sizeof(new_callid), (char *)&new_callid,
@@ -216,6 +217,7 @@ static int
 pptp_inbound_pkt(struct sk_buff *skb,
 		 struct nf_conn *ct,
 		 enum ip_conntrack_info ctinfo,
+		 unsigned int protoff,
 		 struct PptpControlHeader *ctlh,
 		 union pptp_ctrl_union *pptpReq)
 {
@@ -268,7 +270,7 @@ pptp_inbound_pkt(struct sk_buff *skb,
 	pr_debug("altering peer call id from 0x%04x to 0x%04x\n",
 		 ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid));
 
-	if (nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
+	if (nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff,
 				     pcid_off + sizeof(struct pptp_pkt_hdr) +
 				     sizeof(struct PptpControlHeader),
 				     sizeof(new_pcid), (char *)&new_pcid,
net/ipv4/netfilter/nf_nat_sip.c +54 -42

256 lines not on this page · raw message

net/netfilter/ipvs/ip_vs_ftp.c +1 -0
index b20b29c..390c195 100644
@@ -268,6 +268,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
 			 * packet.
 			 */
 			ret = nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
+						       iph->ihl * 4,
 						       start-data, end-start,
 						       buf, buf_len);
 			if (ret) {
net/netfilter/nf_conntrack_amanda.c +3 -2
index 184c0dc..e0212b5 100644
@@ -40,6 +40,7 @@ MODULE_PARM_DESC(ts_algo, "textsearch algorithm to use (default kmp)");
 
 unsigned int (*nf_nat_amanda_hook)(struct sk_buff *skb,
 				   enum ip_conntrack_info ctinfo,
+				   unsigned int protoff,
 				   unsigned int matchoff,
 				   unsigned int matchlen,
 				   struct nf_conntrack_expect *exp)
@@ -156,8 +157,8 @@ static int amanda_help(struct sk_buff *skb,
 		nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook);
 		if (nf_nat_amanda && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 		    ct->status & IPS_NAT_MASK)
-			ret = nf_nat_amanda(skb, ctinfo, off - dataoff,
-					    len, exp);
+			ret = nf_nat_amanda(skb, ctinfo, protoff,
+					    off - dataoff, len, exp);
 		else if (nf_ct_expect_related(exp) != 0)
 			ret = NF_DROP;
 		nf_ct_expect_put(exp);
net/netfilter/nf_conntrack_ftp.c +2 -1
index 3e1587e..c0f4a5b 100644
@@ -48,6 +48,7 @@ module_param(loose, bool, 0600);
 unsigned int (*nf_nat_ftp_hook)(struct sk_buff *skb,
 				enum ip_conntrack_info ctinfo,
 				enum nf_ct_ftp_type type,
+				unsigned int protoff,
 				unsigned int matchoff,
 				unsigned int matchlen,
 				struct nf_conntrack_expect *exp);
@@ -490,7 +491,7 @@ static int help(struct sk_buff *skb,
 	if (nf_nat_ftp && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 	    ct->status & IPS_NAT_MASK)
 		ret = nf_nat_ftp(skb, ctinfo, search[dir][i].ftptype,
-				 matchoff, matchlen, exp);
+				 protoff, matchoff, matchlen, exp);
 	else {
 		/* Can't expect this?  Best to drop packet now. */
 		if (nf_ct_expect_related(exp) != 0)
net/netfilter/nf_conntrack_h323_main.c +119 -72

721 lines not on this page · raw message

net/netfilter/nf_conntrack_irc.c +2 -1
index e06dc2f..95d097c 100644
@@ -33,6 +33,7 @@ static DEFINE_SPINLOCK(irc_buffer_lock);
 
 unsigned int (*nf_nat_irc_hook)(struct sk_buff *skb,
 				enum ip_conntrack_info ctinfo,
+				unsigned int protoff,
 				unsigned int matchoff,
 				unsigned int matchlen,
 				struct nf_conntrack_expect *exp) __read_mostly;
@@ -206,7 +207,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
 			nf_nat_irc = rcu_dereference(nf_nat_irc_hook);
 			if (nf_nat_irc && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 			    ct->status & IPS_NAT_MASK)
-				ret = nf_nat_irc(skb, ctinfo,
+				ret = nf_nat_irc(skb, ctinfo, protoff,
 						 addr_beg_p - ib_ptr,
 						 addr_end_p - addr_beg_p,
 						 exp);
net/netfilter/nf_conntrack_pptp.c +10 -8
index 6fed9ec..cc7669e 100644
@@ -45,14 +45,14 @@ static DEFINE_SPINLOCK(nf_pptp_lock);
 int
 (*nf_nat_pptp_hook_outbound)(struct sk_buff *skb,
 			     struct nf_conn *ct, enum ip_conntrack_info ctinfo,
-			     struct PptpControlHeader *ctlh,
+			     unsigned int protoff, struct PptpControlHeader *ctlh,
 			     union pptp_ctrl_union *pptpReq) __read_mostly;
 EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_outbound);
 
 int
 (*nf_nat_pptp_hook_inbound)(struct sk_buff *skb,
 			    struct nf_conn *ct, enum ip_conntrack_info ctinfo,
-			    struct PptpControlHeader *ctlh,
+			    unsigned int protoff, struct PptpControlHeader *ctlh,
 			    union pptp_ctrl_union *pptpReq) __read_mostly;
 EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_inbound);
 
@@ -262,7 +262,7 @@ out_unexpect_orig:
 }
 
 static inline int
-pptp_inbound_pkt(struct sk_buff *skb,
+pptp_inbound_pkt(struct sk_buff *skb, unsigned int protoff,
 		 struct PptpControlHeader *ctlh,
 		 union pptp_ctrl_union *pptpReq,
 		 unsigned int reqlen,
@@ -376,7 +376,8 @@ pptp_inbound_pkt(struct sk_buff *skb,
 
 	nf_nat_pptp_inbound = rcu_dereference(nf_nat_pptp_hook_inbound);
 	if (nf_nat_pptp_inbound && ct->status & IPS_NAT_MASK)
-		return nf_nat_pptp_inbound(skb, ct, ctinfo, ctlh, pptpReq);
+		return nf_nat_pptp_inbound(skb, ct, ctinfo,
+					   protoff, ctlh, pptpReq);
 	return NF_ACCEPT;
 
 invalid:
@@ -389,7 +390,7 @@ invalid:
 }
 
 static inline int
-pptp_outbound_pkt(struct sk_buff *skb,
+pptp_outbound_pkt(struct sk_buff *skb, unsigned int protoff,
 		  struct PptpControlHeader *ctlh,
 		  union pptp_ctrl_union *pptpReq,
 		  unsigned int reqlen,
@@ -471,7 +472,8 @@ pptp_outbound_pkt(struct sk_buff *skb,
 
 	nf_nat_pptp_outbound = rcu_dereference(nf_nat_pptp_hook_outbound);
 	if (nf_nat_pptp_outbound && ct->status & IPS_NAT_MASK)
-		return nf_nat_pptp_outbound(skb, ct, ctinfo, ctlh, pptpReq);
+		return nf_nat_pptp_outbound(skb, ct, ctinfo,
+					    protoff, ctlh, pptpReq);
 	return NF_ACCEPT;
 
 invalid:
@@ -570,11 +572,11 @@ conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff,
 	 * established from PNS->PAC.  However, RFC makes no guarantee */
 	if (dir == IP_CT_DIR_ORIGINAL)
 		/* client -> server (PNS -> PAC) */
-		ret = pptp_outbound_pkt(skb, ctlh, pptpReq, reqlen, ct,
+		ret = pptp_outbound_pkt(skb, protoff, ctlh, pptpReq, reqlen, ct,
 					ctinfo);
 	else
 		/* server -> client (PAC -> PNS) */
-		ret = pptp_inbound_pkt(skb, ctlh, pptpReq, reqlen, ct,
+		ret = pptp_inbound_pkt(skb, protoff, ctlh, pptpReq, reqlen, ct,
 				       ctinfo);
 	pr_debug("sstate: %d->%d, cstate: %d->%d\n",
 		 oldsstate, info->sstate, oldcstate, info->cstate);
net/netfilter/nf_conntrack_sip.c +58 -37

288 lines not on this page · raw message

Signature · 1 line
1.7.1
#42 lore raw

PATCH 9/19 netfilter: add protocol independant NAT core

In reply to [email protected]

From: Patrick McHardy <[email protected]>

Convert the IPv4 NAT implementation to a protocol independant core and address family specific modules.

---
 include/linux/netfilter.h                          |   14 +-
 include/linux/netfilter/nf_nat.h                   |    8 +
 include/linux/netfilter/nfnetlink_conntrack.h      |    6 +-
 include/linux/netfilter_ipv4.h                     |    1 -
 include/net/netfilter/nf_conntrack_expect.h        |    2 +-
 include/net/netfilter/nf_nat.h                     |    2 +-
 include/net/netfilter/nf_nat_core.h                |    5 +-
 include/net/netfilter/nf_nat_l3proto.h             |   47 ++
 include/net/netfilter/nf_nat_l4proto.h             |   71 +++
 include/net/netfilter/nf_nat_protocol.h            |   67 ---
 include/net/netfilter/nf_nat_rule.h                |   15 -
 include/net/netns/conntrack.h                      |    4 +
 include/net/netns/ipv4.h                           |    2 -
 net/ipv4/netfilter.c                               |   37 --
 net/ipv4/netfilter/Kconfig                         |   65 +--
 net/ipv4/netfilter/Makefile                        |   11 +-
 net/ipv4/netfilter/ipt_MASQUERADE.c                |   15 +-
 net/ipv4/netfilter/ipt_NETMAP.c                    |   15 +-
 net/ipv4/netfilter/ipt_REDIRECT.c                  |   15 +-
 .../{nf_nat_standalone.c => iptable_nat.c}         |  264 +++++-----
 net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c     |    6 -
 net/ipv4/netfilter/nf_nat_amanda.c                 |    1 -
 net/ipv4/netfilter/nf_nat_ftp.c                    |    1 -
 net/ipv4/netfilter/nf_nat_h323.c                   |   23 +-
 net/ipv4/netfilter/nf_nat_irc.c                    |    1 -
 net/ipv4/netfilter/nf_nat_l3proto_ipv4.c           |  281 +++++++++
 net/ipv4/netfilter/nf_nat_pptp.c                   |   15 +-
 net/ipv4/netfilter/nf_nat_proto_gre.c              |   30 +-
 net/ipv4/netfilter/nf_nat_proto_icmp.c             |   24 +-
 net/ipv4/netfilter/nf_nat_rule.c                   |  214 -------
 net/ipv4/netfilter/nf_nat_sip.c                    |   19 +-
 net/ipv4/netfilter/nf_nat_tftp.c                   |    1 -
 net/netfilter/Kconfig                              |   24 +
 net/netfilter/Makefile                             |   11 +
 net/netfilter/core.c                               |    5 +
 net/netfilter/nf_conntrack_core.c                  |    6 +
 net/netfilter/nf_conntrack_netlink.c               |   35 +-
 net/netfilter/nf_conntrack_proto_tcp.c             |    8 +-
 net/netfilter/nf_conntrack_sip.c                   |    6 +-
 net/{ipv4 => }/netfilter/nf_nat_core.c             |  599 ++++++++++----------
 net/{ipv4 => }/netfilter/nf_nat_helper.c           |  100 ++--
 net/{ipv4 => }/netfilter/nf_nat_proto_common.c     |   54 +-
 net/{ipv4 => }/netfilter/nf_nat_proto_dccp.c       |   56 ++-
 net/{ipv4 => }/netfilter/nf_nat_proto_sctp.c       |   53 +-
 net/{ipv4 => }/netfilter/nf_nat_proto_tcp.c        |   40 +-
 net/{ipv4 => }/netfilter/nf_nat_proto_udp.c        |   42 +-
 net/{ipv4 => }/netfilter/nf_nat_proto_udplite.c    |   58 ++-
 net/{ipv4 => }/netfilter/nf_nat_proto_unknown.c    |   16 +-
 net/netfilter/xt_nat.c                             |  167 ++++++
 49 files changed, 1427 insertions(+), 1135 deletions(-)
 create mode 100644 include/net/netfilter/nf_nat_l3proto.h
 create mode 100644 include/net/netfilter/nf_nat_l4proto.h
 delete mode 100644 include/net/netfilter/nf_nat_protocol.h
 delete mode 100644 include/net/netfilter/nf_nat_rule.h
 rename net/ipv4/netfilter/{nf_nat_standalone.c => iptable_nat.c} (52%)
 create mode 100644 net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
 delete mode 100644 net/ipv4/netfilter/nf_nat_rule.c
 rename net/{ipv4 => }/netfilter/nf_nat_core.c (56%)
 rename net/{ipv4 => }/netfilter/nf_nat_helper.c (83%)
 rename net/{ipv4 => }/netfilter/nf_nat_proto_common.c (62%)
 rename net/{ipv4 => }/netfilter/nf_nat_proto_dccp.c (61%)
 rename net/{ipv4 => }/netfilter/nf_nat_proto_sctp.c (61%)
 rename net/{ipv4 => }/netfilter/nf_nat_proto_tcp.c (65%)
 rename net/{ipv4 => }/netfilter/nf_nat_proto_udp.c (60%)
 rename net/{ipv4 => }/netfilter/nf_nat_proto_udplite.c (58%)
 rename net/{ipv4 => }/netfilter/nf_nat_proto_unknown.c (76%)
 create mode 100644 net/netfilter/xt_nat.c
include/linux/netfilter.h +6 -8
index c613cf0..1dcf2a3 100644
@@ -342,7 +342,7 @@ extern int nf_register_afinfo(const struct nf_afinfo *afinfo);
 extern void nf_unregister_afinfo(const struct nf_afinfo *afinfo);
 
 #include <net/flow.h>
-extern void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
+extern void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *);
 
 static inline void
 nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
@@ -350,13 +350,11 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
 #ifdef CONFIG_NF_NAT_NEEDED
 	void (*decodefn)(struct sk_buff *, struct flowi *);
 
-	if (family == AF_INET) {
-		rcu_read_lock();
-		decodefn = rcu_dereference(ip_nat_decode_session);
-		if (decodefn)
-			decodefn(skb, fl);
-		rcu_read_unlock();
-	}
+	rcu_read_lock();
+	decodefn = rcu_dereference(nf_nat_decode_session_hook);
+	if (decodefn)
+		decodefn(skb, fl);
+	rcu_read_unlock();
 #endif
 }
 
include/linux/netfilter/nf_nat.h +8 -0
index 8df2d13..bf0cc37 100644
@@ -22,4 +22,12 @@ struct nf_nat_ipv4_multi_range_compat {
 	struct nf_nat_ipv4_range	range[1];
 };
 
+struct nf_nat_range {
+	unsigned int			flags;
+	union nf_inet_addr		min_addr;
+	union nf_inet_addr		max_addr;
+	union nf_conntrack_man_proto	min_proto;
+	union nf_conntrack_man_proto	max_proto;
+};
+
 #endif /* _NETFILTER_NF_NAT_H */
include/linux/netfilter/nfnetlink_conntrack.h +4 -2
index f649f74..68920ea 100644
@@ -142,8 +142,10 @@ enum ctattr_tstamp {
 
 enum ctattr_nat {
 	CTA_NAT_UNSPEC,
-	CTA_NAT_MINIP,
-	CTA_NAT_MAXIP,
+	CTA_NAT_V4_MINIP,
+#define CTA_NAT_MINIP CTA_NAT_V4_MINIP
+	CTA_NAT_V4_MAXIP,
+#define CTA_NAT_MAXIP CTA_NAT_V4_MAXIP
 	CTA_NAT_PROTO,
 	__CTA_NAT_MAX
 };
include/linux/netfilter_ipv4.h +0 -1
index e2b1280..b962dfc 100644
@@ -79,7 +79,6 @@ enum nf_ip_hook_priorities {
 
 #ifdef __KERNEL__
 extern int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type);
-extern int ip_xfrm_me_harder(struct sk_buff *skb);
 extern __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
 				   unsigned int dataoff, u_int8_t protocol);
 #endif /*__KERNEL__*/
include/net/netfilter/nf_conntrack_expect.h +1 -1
index 983f002..cc13f37 100644
@@ -43,7 +43,7 @@ struct nf_conntrack_expect {
 	unsigned int class;
 
 #ifdef CONFIG_NF_NAT_NEEDED
-	__be32 saved_ip;
+	union nf_inet_addr saved_addr;
 	/* This is the original per-proto part, used to map the
 	 * expected connection the way the recipient expects. */
 	union nf_conntrack_man_proto saved_proto;
include/net/netfilter/nf_nat.h +1 -1
index b4de990..1752f13 100644
@@ -50,7 +50,7 @@ struct nf_conn_nat {
 
 /* Set up the info structure to map into this range. */
 extern unsigned int nf_nat_setup_info(struct nf_conn *ct,
-				      const struct nf_nat_ipv4_range *range,
+				      const struct nf_nat_range *range,
 				      enum nf_nat_manip_type maniptype);
 
 /* Is this tuple already taken? (not by us)*/
include/net/netfilter/nf_nat_core.h +1 -4
index b13d8d1..972e1e4 100644
@@ -12,10 +12,7 @@ extern unsigned int nf_nat_packet(struct nf_conn *ct,
 				  unsigned int hooknum,
 				  struct sk_buff *skb);
 
-extern int nf_nat_icmp_reply_translation(struct nf_conn *ct,
-					 enum ip_conntrack_info ctinfo,
-					 unsigned int hooknum,
-					 struct sk_buff *skb);
+extern int nf_xfrm_me_harder(struct sk_buff *skb, unsigned int family);
 
 static inline int nf_nat_initialized(struct nf_conn *ct,
 				     enum nf_nat_manip_type manip)
include/net/netfilter/nf_nat_l3proto.h new file +47 -0

47 lines not on this page · raw message

include/net/netfilter/nf_nat_l4proto.h new file +71 -0

71 lines not on this page · raw message

include/net/netfilter/nf_nat_protocol.h deleted +0 -67

67 lines not on this page · raw message

include/net/netfilter/nf_nat_rule.h deleted +0 -15
deleted file mode 100644
index 2890bdc..0000000
@@ -1,15 +0,0 @@
-#ifndef _NF_NAT_RULE_H
-#define _NF_NAT_RULE_H
-#include <net/netfilter/nf_conntrack.h>
-#include <net/netfilter/nf_nat.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-
-extern int nf_nat_rule_init(void) __init;
-extern void nf_nat_rule_cleanup(void);
-extern int nf_nat_rule_find(struct sk_buff *skb,
-			    unsigned int hooknum,
-			    const struct net_device *in,
-			    const struct net_device *out,
-			    struct nf_conn *ct);
-
-#endif /* _NF_NAT_RULE_H */
include/net/netns/conntrack.h +4 -0
index 3aecdc7..a1d83cc 100644
@@ -83,6 +83,10 @@ struct netns_ct {
 	int			sysctl_auto_assign_helper;
 	bool			auto_assign_helper_warned;
 	struct nf_ip_net	nf_ct_proto;
+#ifdef CONFIG_NF_NAT_NEEDED
+	struct hlist_head	*nat_bysource;
+	unsigned int		nat_htable_size;
+#endif
 #ifdef CONFIG_SYSCTL
 	struct ctl_table_header	*sysctl_header;
 	struct ctl_table_header	*acct_sysctl_header;
include/net/netns/ipv4.h +0 -2
index 1474dd6..ace280d 100644
@@ -51,8 +51,6 @@ struct netns_ipv4 {
 	struct xt_table		*iptable_security;
 #endif
 	struct xt_table		*nat_table;
-	struct hlist_head	*nat_bysource;
-	unsigned int		nat_htable_size;
 #endif
 
 	int sysctl_icmp_echo_ignore_all;
net/ipv4/netfilter.c +0 -37
index ed1b367..f1643c0 100644
@@ -72,43 +72,6 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
 }
 EXPORT_SYMBOL(ip_route_me_harder);
 
-#ifdef CONFIG_XFRM
-int ip_xfrm_me_harder(struct sk_buff *skb)
-{
-	struct flowi fl;
-	unsigned int hh_len;
-	struct dst_entry *dst;
-
-	if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
-		return 0;
-	if (xfrm_decode_session(skb, &fl, AF_INET) < 0)
-		return -1;
-
-	dst = skb_dst(skb);
-	if (dst->xfrm)
-		dst = ((struct xfrm_dst *)dst)->route;
-	dst_hold(dst);
-
-	dst = xfrm_lookup(dev_net(dst->dev), dst, &fl, skb->sk, 0);
-	if (IS_ERR(dst))
-		return -1;
-
-	skb_dst_drop(skb);
-	skb_dst_set(skb, dst);
-
-	/* Change in oif may mean change in hh_len. */
-	hh_len = skb_dst(skb)->dev->hard_header_len;
-	if (skb_headroom(skb) < hh_len &&
-	    pskb_expand_head(skb, hh_len - skb_headroom(skb), 0, GFP_ATOMIC))
-		return -1;
-	return 0;
-}
-EXPORT_SYMBOL(ip_xfrm_me_harder);
-#endif
-
-void (*ip_nat_decode_session)(struct sk_buff *, struct flowi *);
-EXPORT_SYMBOL(ip_nat_decode_session);
-
 /*
  * Extra routing may needed on local out, as the QUEUE target never
  * returns control to the table.
net/ipv4/netfilter/Kconfig +23 -42

130 lines not on this page · raw message

net/ipv4/netfilter/Makefile +3 -8
index c20674d..0ea3acc 100644
@@ -10,13 +10,11 @@ nf_conntrack_ipv4-objs	+= nf_conntrack_l3proto_ipv4_compat.o
 endif
 endif
 
-nf_nat-y		:= nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_common.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o
-iptable_nat-y	:= nf_nat_rule.o nf_nat_standalone.o
-
 # connection tracking
 obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
 
-obj-$(CONFIG_NF_NAT) += nf_nat.o
+nf_nat_ipv4-y		:= nf_nat_l3proto_ipv4.o nf_nat_proto_icmp.o
+obj-$(CONFIG_NF_NAT_IPV4) += nf_nat_ipv4.o
 
 # defrag
 obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o
@@ -32,10 +30,7 @@ obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
 obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o
 
 # NAT protocols (nf_nat)
-obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o
 obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
-obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o
-obj-$(CONFIG_NF_NAT_PROTO_SCTP) += nf_nat_proto_sctp.o
 
 # generic IP tables 
 obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
@@ -43,7 +38,7 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
 # the three instances of ip_tables
 obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
 obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
-obj-$(CONFIG_NF_NAT) += iptable_nat.o
+obj-$(CONFIG_NF_NAT_IPV4) += iptable_nat.o
 obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
 obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
 
net/ipv4/netfilter/ipt_MASQUERADE.c +9 -6
index cbb6a1a..1c3aa28 100644
@@ -19,9 +19,9 @@
 #include <net/ip.h>
 #include <net/checksum.h>
 #include <net/route.h>
-#include <net/netfilter/nf_nat_rule.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter/x_tables.h>
+#include <net/netfilter/nf_nat.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <[email protected]>");
@@ -49,7 +49,7 @@ masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
 	struct nf_conn *ct;
 	struct nf_conn_nat *nat;
 	enum ip_conntrack_info ctinfo;
-	struct nf_nat_ipv4_range newrange;
+	struct nf_nat_range newrange;
 	const struct nf_nat_ipv4_multi_range_compat *mr;
 	const struct rtable *rt;
 	__be32 newsrc, nh;
@@ -80,10 +80,13 @@ masquerade_tg(struct sk_buff *skb, const struct xt_action_param *par)
 	nat->masq_index = par->out->ifindex;
 
 	/* Transfer from original range. */
-	newrange = ((struct nf_nat_ipv4_range)
-		{ mr->range[0].flags | NF_NAT_RANGE_MAP_IPS,
-		  newsrc, newsrc,
-		  mr->range[0].min, mr->range[0].max });
+	memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
+	memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
+	newrange.flags       = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
+	newrange.min_addr.ip = newsrc;
+	newrange.max_addr.ip = newsrc;
+	newrange.min_proto   = mr->range[0].min;
+	newrange.max_proto   = mr->range[0].max;
 
 	/* Hand modified range to generic setup. */
 	return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
net/ipv4/netfilter/ipt_NETMAP.c +9 -6
index b5bfbba..85028dc 100644
@@ -16,7 +16,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter/x_tables.h>
-#include <net/netfilter/nf_nat_rule.h>
+#include <net/netfilter/nf_nat.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Svenning Soerensen <[email protected]>");
@@ -44,7 +44,7 @@ netmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
 	enum ip_conntrack_info ctinfo;
 	__be32 new_ip, netmask;
 	const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
-	struct nf_nat_ipv4_range newrange;
+	struct nf_nat_range newrange;
 
 	NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
 		     par->hooknum == NF_INET_POST_ROUTING ||
@@ -61,10 +61,13 @@ netmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
 		new_ip = ip_hdr(skb)->saddr & ~netmask;
 	new_ip |= mr->range[0].min_ip & netmask;
 
-	newrange = ((struct nf_nat_ipv4_range)
-		{ mr->range[0].flags | NF_NAT_RANGE_MAP_IPS,
-		  new_ip, new_ip,
-		  mr->range[0].min, mr->range[0].max });
+	memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
+	memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
+	newrange.flags	     = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
+	newrange.min_addr.ip = new_ip;
+	newrange.max_addr.ip = new_ip;
+	newrange.min_proto   = mr->range[0].min;
+	newrange.max_proto   = mr->range[0].max;
 
 	/* Hand modified range to generic setup. */
 	return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
net/ipv4/netfilter/ipt_REDIRECT.c +9 -6
index 7c0103a..11407d7 100644
@@ -19,7 +19,7 @@
 #include <net/checksum.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter/x_tables.h>
-#include <net/netfilter/nf_nat_rule.h>
+#include <net/netfilter/nf_nat.h>
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <[email protected]>");
@@ -48,7 +48,7 @@ redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
 	enum ip_conntrack_info ctinfo;
 	__be32 newdst;
 	const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
-	struct nf_nat_ipv4_range newrange;
+	struct nf_nat_range newrange;
 
 	NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
 		     par->hooknum == NF_INET_LOCAL_OUT);
@@ -76,10 +76,13 @@ redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
 	}
 
 	/* Transfer from original range. */
-	newrange = ((struct nf_nat_ipv4_range)
-		{ mr->range[0].flags | NF_NAT_RANGE_MAP_IPS,
-		  newdst, newdst,
-		  mr->range[0].min, mr->range[0].max });
+	memset(&newrange.min_addr, 0, sizeof(newrange.min_addr));
+	memset(&newrange.max_addr, 0, sizeof(newrange.max_addr));
+	newrange.flags	     = mr->range[0].flags | NF_NAT_RANGE_MAP_IPS;
+	newrange.min_addr.ip = newdst;
+	newrange.max_addr.ip = newdst;
+	newrange.min_proto   = mr->range[0].min;
+	newrange.max_proto   = mr->range[0].max;
 
 	/* Hand modified range to generic setup. */
 	return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
net/ipv4/netfilter/iptable_nat.c renamed from net/ipv4/netfilter/nf_nat_standalone.c +129 -135

400 lines not on this page · raw message

net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +0 -6
index 4ada329..fcdd0c2 100644
@@ -29,12 +29,6 @@
 #include <net/netfilter/ipv4/nf_defrag_ipv4.h>
 #include <net/netfilter/nf_log.h>
 
-int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
-			      struct nf_conn *ct,
-			      enum ip_conntrack_info ctinfo,
-			      unsigned int protoff);
-EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook);
-
 static bool ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
 			      struct nf_conntrack_tuple *tuple)
 {
net/ipv4/netfilter/nf_nat_amanda.c +0 -1
index 75464b6..42d3378 100644
@@ -16,7 +16,6 @@
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <net/netfilter/nf_nat_helper.h>
-#include <net/netfilter/nf_nat_rule.h>
 #include <linux/netfilter/nf_conntrack_amanda.h>
 
 MODULE_AUTHOR("Brian J. Murrell <[email protected]>");
net/ipv4/netfilter/nf_nat_ftp.c +0 -1
index 5589f3a..dd5e387 100644
@@ -15,7 +15,6 @@
 #include <linux/netfilter_ipv4.h>
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_helper.h>
-#include <net/netfilter/nf_nat_rule.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <linux/netfilter/nf_conntrack_ftp.h>
net/ipv4/netfilter/nf_nat_h323.c +12 -11
index d2c228d..9c3db10 100644
@@ -15,7 +15,6 @@
 
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_helper.h>
-#include <net/netfilter/nf_nat_rule.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <linux/netfilter/nf_conntrack_h323.h>
@@ -392,7 +391,7 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
 static void ip_nat_q931_expect(struct nf_conn *new,
 			       struct nf_conntrack_expect *this)
 {
-	struct nf_nat_ipv4_range range;
+	struct nf_nat_range range;
 
 	if (this->tuple.src.u3.ip != 0) {	/* Only accept calls from GK */
 		nf_nat_follow_master(new, this);
@@ -404,14 +403,15 @@ static void ip_nat_q931_expect(struct nf_conn *new,
 
 	/* Change src to where master sends to */
 	range.flags = NF_NAT_RANGE_MAP_IPS;
-	range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip;
+	range.min_addr = range.max_addr =
+	    new->tuplehash[!this->dir].tuple.src.u3;
 	nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC);
 
 	/* For DST manip, map port here to where it's expected. */
 	range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
-	range.min = range.max = this->saved_proto;
-	range.min_ip = range.max_ip =
-	    new->master->tuplehash[!this->dir].tuple.src.u3.ip;
+	range.min_proto = range.max_proto = this->saved_proto;
+	range.min_addr = range.max_addr =
+	    new->master->tuplehash[!this->dir].tuple.src.u3;
 	nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST);
 }
 
@@ -490,20 +490,21 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
 static void ip_nat_callforwarding_expect(struct nf_conn *new,
 					 struct nf_conntrack_expect *this)
 {
-	struct nf_nat_ipv4_range range;
+	struct nf_nat_range range;
 
 	/* This must be a fresh one. */
 	BUG_ON(new->status & IPS_NAT_DONE_MASK);
 
 	/* Change src to where master sends to */
 	range.flags = NF_NAT_RANGE_MAP_IPS;
-	range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip;
+	range.min_addr = range.max_addr =
+	    new->tuplehash[!this->dir].tuple.src.u3;
 	nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC);
 
 	/* For DST manip, map port here to where it's expected. */
 	range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
-	range.min = range.max = this->saved_proto;
-	range.min_ip = range.max_ip = this->saved_ip;
+	range.min_proto = range.max_proto = this->saved_proto;
+	range.min_addr = range.max_addr = this->saved_addr;
 	nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST);
 }
 
@@ -519,7 +520,7 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
 	u_int16_t nated_port;
 
 	/* Set expectations for NAT */
-	exp->saved_ip = exp->tuple.dst.u3.ip;
+	exp->saved_addr = exp->tuple.dst.u3;
 	exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
 	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
 	exp->expectfn = ip_nat_callforwarding_expect;
net/ipv4/netfilter/nf_nat_irc.c +0 -1
index 5b0c20a..1ce37f8 100644
@@ -17,7 +17,6 @@
 
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_helper.h>
-#include <net/netfilter/nf_nat_rule.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <linux/netfilter/nf_conntrack_irc.h>
net/ipv4/netfilter/nf_nat_l3proto_ipv4.c new file +281 -0

281 lines not on this page · raw message

net/ipv4/netfilter/nf_nat_pptp.c +7 -8
index 31ef890..a06d7d7 100644
@@ -22,7 +22,6 @@
 
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_helper.h>
-#include <net/netfilter/nf_nat_rule.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <net/netfilter/nf_conntrack_zones.h>
@@ -47,7 +46,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
 	struct nf_conntrack_tuple t;
 	const struct nf_ct_pptp_master *ct_pptp_info;
 	const struct nf_nat_pptp *nat_pptp_info;
-	struct nf_nat_ipv4_range range;
+	struct nf_nat_range range;
 
 	ct_pptp_info = nfct_help_data(master);
 	nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info;
@@ -89,21 +88,21 @@ static void pptp_nat_expected(struct nf_conn *ct,
 
 	/* Change src to where master sends to */
 	range.flags = NF_NAT_RANGE_MAP_IPS;
-	range.min_ip = range.max_ip
-		= ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
+	range.min_addr = range.max_addr
+		= ct->master->tuplehash[!exp->dir].tuple.dst.u3;
 	if (exp->dir == IP_CT_DIR_ORIGINAL) {
 		range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-		range.min = range.max = exp->saved_proto;
+		range.min_proto = range.max_proto = exp->saved_proto;
 	}
 	nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
 
 	/* For DST manip, map port here to where it's expected. */
 	range.flags = NF_NAT_RANGE_MAP_IPS;
-	range.min_ip = range.max_ip
-		= ct->master->tuplehash[!exp->dir].tuple.src.u3.ip;
+	range.min_addr = range.max_addr
+		= ct->master->tuplehash[!exp->dir].tuple.src.u3;
 	if (exp->dir == IP_CT_DIR_REPLY) {
 		range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-		range.min = range.max = exp->saved_proto;
+		range.min_proto = range.max_proto = exp->saved_proto;
 	}
 	nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
 }
net/ipv4/netfilter/nf_nat_proto_gre.c +15 -15
index 46ba0b9..ea44f02 100644
@@ -28,8 +28,7 @@
 #include <linux/ip.h>
 
 #include <net/netfilter/nf_nat.h>
-#include <net/netfilter/nf_nat_rule.h>
-#include <net/netfilter/nf_nat_protocol.h>
+#include <net/netfilter/nf_nat_l4proto.h>
 #include <linux/netfilter/nf_conntrack_proto_gre.h>
 
 MODULE_LICENSE("GPL");
@@ -38,8 +37,9 @@ MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
 
 /* generate unique tuple ... */
 static void
-gre_unique_tuple(struct nf_conntrack_tuple *tuple,
-		 const struct nf_nat_ipv4_range *range,
+gre_unique_tuple(const struct nf_nat_l3proto *l3proto,
+		 struct nf_conntrack_tuple *tuple,
+		 const struct nf_nat_range *range,
 		 enum nf_nat_manip_type maniptype,
 		 const struct nf_conn *ct)
 {
@@ -62,8 +62,8 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
 		min = 1;
 		range_size = 0xffff;
 	} else {
-		min = ntohs(range->min.gre.key);
-		range_size = ntohs(range->max.gre.key) - min + 1;
+		min = ntohs(range->min_proto.gre.key);
+		range_size = ntohs(range->max_proto.gre.key) - min + 1;
 	}
 
 	pr_debug("min = %u, range_size = %u\n", min, range_size);
@@ -80,14 +80,14 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
 
 /* manipulate a GRE packet according to maniptype */
 static bool
-gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff,
+gre_manip_pkt(struct sk_buff *skb,
+	      const struct nf_nat_l3proto *l3proto,
+	      unsigned int iphdroff, unsigned int hdroff,
 	      const struct nf_conntrack_tuple *tuple,
 	      enum nf_nat_manip_type maniptype)
 {
 	const struct gre_hdr *greh;
 	struct gre_hdr_pptp *pgreh;
-	const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
-	unsigned int hdroff = iphdroff + iph->ihl * 4;
 
 	/* pgreh includes two optional 32bit fields which are not required
 	 * to be there.  That's where the magic '8' comes from */
@@ -117,24 +117,24 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff,
 	return true;
 }
 
-static const struct nf_nat_protocol gre = {
-	.protonum		= IPPROTO_GRE,
+static const struct nf_nat_l4proto gre = {
+	.l4proto		= IPPROTO_GRE,
 	.manip_pkt		= gre_manip_pkt,
-	.in_range		= nf_nat_proto_in_range,
+	.in_range		= nf_nat_l4proto_in_range,
 	.unique_tuple		= gre_unique_tuple,
 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
-	.nlattr_to_range	= nf_nat_proto_nlattr_to_range,
+	.nlattr_to_range	= nf_nat_l4proto_nlattr_to_range,
 #endif
 };
 
 static int __init nf_nat_proto_gre_init(void)
 {
-	return nf_nat_protocol_register(&gre);
+	return nf_nat_l4proto_register(NFPROTO_IPV4, &gre);
 }
 
 static void __exit nf_nat_proto_gre_fini(void)
 {
-	nf_nat_protocol_unregister(&gre);
+	nf_nat_l4proto_unregister(NFPROTO_IPV4, &gre);
 }
 
 module_init(nf_nat_proto_gre_init);
net/ipv4/netfilter/nf_nat_proto_icmp.c +12 -12
index b351728..eb30347 100644
@@ -15,8 +15,7 @@
 #include <linux/netfilter.h>
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_core.h>
-#include <net/netfilter/nf_nat_rule.h>
-#include <net/netfilter/nf_nat_protocol.h>
+#include <net/netfilter/nf_nat_l4proto.h>
 
 static bool
 icmp_in_range(const struct nf_conntrack_tuple *tuple,
@@ -29,8 +28,9 @@ icmp_in_range(const struct nf_conntrack_tuple *tuple,
 }
 
 static void
-icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
-		  const struct nf_nat_ipv4_range *range,
+icmp_unique_tuple(const struct nf_nat_l3proto *l3proto,
+		  struct nf_conntrack_tuple *tuple,
+		  const struct nf_nat_range *range,
 		  enum nf_nat_manip_type maniptype,
 		  const struct nf_conn *ct)
 {
@@ -38,13 +38,14 @@ icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
 	unsigned int range_size;
 	unsigned int i;
 
-	range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1;
+	range_size = ntohs(range->max_proto.icmp.id) -
+		     ntohs(range->min_proto.icmp.id) + 1;
 	/* If no range specified... */
 	if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED))
 		range_size = 0xFFFF;
 
 	for (i = 0; ; ++id) {
-		tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) +
+		tuple->src.u.icmp.id = htons(ntohs(range->min_proto.icmp.id) +
 					     (id % range_size));
 		if (++i == range_size || !nf_nat_used_tuple(tuple, ct))
 			return;
@@ -54,13 +55,12 @@ icmp_unique_tuple(struct nf_conntrack_tuple *tuple,
 
 static bool
 icmp_manip_pkt(struct sk_buff *skb,
-	       unsigned int iphdroff,
+	       const struct nf_nat_l3proto *l3proto,
+	       unsigned int iphdroff, unsigned int hdroff,
 	       const struct nf_conntrack_tuple *tuple,
 	       enum nf_nat_manip_type maniptype)
 {
-	const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
 	struct icmphdr *hdr;
-	unsigned int hdroff = iphdroff + iph->ihl*4;
 
 	if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
 		return false;
@@ -72,12 +72,12 @@ icmp_manip_pkt(struct sk_buff *skb,
 	return true;
 }
 
-const struct nf_nat_protocol nf_nat_protocol_icmp = {
-	.protonum		= IPPROTO_ICMP,
+const struct nf_nat_l4proto nf_nat_l4proto_icmp = {
+	.l4proto		= IPPROTO_ICMP,
 	.manip_pkt		= icmp_manip_pkt,
 	.in_range		= icmp_in_range,
 	.unique_tuple		= icmp_unique_tuple,
 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
-	.nlattr_to_range	= nf_nat_proto_nlattr_to_range,
+	.nlattr_to_range	= nf_nat_l4proto_nlattr_to_range,
 #endif
 };
net/ipv4/netfilter/nf_nat_rule.c deleted +0 -214

214 lines not on this page · raw message

net/ipv4/netfilter/nf_nat_sip.c +9 -10
index df626af..47a4718 100644
@@ -19,7 +19,6 @@
 
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_helper.h>
-#include <net/netfilter/nf_nat_rule.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <linux/netfilter/nf_conntrack_sip.h>
@@ -255,15 +254,15 @@ static void ip_nat_sip_seq_adjust(struct sk_buff *skb, s16 off)
 static void ip_nat_sip_expected(struct nf_conn *ct,
 				struct nf_conntrack_expect *exp)
 {
-	struct nf_nat_ipv4_range range;
+	struct nf_nat_range range;
 
 	/* This must be a fresh one. */
 	BUG_ON(ct->status & IPS_NAT_DONE_MASK);
 
 	/* For DST manip, map port here to where it's expected. */
 	range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
-	range.min = range.max = exp->saved_proto;
-	range.min_ip = range.max_ip = exp->saved_ip;
+	range.min_proto = range.max_proto = exp->saved_proto;
+	range.min_addr = range.max_addr = exp->saved_addr;
 	nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
 
 	/* Change src to where master sends to, but only if the connection
@@ -271,8 +270,8 @@ static void ip_nat_sip_expected(struct nf_conn *ct,
 	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip ==
 	    ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
 		range.flags = NF_NAT_RANGE_MAP_IPS;
-		range.min_ip = range.max_ip
-			= ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
+		range.min_addr = range.max_addr
+			= ct->master->tuplehash[!exp->dir].tuple.dst.u3;
 		nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
 	}
 }
@@ -307,7 +306,7 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
 	else
 		port = ntohs(exp->tuple.dst.u.udp.port);
 
-	exp->saved_ip = exp->tuple.dst.u3.ip;
+	exp->saved_addr = exp->tuple.dst.u3;
 	exp->tuple.dst.u3.ip = newip;
 	exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
 	exp->dir = !dir;
@@ -329,7 +328,7 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
 	if (port == 0)
 		return NF_DROP;
 
-	if (exp->tuple.dst.u3.ip != exp->saved_ip ||
+	if (exp->tuple.dst.u3.ip != exp->saved_addr.ip ||
 	    exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
 		buflen = sprintf(buffer, "%pI4:%u", &newip, port);
 		if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
@@ -485,13 +484,13 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
 	else
 		rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
 
-	rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
+	rtp_exp->saved_addr = rtp_exp->tuple.dst.u3;
 	rtp_exp->tuple.dst.u3.ip = rtp_addr->ip;
 	rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
 	rtp_exp->dir = !dir;
 	rtp_exp->expectfn = ip_nat_sip_expected;
 
-	rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
+	rtcp_exp->saved_addr = rtcp_exp->tuple.dst.u3;
 	rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip;
 	rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
 	rtcp_exp->dir = !dir;
net/ipv4/netfilter/nf_nat_tftp.c +0 -1
index 9dbb8d2..ccabbda 100644
@@ -11,7 +11,6 @@
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <net/netfilter/nf_nat_helper.h>
-#include <net/netfilter/nf_nat_rule.h>
 #include <linux/netfilter/nf_conntrack_tftp.h>
 
 MODULE_AUTHOR("Magnus Boden <[email protected]>");
net/netfilter/Kconfig +24 -0
index c19b214..91addda 100644
@@ -356,6 +356,30 @@ config NETFILTER_NETLINK_QUEUE_CT
 	  If this option is enabled, NFQUEUE can include Connection Tracking
 	  information together with the packet is the enqueued via NFNETLINK.
 
+config NF_NAT
+	tristate
+
+config NF_NAT_NEEDED
+	bool
+	depends on NF_NAT
+	default y
+
+config NF_NAT_PROTO_DCCP
+	tristate
+	depends on NF_NAT && NF_CT_PROTO_DCCP
+	default NF_NAT && NF_CT_PROTO_DCCP
+
+config NF_NAT_PROTO_UDPLITE
+	tristate
+	depends on NF_NAT && NF_CT_PROTO_UDPLITE
+	default NF_NAT && NF_CT_PROTO_UDPLITE
+
+config NF_NAT_PROTO_SCTP
+	tristate
+	default NF_NAT && NF_CT_PROTO_SCTP
+	depends on NF_NAT && NF_CT_PROTO_SCTP
+	select LIBCRC32C
+
 endif # NF_CONNTRACK
 
 # transparent proxy support
net/netfilter/Makefile +11 -0
index 1c5160f..09c9451 100644
@@ -43,6 +43,17 @@ obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o
 obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o
 obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o
 
+nf_nat-y	:= nf_nat_core.o nf_nat_proto_unknown.o nf_nat_proto_common.o \
+		   nf_nat_proto_udp.o nf_nat_proto_tcp.o nf_nat_helper.o
+
+obj-$(CONFIG_NF_NAT) += nf_nat.o
+obj-$(CONFIG_NF_NAT) += xt_nat.o
+
+# NAT protocols (nf_nat)
+obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o
+obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o
+obj-$(CONFIG_NF_NAT_PROTO_SCTP) += nf_nat_proto_sctp.o
+
 # transparent proxy support
 obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o
 
net/netfilter/core.c +5 -0
index 0bc6b60..4ff0a60 100644
@@ -273,6 +273,11 @@ EXPORT_SYMBOL_GPL(nfq_ct_nat_hook);
 
 #endif /* CONFIG_NF_CONNTRACK */
 
+#ifdef CONFIG_NF_NAT_NEEDED
+void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *);
+EXPORT_SYMBOL(nf_nat_decode_session_hook);
+#endif
+
 #ifdef CONFIG_PROC_FS
 struct proc_dir_entry *proc_net_netfilter;
 EXPORT_SYMBOL(proc_net_netfilter);
net/netfilter/nf_conntrack_core.c +6 -0
index cf48755..f83e79d 100644
@@ -55,6 +55,12 @@ int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
 				      const struct nlattr *attr) __read_mostly;
 EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook);
 
+int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb,
+			      struct nf_conn *ct,
+			      enum ip_conntrack_info ctinfo,
+			      unsigned int protoff);
+EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook);
+
 DEFINE_SPINLOCK(nf_conntrack_lock);
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
 
net/netfilter/nf_conntrack_netlink.c +29 -6
index 14f67a2..7545506 100644
@@ -45,7 +45,7 @@
 #include <net/netfilter/nf_conntrack_timestamp.h>
 #ifdef CONFIG_NF_NAT_NEEDED
 #include <net/netfilter/nf_nat_core.h>
-#include <net/netfilter/nf_nat_protocol.h>
+#include <net/netfilter/nf_nat_l4proto.h>
 #include <net/netfilter/nf_nat_helper.h>
 #endif
 
@@ -1096,13 +1096,14 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
 			  const struct nlattr *attr)
 {
 	typeof(nfnetlink_parse_nat_setup_hook) parse_nat_setup;
+	int err;
 
 	parse_nat_setup = rcu_dereference(nfnetlink_parse_nat_setup_hook);
 	if (!parse_nat_setup) {
 #ifdef CONFIG_MODULES
 		rcu_read_unlock();
 		nfnl_unlock();
-		if (request_module("nf-nat-ipv4") < 0) {
+		if (request_module("nf-nat") < 0) {
 			nfnl_lock();
 			rcu_read_lock();
 			return -EOPNOTSUPP;
@@ -1115,7 +1116,26 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
 		return -EOPNOTSUPP;
 	}
 
-	return parse_nat_setup(ct, manip, attr);
+	err = parse_nat_setup(ct, manip, attr);
+	if (err == -EAGAIN) {
+#ifdef CONFIG_MODULES
+		rcu_read_unlock();
+		spin_unlock_bh(&nf_conntrack_lock);
+		nfnl_unlock();
+		if (request_module("nf-nat-%u", nf_ct_l3num(ct)) < 0) {
+			nfnl_lock();
+			spin_lock_bh(&nf_conntrack_lock);
+			rcu_read_lock();
+			return -EOPNOTSUPP;
+		}
+		nfnl_lock();
+		spin_lock_bh(&nf_conntrack_lock);
+		rcu_read_lock();
+#else
+		err = -EOPNOTSUPP;
+#endif
+	}
+	return err;
 }
 #endif
 
@@ -1974,6 +1994,8 @@ nla_put_failure:
 	return -1;
 }
 
+static const union nf_inet_addr any_addr;
+
 static int
 ctnetlink_exp_dump_expect(struct sk_buff *skb,
 			  const struct nf_conntrack_expect *exp)
@@ -2000,7 +2022,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
 		goto nla_put_failure;
 
 #ifdef CONFIG_NF_NAT_NEEDED
-	if (exp->saved_ip || exp->saved_proto.all) {
+	if (!nf_inet_addr_cmp(&exp->saved_addr, &any_addr) ||
+	    exp->saved_proto.all) {
 		nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED);
 		if (!nest_parms)
 			goto nla_put_failure;
@@ -2009,7 +2032,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
 			goto nla_put_failure;
 
 		nat_tuple.src.l3num = nf_ct_l3num(master);
-		nat_tuple.src.u3.ip = exp->saved_ip;
+		nat_tuple.src.u3 = exp->saved_addr;
 		nat_tuple.dst.protonum = nf_ct_protonum(master);
 		nat_tuple.src.u = exp->saved_proto;
 
@@ -2405,7 +2428,7 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr,
 	if (err < 0)
 		return err;
 
-	exp->saved_ip = nat_tuple.src.u3.ip;
+	exp->saved_addr = nat_tuple.src.u3;
 	exp->saved_proto = nat_tuple.src.u;
 	exp->dir = ntohl(nla_get_be32(tb[CTA_EXPECT_NAT_DIR]));
 
net/netfilter/nf_conntrack_proto_tcp.c +4 -4
index a5ac11e..9c2cc71 100644
@@ -505,10 +505,10 @@ static inline s16 nat_offset(const struct nf_conn *ct,
 
 	return get_offset != NULL ? get_offset(ct, dir, seq) : 0;
 }
-#define NAT_OFFSET(pf, ct, dir, seq) \
-	(pf == NFPROTO_IPV4 ? nat_offset(ct, dir, seq) : 0)
+#define NAT_OFFSET(ct, dir, seq) \
+	(nat_offset(ct, dir, seq))
 #else
-#define NAT_OFFSET(pf, ct, dir, seq)	0
+#define NAT_OFFSET(ct, dir, seq)	0
 #endif
 
 static bool tcp_in_window(const struct nf_conn *ct,
@@ -541,7 +541,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
 		tcp_sack(skb, dataoff, tcph, &sack);
 
 	/* Take into account NAT sequence number mangling */
-	receiver_offset = NAT_OFFSET(pf, ct, !dir, ack - 1);
+	receiver_offset = NAT_OFFSET(ct, !dir, ack - 1);
 	ack -= receiver_offset;
 	sack -= receiver_offset;
 
net/netfilter/nf_conntrack_sip.c +3 -3
index 590f0ab..d517490 100644
@@ -946,11 +946,11 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
 			break;
 #ifdef CONFIG_NF_NAT_NEEDED
 		if (exp->tuple.src.l3num == AF_INET && !direct_rtp &&
-		    (exp->saved_ip != exp->tuple.dst.u3.ip ||
+		    (exp->saved_addr.ip != exp->tuple.dst.u3.ip ||
 		     exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) &&
 		    ct->status & IPS_NAT_MASK) {
-			daddr->ip		= exp->saved_ip;
-			tuple.dst.u3.ip		= exp->saved_ip;
+			daddr->ip		= exp->saved_addr.ip;
+			tuple.dst.u3.ip		= exp->saved_addr.ip;
 			tuple.dst.u.udp.port	= exp->saved_proto.udp.port;
 			direct_rtp = 1;
 		} else
net/netfilter/nf_nat_core.c renamed from net/ipv4/netfilter/nf_nat_core.c +314 -285

919 lines not on this page · raw message

net/netfilter/nf_nat_helper.c renamed from net/ipv4/netfilter/nf_nat_helper.c +37 -63

31 lines not on this page · raw message

net/netfilter/nf_nat_proto_common.c renamed from net/ipv4/netfilter/nf_nat_proto_common.c +26 -28

54 lines not on this page · raw message

net/netfilter/nf_nat_proto_dccp.c renamed from net/ipv4/netfilter/nf_nat_proto_dccp.c +33 -23

56 lines not on this page · raw message

net/netfilter/nf_nat_proto_sctp.c renamed from net/ipv4/netfilter/nf_nat_proto_sctp.c +30 -23

53 lines not on this page · raw message

net/netfilter/nf_nat_proto_tcp.c renamed from net/ipv4/netfilter/nf_nat_proto_tcp.c +17 -23
similarity index 65%
rename from net/ipv4/netfilter/nf_nat_proto_tcp.c
rename to net/netfilter/nf_nat_proto_tcp.c
index 9fb4b4e..83ec8a6 100644

Lines of this file are not shown. View the raw message.

net/netfilter/nf_nat_proto_udp.c renamed from net/ipv4/netfilter/nf_nat_proto_udp.c +18 -24

42 lines not on this page · raw message

net/netfilter/nf_nat_proto_udplite.c renamed from net/ipv4/netfilter/nf_nat_proto_udplite.c +33 -25

58 lines not on this page · raw message

net/netfilter/nf_nat_proto_unknown.c renamed from net/ipv4/netfilter/nf_nat_proto_unknown.c +9 -7
similarity index 76%
rename from net/ipv4/netfilter/nf_nat_proto_unknown.c
rename to net/netfilter/nf_nat_proto_unknown.c
index e0afe81..6e494d5 100644

Lines of this file are not shown. View the raw message.

net/netfilter/xt_nat.c new file +167 -0

167 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 1 line
1.7.1

Part of the diff is not shown here. View the raw message.

#43 lore raw

PATCH 10/19 netfilter: ipv6: expand skb head in ip6_route_me_harder after oif change

In reply to [email protected]

From: Patrick McHardy <[email protected]>

Expand the skb headroom if the oif changed due to rerouting similar to how IPv4 packets are handled.

---
 net/ipv6/netfilter.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)
net/ipv6/netfilter.c +8 -0
index db31561..429089c 100644
@@ -15,6 +15,7 @@ int ip6_route_me_harder(struct sk_buff *skb)
 {
 	struct net *net = dev_net(skb_dst(skb)->dev);
 	const struct ipv6hdr *iph = ipv6_hdr(skb);
+	unsigned int hh_len;
 	struct dst_entry *dst;
 	struct flowi6 fl6 = {
 		.flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0,
@@ -47,6 +48,13 @@ int ip6_route_me_harder(struct sk_buff *skb)
 	}
 #endif
 
+	/* Change in oif may mean change in hh_len. */
+	hh_len = skb_dst(skb)->dev->hard_header_len;
+	if (skb_headroom(skb) < hh_len &&
+	    pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)),
+			     0, GFP_ATOMIC))
+		return -1;
+
 	return 0;
 }
 EXPORT_SYMBOL(ip6_route_me_harder);
Signature · 1 line
1.7.1
#44 lore raw

PATCH 11/19 net: core: add function for incremental IPv6 pseudo header checksum updates

In reply to [email protected]

From: Patrick McHardy <[email protected]>

Add inet_proto_csum_replace16 for incrementally updating IPv6 pseudo header checksums for IPv6 NAT.

---
 include/net/checksum.h |    3 +++
 net/core/utils.c       |   20 ++++++++++++++++++++
 2 files changed, 23 insertions(+), 0 deletions(-)
include/net/checksum.h +3 -0
index ba55d8b..600d1d7 100644
@@ -109,6 +109,9 @@ static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to)
 struct sk_buff;
 extern void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
 				     __be32 from, __be32 to, int pseudohdr);
+extern void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
+				      const __be32 *from, const __be32 *to,
+				      int pseudohdr);
 
 static inline void inet_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
 					    __be16 from, __be16 to,
net/core/utils.c +20 -0
index 39895a6..f5613d5 100644
@@ -294,6 +294,26 @@ void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
 }
 EXPORT_SYMBOL(inet_proto_csum_replace4);
 
+void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
+			       const __be32 *from, const __be32 *to,
+			       int pseudohdr)
+{
+	__be32 diff[] = {
+		~from[0], ~from[1], ~from[2], ~from[3],
+		to[0], to[1], to[2], to[3],
+	};
+	if (skb->ip_summed != CHECKSUM_PARTIAL) {
+		*sum = csum_fold(csum_partial(diff, sizeof(diff),
+				 ~csum_unfold(*sum)));
+		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
+			skb->csum = ~csum_partial(diff, sizeof(diff),
+						  ~skb->csum);
+	} else if (pseudohdr)
+		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
+				  csum_unfold(*sum)));
+}
+EXPORT_SYMBOL(inet_proto_csum_replace16);
+
 int mac_pton(const char *s, u8 *mac)
 {
 	int i;
Signature · 1 line
1.7.1
#45 lore raw

PATCH 12/19 netfilter: ipv6: add IPv6 NAT support

In reply to [email protected]

From: Patrick McHardy <[email protected]>

---
 include/linux/netfilter/nfnetlink_conntrack.h  |    2 +
 include/net/netfilter/nf_nat_l3proto.h         |    5 +
 include/net/netfilter/nf_nat_l4proto.h         |    1 +
 include/net/netns/ipv6.h                       |    1 +
 net/core/secure_seq.c                          |    1 +
 net/ipv6/netfilter/Kconfig                     |   12 +
 net/ipv6/netfilter/Makefile                    |    4 +
 net/ipv6/netfilter/ip6table_nat.c              |  321 ++++++++++++++++++++++++
 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |   39 +++-
 net/ipv6/netfilter/nf_nat_l3proto_ipv6.c       |  287 +++++++++++++++++++++
 net/ipv6/netfilter/nf_nat_proto_icmpv6.c       |   90 +++++++
 11 files changed, 761 insertions(+), 2 deletions(-)
 create mode 100644 net/ipv6/netfilter/ip6table_nat.c
 create mode 100644 net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
 create mode 100644 net/ipv6/netfilter/nf_nat_proto_icmpv6.c
include/linux/netfilter/nfnetlink_conntrack.h +2 -0
index 68920ea..43bfe3e 100644
@@ -147,6 +147,8 @@ enum ctattr_nat {
 	CTA_NAT_V4_MAXIP,
 #define CTA_NAT_MAXIP CTA_NAT_V4_MAXIP
 	CTA_NAT_PROTO,
+	CTA_NAT_V6_MINIP,
+	CTA_NAT_V6_MAXIP,
 	__CTA_NAT_MAX
 };
 #define CTA_NAT_MAX (__CTA_NAT_MAX - 1)
include/net/netfilter/nf_nat_l3proto.h +5 -0
index 3df4a67..57d9e27 100644
@@ -43,5 +43,10 @@ extern int nf_nat_icmp_reply_translation(struct sk_buff *skb,
 					 struct nf_conn *ct,
 					 enum ip_conntrack_info ctinfo,
 					 unsigned int hooknum);
+extern int nf_nat_icmpv6_reply_translation(struct sk_buff *skb,
+					   struct nf_conn *ct,
+					   enum ip_conntrack_info ctinfo,
+					   unsigned int hooknum,
+					   unsigned int hdrlen);
 
 #endif /* _NF_NAT_L3PROTO_H */
include/net/netfilter/nf_nat_l4proto.h +1 -0
index 1f0a4f0..24feb68 100644
@@ -51,6 +51,7 @@ extern const struct nf_nat_l4proto *__nf_nat_l4proto_find(u8 l3proto, u8 l4proto
 extern const struct nf_nat_l4proto nf_nat_l4proto_tcp;
 extern const struct nf_nat_l4proto nf_nat_l4proto_udp;
 extern const struct nf_nat_l4proto nf_nat_l4proto_icmp;
+extern const struct nf_nat_l4proto nf_nat_l4proto_icmpv6;
 extern const struct nf_nat_l4proto nf_nat_l4proto_unknown;
 
 extern bool nf_nat_l4proto_in_range(const struct nf_conntrack_tuple *tuple,
include/net/netns/ipv6.h +1 -0
index df0a545..0318104 100644
@@ -42,6 +42,7 @@ struct netns_ipv6 {
 #ifdef CONFIG_SECURITY
 	struct xt_table		*ip6table_security;
 #endif
+	struct xt_table		*ip6table_nat;
 #endif
 	struct rt6_info         *ip6_null_entry;
 	struct rt6_statistics   *rt6_stats;
net/core/secure_seq.c +1 -0
index 99b2596..e61a8bb 100644
@@ -76,6 +76,7 @@ u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
 
 	return hash[0];
 }
+EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
 #endif
 
 #ifdef CONFIG_INET
net/ipv6/netfilter/Kconfig +12 -0
index 1013534..b27e0ad 100644
@@ -25,6 +25,18 @@ config NF_CONNTRACK_IPV6
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NF_NAT_IPV6
+	tristate "IPv6 NAT"
+	depends on NF_CONNTRACK_IPV6
+	depends on NETFILTER_ADVANCED
+	select NF_NAT
+	help
+	  The IPv6 NAT option allows masquerading, port forwarding and other
+	  forms of full Network Address Port Translation. It is controlled by
+	  the `nat' table in ip6tables, see the man page for ip6tables(8).
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP6_NF_IPTABLES
 	tristate "IP6 tables support (required for filtering)"
 	depends on INET && IPV6
net/ipv6/netfilter/Makefile +4 -0
index 534d3f2..7677937 100644
@@ -8,6 +8,7 @@ obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
 obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
 obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
 obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o
+obj-$(CONFIG_NF_NAT_IPV6) += ip6table_nat.o
 
 # objects for l3 independent conntrack
 nf_conntrack_ipv6-y  :=  nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o
@@ -15,6 +16,9 @@ nf_conntrack_ipv6-y  :=  nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o
 # l3 independent conntrack
 obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o nf_defrag_ipv6.o
 
+nf_nat_ipv6-y		:= nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o
+obj-$(CONFIG_NF_NAT_IPV6) += nf_nat_ipv6.o
+
 # defrag
 nf_defrag_ipv6-y := nf_defrag_ipv6_hooks.o nf_conntrack_reasm.o
 obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
net/ipv6/netfilter/ip6table_nat.c new file +321 -0

321 lines not on this page · raw message

net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +37 -2
index 4d92ea6..9f427b5 100644
@@ -28,6 +28,7 @@
 #include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
+#include <net/netfilter/nf_nat_helper.h>
 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
 #include <net/netfilter/nf_log.h>
 
@@ -142,6 +143,36 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
 				 const struct net_device *out,
 				 int (*okfn)(struct sk_buff *))
 {
+	struct nf_conn *ct;
+	enum ip_conntrack_info ctinfo;
+	unsigned char pnum = ipv6_hdr(skb)->nexthdr;
+	int protoff;
+	__be16 frag_off;
+
+	ct = nf_ct_get(skb, &ctinfo);
+	if (!ct || ctinfo == IP_CT_RELATED_REPLY)
+		goto out;
+
+	protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum,
+				   &frag_off);
+	if (protoff < 0 || (frag_off & ntohs(~0x7)) != 0) {
+		pr_debug("proto header not found\n");
+		goto out;
+	}
+
+	/* adjust seqs for loopback traffic only in outgoing direction */
+	if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
+	    !nf_is_loopback_packet(skb)) {
+		typeof(nf_nat_seq_adjust_hook) seq_adjust;
+
+		seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
+		if (!seq_adjust ||
+		    !seq_adjust(skb, ct, ctinfo, protoff)) {
+			NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
+			return NF_DROP;
+		}
+	}
+out:
 	/* We've seen it coming out the other side: confirm it */
 	return nf_conntrack_confirm(skb);
 }
@@ -169,10 +200,14 @@ static unsigned int __ipv6_conntrack_in(struct net *net,
 		}
 
 		/* Conntrack helpers need the entire reassembled packet in the
-		 * POST_ROUTING hook.
+		 * POST_ROUTING hook. In case of unconfirmed connections NAT
+		 * might reassign a helper, so the entire packet is also
+		 * required.
 		 */
 		ct = nf_ct_get(reasm, &ctinfo);
-		if (ct != NULL && test_bit(IPS_HELPER_BIT, &ct->status)) {
+		if (ct != NULL &&
+		    (test_bit(IPS_HELPER_BIT, &ct->status) ||
+		     !nf_ct_is_confirmed(ct))) {
 			nf_conntrack_get_reasm(skb);
 			NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
 				       (struct net_device *)in,
net/ipv6/netfilter/nf_nat_l3proto_ipv6.c new file +287 -0

287 lines not on this page · raw message

net/ipv6/netfilter/nf_nat_proto_icmpv6.c new file +90 -0

90 lines not on this page · raw message

Signature · 1 line
1.7.1
#46 lore raw

PATCH 13/19 netfilter: ip6tables: add MASQUERADE target

In reply to [email protected]

From: Patrick McHardy <[email protected]>

---
 include/net/addrconf.h               |    2 +-
 net/ipv4/netfilter/ipt_MASQUERADE.c  |    3 +-
 net/ipv6/addrconf.c                  |    2 +-
 net/ipv6/netfilter/Kconfig           |   12 +++
 net/ipv6/netfilter/Makefile          |    1 +
 net/ipv6/netfilter/ip6t_MASQUERADE.c |  135 ++++++++++++++++++++++++++++++++++
 6 files changed, 152 insertions(+), 3 deletions(-)
 create mode 100644 net/ipv6/netfilter/ip6t_MASQUERADE.c
include/net/addrconf.h +1 -1
index 089a09d..9e63e76 100644
@@ -78,7 +78,7 @@ extern struct inet6_ifaddr      *ipv6_get_ifaddr(struct net *net,
 						 int strict);
 
 extern int			ipv6_dev_get_saddr(struct net *net,
-					       struct net_device *dev,
+					       const struct net_device *dev,
 					       const struct in6_addr *daddr,
 					       unsigned int srcprefs,
 					       struct in6_addr *saddr);
net/ipv4/netfilter/ipt_MASQUERADE.c +2 -1
index 1c3aa28..5d5d4d1 100644
@@ -99,7 +99,8 @@ device_cmp(struct nf_conn *i, void *ifindex)
 
 	if (!nat)
 		return 0;
-
+	if (nf_ct_l3num(i) != NFPROTO_IPV4)
+		return 0;
 	return nat->masq_index == (int)(long)ifindex;
 }
 
net/ipv6/addrconf.c +1 -1
index 7918181..6536404 100644
@@ -1095,7 +1095,7 @@ out:
 	return ret;
 }
 
-int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
+int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
 		       const struct in6_addr *daddr, unsigned int prefs,
 		       struct in6_addr *saddr)
 {
net/ipv6/netfilter/Kconfig +12 -0
index b27e0ad..54a5032 100644
@@ -144,6 +144,18 @@ config IP6_NF_TARGET_HL
 	(e.g. when running oldconfig). It selects
 	CONFIG_NETFILTER_XT_TARGET_HL.
 
+config IP6_NF_TARGET_MASQUERADE
+	tristate "MASQUERADE target support"
+	depends on NF_NAT_IPV6
+	help
+	  Masquerading is a special case of NAT: all outgoing connections are
+	  changed to seem to come from a particular interface's address, and
+	  if the interface goes down, those connections are lost.  This is
+	  only useful for dialup accounts with dynamic IP address (ie. your IP
+	  address will be different on next dialup).
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP6_NF_FILTER
 	tristate "Packet filtering"
 	default m if NETFILTER_ADVANCED=n
net/ipv6/netfilter/Makefile +1 -0
index 7677937..068bad1 100644
@@ -34,4 +34,5 @@ obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
 
 # targets
+obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
 obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
net/ipv6/netfilter/ip6t_MASQUERADE.c new file +135 -0

135 lines not on this page · raw message

Signature · 1 line
1.7.1
#47 lore raw

Re: [PATCH 13/19] netfilter: ip6tables: add MASQUERADE target

Hi Patrick,

Quoted 12 lines · On Thu, Aug 09, 2012 at 10:08:57PM +0200, [email protected] wrote:

From: Patrick McHardy <[email protected]>

---
 include/net/addrconf.h               |    2 +-
 net/ipv4/netfilter/ipt_MASQUERADE.c  |    3 +-
 net/ipv6/addrconf.c                  |    2 +-
 net/ipv6/netfilter/Kconfig           |   12 +++
 net/ipv6/netfilter/Makefile          |    1 +
 net/ipv6/netfilter/ip6t_MASQUERADE.c |  135 ++++++++++++++++++++++++++++++++++
 6 files changed, 152 insertions(+), 3 deletions(-)
 create mode 100644 net/ipv6/netfilter/ip6t_MASQUERADE.c

Please, add this chunk to this patch:

(quoted diff) +0 -0

b/include/net/netfilter/nf_nat.h
index 1752f133..bd8eea7 100644

include/net/netfilter/nf_nat.h +3 -1
@@ -43,7 +43,9 @@ struct nf_conn_nat {
        struct nf_conn *ct;
        union nf_conntrack_nat_help help;
 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
-    defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
+    defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) || \
+    defined(CONFIG_IP6_NF_TARGET_MASQUERADE) || \
+    defined(CONFIG_IP6_NF_TARGET_MASQUERADE_MODULE)
        int masq_index;
 #endif
 };

Otherwise, compilation breaks with:

* IPv4 NAT is disabled
* IPv6 NAT enabled.

And yes, that pile of ifdefs is really ugly, I wonder if they are worth for saving 4 bytes. I think most vendors usually include MASQUERADE support if NAT is enabled.

It seems we have the tradition of keeping several similar compile time options in Netfilter to optimize memory in several situations (at the cost of polluting the code with ifdefs). Probably we can think of getting rid of them.

Quoted 221 lines
include/net/addrconf.h +1 -1
index 089a09d..9e63e76 100644
@@ -78,7 +78,7 @@ extern struct inet6_ifaddr      *ipv6_get_ifaddr(struct net *net,
 						 int strict);
 
 extern int			ipv6_dev_get_saddr(struct net *net,
-					       struct net_device *dev,
+					       const struct net_device *dev,
 					       const struct in6_addr *daddr,
 					       unsigned int srcprefs,
 					       struct in6_addr *saddr);
net/ipv4/netfilter/ipt_MASQUERADE.c +2 -1
index 1c3aa28..5d5d4d1 100644
@@ -99,7 +99,8 @@ device_cmp(struct nf_conn *i, void *ifindex)
 
 	if (!nat)
 		return 0;
-
+	if (nf_ct_l3num(i) != NFPROTO_IPV4)
+		return 0;
 	return nat->masq_index == (int)(long)ifindex;
 }
 
net/ipv6/addrconf.c +1 -1
index 7918181..6536404 100644
@@ -1095,7 +1095,7 @@ out:
 	return ret;
 }
 
-int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
+int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
 		       const struct in6_addr *daddr, unsigned int prefs,
 		       struct in6_addr *saddr)
 {
net/ipv6/netfilter/Kconfig +12 -0
index b27e0ad..54a5032 100644
@@ -144,6 +144,18 @@ config IP6_NF_TARGET_HL
 	(e.g. when running oldconfig). It selects
 	CONFIG_NETFILTER_XT_TARGET_HL.
 
+config IP6_NF_TARGET_MASQUERADE
+	tristate "MASQUERADE target support"
+	depends on NF_NAT_IPV6
+	help
+	  Masquerading is a special case of NAT: all outgoing connections are
+	  changed to seem to come from a particular interface's address, and
+	  if the interface goes down, those connections are lost.  This is
+	  only useful for dialup accounts with dynamic IP address (ie. your IP
+	  address will be different on next dialup).
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP6_NF_FILTER
 	tristate "Packet filtering"
 	default m if NETFILTER_ADVANCED=n
net/ipv6/netfilter/Makefile +1 -0
index 7677937..068bad1 100644
@@ -34,4 +34,5 @@ obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
 
 # targets
+obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
 obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
net/ipv6/netfilter/ip6t_MASQUERADE.c new file +135 -0
new file mode 100644
index 0000000..60e9053
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2011 Patrick McHardy <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Based on Rusty Russell's IPv6 MASQUERADE target. Development of IPv6
+ * NAT funded by Astaro.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/ipv6.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter/x_tables.h>
+#include <net/netfilter/nf_nat.h>
+#include <net/addrconf.h>
+#include <net/ipv6.h>
+
+static unsigned int
+masquerade_tg6(struct sk_buff *skb, const struct xt_action_param *par)
+{
+	const struct nf_nat_range *range = par->targinfo;
+	enum ip_conntrack_info ctinfo;
+	struct in6_addr src;
+	struct nf_conn *ct;
+	struct nf_nat_range newrange;
+
+	ct = nf_ct_get(skb, &ctinfo);
+	NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
+			    ctinfo == IP_CT_RELATED_REPLY));
+
+	if (ipv6_dev_get_saddr(dev_net(par->out), par->out,
+			       &ipv6_hdr(skb)->daddr, 0, &src) < 0)
+		return NF_DROP;
+
+	nfct_nat(ct)->masq_index = par->out->ifindex;
+
+	newrange.flags		= range->flags | NF_NAT_RANGE_MAP_IPS;
+	newrange.min_addr.in6	= src;
+	newrange.max_addr.in6	= src;
+	newrange.min_proto	= range->min_proto;
+	newrange.max_proto	= range->max_proto;
+
+	return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_SRC);
+}
+
+static int masquerade_tg6_checkentry(const struct xt_tgchk_param *par)
+{
+	const struct nf_nat_range *range = par->targinfo;
+
+	if (range->flags & NF_NAT_RANGE_MAP_IPS)
+		return -EINVAL;
+	return 0;
+}
+
+static int device_cmp(struct nf_conn *ct, void *ifindex)
+{
+	const struct nf_conn_nat *nat = nfct_nat(ct);
+
+	if (!nat)
+		return 0;
+	if (nf_ct_l3num(ct) != NFPROTO_IPV6)
+		return 0;
+	return nat->masq_index == (int)(long)ifindex;
+}
+
+static int masq_device_event(struct notifier_block *this,
+			     unsigned long event, void *ptr)
+{
+	const struct net_device *dev = ptr;
+	struct net *net = dev_net(dev);
+
+	if (event == NETDEV_DOWN)
+		nf_ct_iterate_cleanup(net, device_cmp,
+				      (void *)(long)dev->ifindex);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block masq_dev_notifier = {
+	.notifier_call	= masq_device_event,
+};
+
+static int masq_inet_event(struct notifier_block *this,
+			   unsigned long event, void *ptr)
+{
+	struct inet6_ifaddr *ifa = ptr;
+
+	return masq_device_event(this, event, ifa->idev->dev);
+}
+
+static struct notifier_block masq_inet_notifier = {
+	.notifier_call	= masq_inet_event,
+};
+
+static struct xt_target masquerade_tg6_reg __read_mostly = {
+	.name		= "MASQUERADE",
+	.family		= NFPROTO_IPV6,
+	.checkentry	= masquerade_tg6_checkentry,
+	.target		= masquerade_tg6,
+	.targetsize	= sizeof(struct nf_nat_range),
+	.table		= "nat",
+	.hooks		= 1 << NF_INET_POST_ROUTING,
+	.me		= THIS_MODULE,
+};
+
+static int __init masquerade_tg6_init(void)
+{
+	int err;
+
+	err = xt_register_target(&masquerade_tg6_reg);
+	if (err == 0) {
+		register_netdevice_notifier(&masq_dev_notifier);
+		register_inet6addr_notifier(&masq_inet_notifier);
+	}
+
+	return err;
+}
+static void __exit masquerade_tg6_exit(void)
+{
+	unregister_inet6addr_notifier(&masq_inet_notifier);
+	unregister_netdevice_notifier(&masq_dev_notifier);
+	xt_unregister_target(&masquerade_tg6_reg);
+}
+
+module_init(masquerade_tg6_init);
+module_exit(masquerade_tg6_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <[email protected]>");
+MODULE_DESCRIPTION("Xtables: automatic address SNAT");
Signature · 6 lines
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#48 lore raw

Re: [PATCH 13/19] netfilter: ip6tables: add MASQUERADE target

Quoted 24 lines · Pablo Neira Ayuso

Hi Patrick,

Quoted 2 lines · On Thu, Aug 09, 2012 at 10:08:57PM +0200, [email protected] wrote:

From: Patrick McHardy <[email protected]>

Please, add this chunk to this patch:

include/net/netfilter/nf_nat.h +3 -1
index 1752f133..bd8eea7 100644
@@ -43,7 +43,9 @@ struct nf_conn_nat {
       struct nf_conn *ct;
       union nf_conntrack_nat_help help;
 #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
-    defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
+    defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) || \
+    defined(CONFIG_IP6_NF_TARGET_MASQUERADE) || \
+    defined(CONFIG_IP6_NF_TARGET_MASQUERADE_MODULE)
       int masq_index;
 #endif
 };
Quoted 4 lines

Otherwise, compilation breaks with:

* IPv4 NAT is disabled
* IPv6 NAT enabled.

Fixed, thanks.

Quoted 9 lines

And yes, that pile of ifdefs is really ugly, I wonder if they are worth for saving 4 bytes. I think most vendors usually include MASQUERADE support if NAT is enabled.

It seems we have the tradition of keeping several similar compile time options in Netfilter to optimize memory in several situations (at the cost of polluting the code with ifdefs). Probably we can think of getting rid of them.

Well, vendors maybe, but what about embedded systems? I have some which are *really* short on memory. They limit conntrack to very few entries though, so it doesn't make that much of a difference.

#49 lore raw

PATCH 14/19 netfilter: ip6tables: add REDIRECT target

In reply to [email protected]

From: Patrick McHardy <[email protected]>

---
 net/ipv6/netfilter/Kconfig         |   11 ++++
 net/ipv6/netfilter/Makefile        |    1 +
 net/ipv6/netfilter/ip6t_REDIRECT.c |   98 ++++++++++++++++++++++++++++++++++++
 3 files changed, 110 insertions(+), 0 deletions(-)
 create mode 100644 net/ipv6/netfilter/ip6t_REDIRECT.c
net/ipv6/netfilter/Kconfig +11 -0
index 54a5032..585590f 100644
@@ -156,6 +156,17 @@ config IP6_NF_TARGET_MASQUERADE
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config IP6_NF_TARGET_REDIRECT
+	tristate "REDIRECT target support"
+	depends on NF_NAT_IPV6
+	help
+	  REDIRECT is a special case of NAT: all incoming connections are
+	  mapped onto the incoming interface's address, causing the packets to
+	  come to the local machine instead of passing through.  This is
+	  useful for transparent proxies.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP6_NF_FILTER
 	tristate "Packet filtering"
 	default m if NETFILTER_ADVANCED=n
net/ipv6/netfilter/Makefile +1 -0
index 068bad1..e30a531 100644
@@ -35,4 +35,5 @@ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
 
 # targets
 obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
+obj-$(CONFIG_IP6_NF_TARGET_REDIRECT) += ip6t_REDIRECT.o
 obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
net/ipv6/netfilter/ip6t_REDIRECT.c new file +98 -0

98 lines not on this page · raw message

Signature · 1 line
1.7.1
#50 lore raw

PATCH 15/19 netfilter: ip6tables: add NETMAP target

In reply to [email protected]

From: Patrick McHardy <[email protected]>

---
 net/ipv6/netfilter/Kconfig       |   10 ++++
 net/ipv6/netfilter/Makefile      |    1 +
 net/ipv6/netfilter/ip6t_NETMAP.c |   94 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 105 insertions(+), 0 deletions(-)
 create mode 100644 net/ipv6/netfilter/ip6t_NETMAP.c
net/ipv6/netfilter/Kconfig +10 -0
index 585590f..7bdf73b 100644
@@ -156,6 +156,16 @@ config IP6_NF_TARGET_MASQUERADE
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config IP6_NF_TARGET_NETMAP
+	tristate "NETMAP target support"
+	depends on NF_NAT_IPV6
+	help
+	  NETMAP is an implementation of static 1:1 NAT mapping of network
+	  addresses. It maps the network address part, while keeping the host
+	  address part intact.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP6_NF_TARGET_REDIRECT
 	tristate "REDIRECT target support"
 	depends on NF_NAT_IPV6
net/ipv6/netfilter/Makefile +1 -0
index e30a531..0864ce6 100644
@@ -35,5 +35,6 @@ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
 
 # targets
 obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
+obj-$(CONFIG_IP6_NF_TARGET_NETMAP) += ip6t_NETMAP.o
 obj-$(CONFIG_IP6_NF_TARGET_REDIRECT) += ip6t_REDIRECT.o
 obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
net/ipv6/netfilter/ip6t_NETMAP.c new file +94 -0

94 lines not on this page · raw message

Signature · 1 line
1.7.1
#51 lore raw

PATCH 16/19 netfilter: nf_nat: support IPv6 in FTP NAT helper

In reply to [email protected]

From: Patrick McHardy <[email protected]>

---
 net/ipv4/netfilter/Kconfig            |    5 -----
 net/ipv4/netfilter/Makefile           |    1 -
 net/netfilter/Kconfig                 |    5 +++++
 net/netfilter/Makefile                |    3 +++
 net/netfilter/nf_conntrack_ftp.c      |    3 +--
 net/{ipv4 => }/netfilter/nf_nat_ftp.c |   30 ++++++++++++++++++------------
 6 files changed, 27 insertions(+), 20 deletions(-)
 rename net/{ipv4 => }/netfilter/nf_nat_ftp.c (82%)
net/ipv4/netfilter/Kconfig +0 -5
index 33372a1..80272e7 100644
@@ -220,11 +220,6 @@ config NF_NAT_PROTO_GRE
 	tristate
 	depends on NF_NAT_IPV4 && NF_CT_PROTO_GRE
 
-config NF_NAT_FTP
-	tristate
-	depends on NF_CONNTRACK && NF_NAT_IPV4
-	default NF_NAT_IPV4 && NF_CONNTRACK_FTP
-
 config NF_NAT_IRC
 	tristate
 	depends on NF_CONNTRACK && NF_NAT_IPV4
net/ipv4/netfilter/Makefile +0 -1
index 0ea3acc..4d8a4ad 100644
@@ -21,7 +21,6 @@ obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o
 
 # NAT helpers (nf_conntrack)
 obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o
-obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
 obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
 obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o
 obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
net/netfilter/Kconfig +5 -0
index 91addda..3104494 100644
@@ -380,6 +380,11 @@ config NF_NAT_PROTO_SCTP
 	depends on NF_NAT && NF_CT_PROTO_SCTP
 	select LIBCRC32C
 
+config NF_NAT_FTP
+	tristate
+	depends on NF_CONNTRACK && NF_NAT
+	default NF_NAT && NF_CONNTRACK_FTP
+
 endif # NF_CONNTRACK
 
 # transparent proxy support
net/netfilter/Makefile +3 -0
index 09c9451..16592b1 100644
@@ -54,6 +54,9 @@ obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o
 obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o
 obj-$(CONFIG_NF_NAT_PROTO_SCTP) += nf_nat_proto_sctp.o
 
+# NAT helpers
+obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
+
 # transparent proxy support
 obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o
 
net/netfilter/nf_conntrack_ftp.c +1 -2
index c0f4a5b..f8cc26a 100644
@@ -488,8 +488,7 @@ static int help(struct sk_buff *skb,
 	/* Now, NAT might want to mangle the packet, and register the
 	 * (possibly changed) expectation itself. */
 	nf_nat_ftp = rcu_dereference(nf_nat_ftp_hook);
-	if (nf_nat_ftp && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
-	    ct->status & IPS_NAT_MASK)
+	if (nf_nat_ftp && ct->status & IPS_NAT_MASK)
 		ret = nf_nat_ftp(skb, ctinfo, search[dir][i].ftptype,
 				 protoff, matchoff, matchlen, exp);
 	else {
net/netfilter/nf_nat_ftp.c renamed from net/ipv4/netfilter/nf_nat_ftp.c +18 -12
similarity index 82%
rename from net/ipv4/netfilter/nf_nat_ftp.c
rename to net/netfilter/nf_nat_ftp.c
index dd5e387..e839b97 100644
@@ -10,7 +10,7 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/ip.h>
+#include <linux/inet.h>
 #include <linux/tcp.h>
 #include <linux/netfilter_ipv4.h>
 #include <net/netfilter/nf_nat.h>
@@ -26,22 +26,27 @@ MODULE_ALIAS("ip_nat_ftp");
 
 /* FIXME: Time out? --RR */
 
-static int nf_nat_ftp_fmt_cmd(enum nf_ct_ftp_type type,
+static int nf_nat_ftp_fmt_cmd(struct nf_conn *ct, enum nf_ct_ftp_type type,
 			      char *buffer, size_t buflen,
-			      __be32 addr, u16 port)
+			      union nf_inet_addr *addr, u16 port)
 {
 	switch (type) {
 	case NF_CT_FTP_PORT:
 	case NF_CT_FTP_PASV:
 		return snprintf(buffer, buflen, "%u,%u,%u,%u,%u,%u",
-				((unsigned char *)&addr)[0],
-				((unsigned char *)&addr)[1],
-				((unsigned char *)&addr)[2],
-				((unsigned char *)&addr)[3],
+				((unsigned char *)&addr->ip)[0],
+				((unsigned char *)&addr->ip)[1],
+				((unsigned char *)&addr->ip)[2],
+				((unsigned char *)&addr->ip)[3],
 				port >> 8,
 				port & 0xFF);
 	case NF_CT_FTP_EPRT:
-		return snprintf(buffer, buflen, "|1|%pI4|%u|", &addr, port);
+		if (nf_ct_l3num(ct) == NFPROTO_IPV4)
+			return snprintf(buffer, buflen, "|1|%pI4|%u|",
+					&addr->ip, port);
+		else
+			return snprintf(buffer, buflen, "|2|%pI6|%u|",
+					&addr->ip6, port);
 	case NF_CT_FTP_EPSV:
 		return snprintf(buffer, buflen, "|||%u|", port);
 	}
@@ -59,17 +64,17 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb,
 			       unsigned int matchlen,
 			       struct nf_conntrack_expect *exp)
 {
-	__be32 newip;
+	union nf_inet_addr newaddr;
 	u_int16_t port;
 	int dir = CTINFO2DIR(ctinfo);
 	struct nf_conn *ct = exp->master;
-	char buffer[sizeof("|1|255.255.255.255|65535|")];
+	char buffer[sizeof("|1||65535|") + INET6_ADDRSTRLEN];
 	unsigned int buflen;
 
 	pr_debug("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen);
 
 	/* Connection will come from wherever this packet goes, hence !dir */
-	newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
+	newaddr = ct->tuplehash[!dir].tuple.dst.u3;
 	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
 	exp->dir = !dir;
 
@@ -94,7 +99,8 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb,
 	if (port == 0)
 		return NF_DROP;
 
-	buflen = nf_nat_ftp_fmt_cmd(type, buffer, sizeof(buffer), newip, port);
+	buflen = nf_nat_ftp_fmt_cmd(ct, type, buffer, sizeof(buffer),
+				    &newaddr, port);
 	if (!buflen)
 		goto out;
 
Signature · 1 line
1.7.1
#52 lore raw

PATCH 17/19 netfilter: nf_nat: support IPv6 in amanda NAT helper

In reply to [email protected]

From: Patrick McHardy <[email protected]>

---
 net/ipv4/netfilter/Kconfig               |    5 -----
 net/ipv4/netfilter/Makefile              |    1 -
 net/netfilter/Kconfig                    |    5 +++++
 net/netfilter/Makefile                   |    1 +
 net/netfilter/nf_conntrack_amanda.c      |    3 +--
 net/{ipv4 => }/netfilter/nf_nat_amanda.c |    0
 6 files changed, 7 insertions(+), 8 deletions(-)
 rename net/{ipv4 => }/netfilter/nf_nat_amanda.c (100%)
net/ipv4/netfilter/Kconfig +0 -5
index 80272e7..df42031 100644
@@ -230,11 +230,6 @@ config NF_NAT_TFTP
 	depends on NF_CONNTRACK && NF_NAT_IPV4
 	default NF_NAT_IPV4 && NF_CONNTRACK_TFTP
 
-config NF_NAT_AMANDA
-	tristate
-	depends on NF_CONNTRACK && NF_NAT_IPV4
-	default NF_NAT_IPV4 && NF_CONNTRACK_AMANDA
-
 config NF_NAT_PPTP
 	tristate
 	depends on NF_CONNTRACK && NF_NAT_IPV4
net/ipv4/netfilter/Makefile +0 -1
index 4d8a4ad..8baa496 100644
@@ -20,7 +20,6 @@ obj-$(CONFIG_NF_NAT_IPV4) += nf_nat_ipv4.o
 obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o
 
 # NAT helpers (nf_conntrack)
-obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o
 obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
 obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o
 obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
net/netfilter/Kconfig +5 -0
index 3104494..2eee9f1 100644
@@ -380,6 +380,11 @@ config NF_NAT_PROTO_SCTP
 	depends on NF_NAT && NF_CT_PROTO_SCTP
 	select LIBCRC32C
 
+config NF_NAT_AMANDA
+	tristate
+	depends on NF_CONNTRACK && NF_NAT
+	default NF_NAT && NF_CONNTRACK_AMANDA
+
 config NF_NAT_FTP
 	tristate
 	depends on NF_CONNTRACK && NF_NAT
net/netfilter/Makefile +1 -0
index 16592b1..7d6e1ea 100644
@@ -55,6 +55,7 @@ obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o
 obj-$(CONFIG_NF_NAT_PROTO_SCTP) += nf_nat_proto_sctp.o
 
 # NAT helpers
+obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o
 obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
 
 # transparent proxy support
net/netfilter/nf_conntrack_amanda.c +1 -2
index e0212b5..c514fe6 100644
@@ -155,8 +155,7 @@ static int amanda_help(struct sk_buff *skb,
 				  IPPROTO_TCP, NULL, &port);
 
 		nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook);
-		if (nf_nat_amanda && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
-		    ct->status & IPS_NAT_MASK)
+		if (nf_nat_amanda && ct->status & IPS_NAT_MASK)
 			ret = nf_nat_amanda(skb, ctinfo, protoff,
 					    off - dataoff, len, exp);
 		else if (nf_ct_expect_related(exp) != 0)
net/netfilter/nf_nat_amanda.c renamed from net/ipv4/netfilter/nf_nat_amanda.c +0 -0
similarity index 100%
rename from net/ipv4/netfilter/nf_nat_amanda.c
rename to net/netfilter/nf_nat_amanda.c
Signature · 1 line
1.7.1
#53 lore raw

PATCH 18/19 netfilter: nf_nat: support IPv6 in SIP NAT helper

In reply to [email protected]

From: Patrick McHardy <[email protected]>

Add IPv6 support to the SIP NAT helper. There are no functional differences to IPv4 NAT, just different formats for addresses.

---
 include/linux/netfilter/nf_conntrack_sip.h |    9 +-
 net/ipv4/netfilter/Kconfig                 |    5 -
 net/ipv4/netfilter/Makefile                |    1 -
 net/netfilter/Kconfig                      |    5 +
 net/netfilter/Makefile                     |    1 +
 net/netfilter/nf_conntrack_sip.c           |   68 ++++++------
 net/{ipv4 => }/netfilter/nf_nat_sip.c      |  172 ++++++++++++++++------------
 7 files changed, 145 insertions(+), 116 deletions(-)
 rename net/{ipv4 => }/netfilter/nf_nat_sip.c (76%)
include/linux/netfilter/nf_conntrack_sip.h +4 -5
index 1afc669..387bdd0 100644
@@ -99,10 +99,8 @@ enum sip_header_types {
 enum sdp_header_types {
 	SDP_HDR_UNSPEC,
 	SDP_HDR_VERSION,
-	SDP_HDR_OWNER_IP4,
-	SDP_HDR_CONNECTION_IP4,
-	SDP_HDR_OWNER_IP6,
-	SDP_HDR_CONNECTION_IP6,
+	SDP_HDR_OWNER,
+	SDP_HDR_CONNECTION,
 	SDP_HDR_MEDIA,
 };
 
@@ -111,7 +109,8 @@ extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
 				       unsigned int dataoff,
 				       const char **dptr,
 				       unsigned int *datalen);
-extern void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, s16 off);
+extern void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb,
+					  unsigned int protoff, s16 off);
 extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
 					      unsigned int protoff,
 					      unsigned int dataoff,
net/ipv4/netfilter/Kconfig +0 -5
index df42031..27f9574 100644
@@ -241,11 +241,6 @@ config NF_NAT_H323
 	depends on NF_CONNTRACK && NF_NAT_IPV4
 	default NF_NAT_IPV4 && NF_CONNTRACK_H323
 
-config NF_NAT_SIP
-	tristate
-	depends on NF_CONNTRACK && NF_NAT_IPV4
-	default NF_NAT_IPV4 && NF_CONNTRACK_SIP
-
 # mangle + specific targets
 config IP_NF_MANGLE
 	tristate "Packet mangling"
net/ipv4/netfilter/Makefile +0 -1
index 8baa496..8914abf 100644
@@ -23,7 +23,6 @@ obj-$(CONFIG_NF_DEFRAG_IPV4) += nf_defrag_ipv4.o
 obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
 obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o
 obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
-obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o
 obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
 obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o
 
net/netfilter/Kconfig +5 -0
index 2eee9f1..bf3e464 100644
@@ -390,6 +390,11 @@ config NF_NAT_FTP
 	depends on NF_CONNTRACK && NF_NAT
 	default NF_NAT && NF_CONNTRACK_FTP
 
+config NF_NAT_SIP
+	tristate
+	depends on NF_CONNTRACK && NF_NAT
+	default NF_NAT && NF_CONNTRACK_SIP
+
 endif # NF_CONNTRACK
 
 # transparent proxy support
net/netfilter/Makefile +1 -0
index 7d6e1ea..7d6d1a0 100644
@@ -57,6 +57,7 @@ obj-$(CONFIG_NF_NAT_PROTO_SCTP) += nf_nat_proto_sctp.o
 # NAT helpers
 obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o
 obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
+obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o
 
 # transparent proxy support
 obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o
net/netfilter/nf_conntrack_sip.c +34 -34

160 lines not on this page · raw message

net/netfilter/nf_nat_sip.c renamed from net/ipv4/netfilter/nf_nat_sip.c +101 -71

382 lines not on this page · raw message

Signature · 1 line
1.7.1
#54 lore raw

PATCH 19/19 netfilter: ip6tables: add stateless IPv6-to-IPv6 Network Prefix Translation target

In reply to [email protected]

From: Patrick McHardy <[email protected]>

---
 include/linux/netfilter_ipv6/Kbuild     |    1 +
 include/linux/netfilter_ipv6/ip6t_NPT.h |   16 +++
 net/ipv6/netfilter/Kconfig              |    9 ++
 net/ipv6/netfilter/Makefile             |    1 +
 net/ipv6/netfilter/ip6t_NPT.c           |  165 +++++++++++++++++++++++++++++++
 5 files changed, 192 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/netfilter_ipv6/ip6t_NPT.h
 create mode 100644 net/ipv6/netfilter/ip6t_NPT.c
include/linux/netfilter_ipv6/Kbuild +1 -0
index bd095bc..b88c005 100644
@@ -1,6 +1,7 @@
 header-y += ip6_tables.h
 header-y += ip6t_HL.h
 header-y += ip6t_LOG.h
+header-y += ip6t_NPT.h
 header-y += ip6t_REJECT.h
 header-y += ip6t_ah.h
 header-y += ip6t_frag.h
include/linux/netfilter_ipv6/ip6t_NPT.h new file +16 -0
new file mode 100644
index 0000000..f763355
@@ -0,0 +1,16 @@
+#ifndef __NETFILTER_IP6T_NPT
+#define __NETFILTER_IP6T_NPT
+
+#include <linux/types.h>
+#include <linux/netfilter.h>
+
+struct ip6t_npt_tginfo {
+	union nf_inet_addr	src_pfx;
+	union nf_inet_addr	dst_pfx;
+	__u8			src_pfx_len;
+	__u8			dst_pfx_len;
+	/* Used internally by the kernel */
+	__sum16			adjustment;
+};
+
+#endif /* __NETFILTER_IP6T_NPT */
net/ipv6/netfilter/Kconfig +9 -0
index 7bdf73b..44ae1bf 100644
@@ -177,6 +177,15 @@ config IP6_NF_TARGET_REDIRECT
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config IP6_NF_TARGET_NPT
+	tristate "NPT (Network Prefix translation) target support"
+	depends on NETFILTER_ADVANCED
+	help
+	  This option adda `SNPT' and `DNPT' target, which perform stateless
+	  IPv6-to-IPv6 Network Prefix Translation (RFC 6296).
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config IP6_NF_FILTER
 	tristate "Packet filtering"
 	default m if NETFILTER_ADVANCED=n
net/ipv6/netfilter/Makefile +1 -0
index 0864ce6..5752132 100644
@@ -36,5 +36,6 @@ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
 # targets
 obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
 obj-$(CONFIG_IP6_NF_TARGET_NETMAP) += ip6t_NETMAP.o
+obj-$(CONFIG_IP6_NF_TARGET_NPT) += ip6t_NPT.o
 obj-$(CONFIG_IP6_NF_TARGET_REDIRECT) += ip6t_REDIRECT.o
 obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
net/ipv6/netfilter/ip6t_NPT.c new file +165 -0

165 lines not on this page · raw message

Signature · 1 line
1.7.1
#55 lore raw

Re: [PATCH 19/19] netfilter: ip6tables: add stateless IPv6-to-IPv6 Network Prefix Translation target

net/ipv6/netfilter/Kconfig config IP6_NF_TARGET_REDIRECT · line 185

Quoted 6 lines · On Thursday 2012-08-09 22:09, [email protected] wrote:
net/ipv6/netfilter/Kconfig +6 -0
+config IP6_NF_TARGET_NPT
+	tristate "NPT (Network Prefix translation) target support"
+	depends on NETFILTER_ADVANCED
+	help
+	  This option adda `SNPT' and `DNPT' target, which perform stateless
+	  IPv6-to-IPv6 Network Prefix Translation (RFC 6296).

Fixes/suggestion in the help text (near "adda" and subsequent).

config IP6_NF_TARGET_NPT
tristate "NPT (Network Prefix translation) target support" depends on NETFILTER_ADVANCED
---help---
This option adds the "SNPT" and "DNPT" targets, which perform stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296.

Quoted 7 lines

+/*
+ * Copyright (c) 2011, 2012 Patrick McHardy <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */

GNU sometimes has a strange way of expressing their (C) lines, listing all years separately, as if "1989-1991,1994-1999,2001-2005" was not sufficient. In your case, would "2011-2012" work?

Any objection to adding a "(or later)" clause to the set?

net/ipv6/netfilter/ip6t_NPT.c line 43

Quoted 8 lines
net/ipv6/netfilter/ip6t_NPT.c new file +8 -0
+static int ip6t_npt_checkentry(const struct xt_tgchk_param *par)
+{
+	struct ip6t_npt_tginfo *npt = par->targinfo;
+	__sum16 src_sum = 0, dst_sum = 0;
+	unsigned int i;
+
+	if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64)
+		return -EINVAL;

While the RFC probably only specifies masks up to /64, the general algorithm is sustainable up to at least /96.

Extending the RFC's section 3.6 ("/48 Prefix Mapping") example, fd01:0203:0405:0001:0000:0000:0000:1234/112 (specification per ip addr) would become 2001:0db8:0001:0000:0000:0000:d550:1234.

Not everybody runs exclusively on EUI64-SLAAC / PRIVACY addresses :)

net/ipv6/netfilter/ip6t_NPT.c line 125

Quoted 3 lines
net/ipv6/netfilter/ip6t_NPT.c new file +3 -0
+static struct xt_target ip6t_npt_target_reg[] __read_mostly = {
+	{
+		.name		= "SNPT",

IETF did quite a job again... NPT as an acronym is quite close to NAPT - too close.
Since it's essentially NETMAP, having something in that ballpark may seem more fitting. NPMAP? (Translation is mapping - henceforh "Network Prefix Mapping")

I would hint towards choosing a different name; the P in NPT may be (mis)understood as port (due to the common "NAPT") keyword.

net/ipv6/netfilter/ip6t_NPT.c line 132

Quoted 7 lines
net/ipv6/netfilter/ip6t_NPT.c new file +7 -0
+		.target		= ip6t_snpt_tg,
+		.targetsize	= sizeof(struct ip6t_npt_tginfo),
+		.checkentry	= ip6t_npt_checkentry,
+		.family		= NFPROTO_IPV6,
+		.hooks		= (1 << NF_INET_LOCAL_IN) |
+				  (1 << NF_INET_POST_ROUTING),
+		.me		= THIS_MODULE,

Should perhaps a .table = "mangle" be added?

Are any tricks on the userspace side needed to use SNPT/SNPMAP? Since I spot no code telling conntrack about the address mingling, one would have to use -j CT --notrack or the rawpost table, like it's done for RAWSNAT in xtables-addons, would he not?

#56 lore raw

Re: [PATCH 19/19] netfilter: ip6tables: add stateless IPv6-to-IPv6 Network Prefix Translation target

Quoted 11 lines · Jan Engelhardt

net/ipv6/netfilter/Kconfig config IP6_NF_TARGET_REDIRECT · line 185

Quoted 6 lines · On Thursday 2012-08-09 22:09, [email protected] wrote:
net/ipv6/netfilter/Kconfig +6 -0
+config IP6_NF_TARGET_NPT
+	tristate "NPT (Network Prefix translation) target support"
+	depends on NETFILTER_ADVANCED
+	help
+	  This option adda `SNPT' and `DNPT' target, which perform stateless
+	  IPv6-to-IPv6 Network Prefix Translation (RFC 6296).

Fixes/suggestion in the help text (near "adda" and subsequent).

Quoted 6 lines

config IP6_NF_TARGET_NPT
tristate "NPT (Network Prefix translation) target support" depends on NETFILTER_ADVANCED
---help---
This option adds the "SNPT" and "DNPT" targets, which perform stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296.

Thanks, changes.

Quoted 8 lines
Quoted 7 lines

+/*
+ * Copyright (c) 2011, 2012 Patrick McHardy <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */

Quoted 5 lines

GNU sometimes has a strange way of expressing their (C) lines, listing all years separately, as if "1989-1991,1994-1999,2001-2005" was not sufficient. In your case, would "2011-2012" work?

Any objection to adding a "(or later)" clause to the set?

Yeah this is a stupid habit that doesn't matter anyway, in all jurisdictions I care about copyright duration is based on the lifetime of the author. I'll try to find out whether just adding a copyright statement without any specific year would be fine for my purposes.

Quoted 12 lines

net/ipv6/netfilter/ip6t_NPT.c line 43

Quoted 8 lines
net/ipv6/netfilter/ip6t_NPT.c new file +8 -0
+static int ip6t_npt_checkentry(const struct xt_tgchk_param *par)
+{
+	struct ip6t_npt_tginfo *npt = par->targinfo;
+	__sum16 src_sum = 0, dst_sum = 0;
+	unsigned int i;
+
+	if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64)
+		return -EINVAL;

While the RFC probably only specifies masks up to /64, the general algorithm is sustainable up to at least /96.

Quoted 5 lines

Extending the RFC's section 3.6 ("/48 Prefix Mapping") example, fd01:0203:0405:0001:0000:0000:0000:1234/112 (specification per ip addr) would become 2001:0db8:0001:0000:0000:0000:d550:1234.

Not everybody runs exclusively on EUI64-SLAAC / PRIVACY addresses :)

I'll think about it. If you want to send a patch, please go ahead ;)

Quoted 9 lines

net/ipv6/netfilter/ip6t_NPT.c line 125

Quoted 3 lines
net/ipv6/netfilter/ip6t_NPT.c new file +3 -0
+static struct xt_target ip6t_npt_target_reg[] __read_mostly = {
+	{
+		.name		= "SNPT",

IETF did quite a job again... NPT as an acronym is quite close to NAPT - too close.
Since it's essentially NETMAP, having something in that ballpark may seem more fitting. NPMAP? (Translation is mapping - henceforh "Network Prefix Mapping")

So we'd have SNPMAP and DNPMAP. I like NPMAP, but SNPMAP and DNPMAP don't sound that much better, so I think I prefer keeping the currently used abrevation of Network Prefix Translation. I don't care much though.

Quoted 3 lines

I would hint towards choosing a different name; the P in NPT may be (mis)understood as port (due to the common "NAPT") keyword.

Well, I think people using computers are used to tons of similar sounding acronyms and abrevations. They'll manage ;)

Quoted 9 lines

net/ipv6/netfilter/ip6t_NPT.c line 132

Quoted 7 lines
net/ipv6/netfilter/ip6t_NPT.c new file +7 -0
+		.target		= ip6t_snpt_tg,
+		.targetsize	= sizeof(struct ip6t_npt_tginfo),
+		.checkentry	= ip6t_npt_checkentry,
+		.family		= NFPROTO_IPV6,
+		.hooks		= (1 << NF_INET_LOCAL_IN) |
+				  (1 << NF_INET_POST_ROUTING),
+		.me		= THIS_MODULE,

Should perhaps a .table = "mangle" be added?

I've been proposing to lift the mangle restriction on all targets for years. Basically the only special thing about the mangle table is rerouting on mark changes. Everything else works just fine in other tables (with NAT being somewhat special as well), even marking packets if you don't need rerouting, its even more performant in that case since no extra routing lookups need to be done. So I don't see a reason to impose artificial limitations.

Quoted 4 lines

Are any tricks on the userspace side needed to use SNPT/SNPMAP? Since I spot no code telling conntrack about the address mingling, one would have to use -j CT --notrack or the rawpost table, like it's done for RAWSNAT in xtables-addons, would he not?

Yes, if connection tracking is used (which is not necessary of course) its best to exclude the translated packets from tracking. There's actually a lot of potential for improvement here. One thing is telling connection tracking, if its used, about the translations, so it can properly track packets. Another thing is, with stateless translation you still need ALGs to take care of addresses in layer 7 protocols. I've been thinking about how to make the existing NAT helpers work without conntrack and NAT, but its not easy and requires a lot of restructuring of the existing code. Its something we can still add later, its something that just affects the kernel.

#57 lore raw
In reply to [email protected]
Quoted 7 lines · [email protected] writes:

The following patches contain an updated version of IPv6 NAT against Linus' current tree.

The series is organized as follows:

- Patches 01-03 contain bugfixes for SIP helper bugs/regressions present in the current kernel

Why not just delete this code? The current best practices are to disable ALGs for SIP. To the point in some circles people recommend running SIP over TLS to avoid over helpful NAT ALGs.

Eric

#58 lore raw
Quoted 5 lines · Eric W. Biederman
Quoted 3 lines · [email protected] writes:

The following patches contain an updated version of IPv6 NAT against Linus' current tree.

Quoted 8 lines
Quoted 4 lines

The series is organized as follows:

- Patches 01-03 contain bugfixes for SIP helper bugs/regressions present in the current kernel

Why not just delete this code? The current best practices are to disable ALGs for SIP. To the point in some circles people recommend running SIP over TLS to avoid over helpful NAT ALGs.

And where can I read up on these best practices and how well they work?

In any case, these patches are all for the connection tracking helper,
which is needed unless you want to open up your firewall for every possible RTP source, in which case you can simply disable it. Some people are also using it to proritize RTP streams without any filtering.

Also, even if the NAT helper would not mangle packets, it is still needed to adjust expectations. so incoming connections can go to the correct destination. That is, direct RTP connections between two endpoints
that didn't have any direct signalling communication before

You can of course also proxy everything through your SIP provider (including internal calls) and/or use STUN (which is unreliable under Linux). I prefer not to.

#59 lore raw
In reply to [email protected]

Hi Patrick,

Quoted 7 lines · On Thu, Aug 09, 2012 at 10:08:44PM +0200, [email protected] wrote:

The following patches contain an updated version of IPv6 NAT against Linus' current tree.

The series is organized as follows:

- Patches 01-03 contain bugfixes for SIP helper bugs/regressions present in the current kernel

Thanks, I'll pass these to David.

I have also two more to fixes to oopses regarding SIP. I'm expecting one user to finally confirm that their issues are fixed.

Quoted 25 lines

- Patches 04-06 improve conntrack fragmentation handling, the IPv6 parts are also a precondition for IPv6 NAT

- Patches 07 and 08 prepare the current NAT code for conversion to an address family independant core, but contain no functional changes

- Patch 09 adds the address family independant NAT core and converts the existing IPv4-only NAT code to an AF-specific module

- Patches 10 and 11 add some infrastructure for IPv6 NAT

- Patch 12 adds IPv6 NAT support

- Patches 13-15 add IPv6 specific NAT targets

- Patches 16-19 add some IPv6-capable ports of existing NAT helpers

- Patch 19 is independant of the IPv6 NAT code and adds support for stateless IPv6 prefix translation, just to relieve my conscience ;)

Since the last posting numerous bugs have been fixed, I don't remember all of them, the more important ones include:

Quoted 7 lines

- automatic NAT module loading in ctnetlink

- address selection when mapping to IPv6 ranges

- handling of IPv6 fragments

- NAT handling of ICMPv6 error messages

Thanks, I was keeping the previous patchset in one branch:

http://1984.lsi.us.es/git/nf-next/log/?h=nf-nat4

You can also find forward ports of netlink-mmap (from Florian Westpal) and one for nftables from myself in that tree.

Quoted 2 lines

Besides implementing IPv6 NAT, there are no known bugs left. Userspace patches will follow shortly.

We have this branch for iptables IPv6 NAT:

http://git.netfilter.org/cgi-bin/gitweb.cgi?p=iptables.git;a=shortlog;h=refs/heads/nf-nat

Let me know if you're OK with these.

#60 lore raw
Quoted 8 lines · Pablo Neira Ayuso

Hi Patrick,

Quoted 5 lines · On Thu, Aug 09, 2012 at 10:08:44PM +0200, [email protected] wrote:

The following patches contain an updated version of IPv6 NAT against Linus' current tree.

The series is organized as follows:

Quoted 7 lines
Quoted 2 lines

- Patches 01-03 contain bugfixes for SIP helper bugs/regressions present in the current kernel

Thanks, I'll pass these to David.

I have also two more to fixes to oopses regarding SIP. I'm expecting one user to finally confirm that their issues are fixed.

If you want me to have a look as well, just send me an URL or the patches.

Quoted 31 lines
Quoted 31 lines

- Patches 04-06 improve conntrack fragmentation handling, the IPv6 parts are also a precondition for IPv6 NAT

- Patches 07 and 08 prepare the current NAT code for conversion to an address family independant core, but contain no functional changes

- Patch 09 adds the address family independant NAT core and converts the existing IPv4-only NAT code to an AF-specific module

- Patches 10 and 11 add some infrastructure for IPv6 NAT

- Patch 12 adds IPv6 NAT support

- Patches 13-15 add IPv6 specific NAT targets

- Patches 16-19 add some IPv6-capable ports of existing NAT helpers

- Patch 19 is independant of the IPv6 NAT code and adds support for stateless IPv6 prefix translation, just to relieve my conscience ;)

Since the last posting numerous bugs have been fixed, I don't remember all of them, the more important ones include:

- automatic NAT module loading in ctnetlink

- address selection when mapping to IPv6 ranges

- handling of IPv6 fragments

Quoted 8 lines
Quoted 1 line

- NAT handling of ICMPv6 error messages

Thanks, I was keeping the previous patchset in one branch:

http://1984.lsi.us.es/git/nf-next/log/?h=nf-nat4

You can also find forward ports of netlink-mmap (from Florian Westpal) and one for nftables from myself in that tree.

Thanks, Florian just pointed me to these trees. Will have a look at the changes compared to my tree. I'm actually intending to finish up the mmaped netlink work once I'm done with IPv6 NAT.

Quoted 8 lines
Quoted 2 lines

Besides implementing IPv6 NAT, there are no known bugs left. Userspace patches will follow shortly.

We have this branch for iptables IPv6 NAT:

http://git.netfilter.org/cgi-bin/gitweb.cgi?p=iptables.git;a=shortlog;h=refs/heads/nf-nat

Let me know if you're OK with these.

For now I'll just accumulate feedback and will incorporate it into my tree. I'll also diff them against your tree and will then send the final result once all feedback/fixes are included.

#62 lore raw
Quoted 9 lines · Pablo Neira Ayuso

On Thu, Aug 09, 2012 at 10:08:44PM +0200, [email protected] wrote:
[...]

Quoted 1 line

- Patches 16-19 add some IPv6-capable ports of existing NAT helpers

There was one for IRC also, did it get lost?

I also made TFTP, it was more or less trivial, you can find it here:

http://1984.lsi.us.es/git/nf-next/commit/?h=nf-nat4&id=ac2a06ab790386c8c8333dbf84584fc3f80fcdc5

I've already added your IRC and TFTP patches to my tree. Will send the latest version later today.

#63 lore raw
In reply to [email protected]
Quoted 2 lines · On 09. aug. 2012 22:08, [email protected] wrote:

The following patches contain an updated version of IPv6 NAT against Linus' current tree.

Hmmm. Looking in my crystal ball (hi #ipv6!), I predict that if this lands in mainline - and thus in consumer CPE/routers eventually - many ISP's will have little incentive to actually implement assigning of blocks to their consumer users like they "have to" today.

We have this wonderful chance of fixing a major problem with todays internet, but now we are going down this very slippery slope.

I do need this code for a experimental project myself, and acknowledge there may be some valid use cases, but I do not like the global implications one bit.

At least some big fat warnings please?

:-(

#64 lore raw
Quoted 9 lines · Andre Tomt
Quoted 2 lines · On 09. aug. 2012 22:08, [email protected] wrote:

The following patches contain an updated version of IPv6 NAT against Linus' current tree.

Hmmm. Looking in my crystal ball (hi #ipv6!), I predict that if this lands in mainline - and thus in consumer CPE/routers eventually - many ISP's will have little incentive to actually implement assigning of blocks to their consumer users like they "have to" today.

Quoted 8 lines

We have this wonderful chance of fixing a major problem with todays internet, but now we are going down this very slippery slope.

I do need this code for a experimental project myself, and acknowledge there may be some valid use cases, but I do not like the global implications one bit.

At least some big fat warnings please?

Clarification: This is about the NAT66 port-based 1:n NAT targets.

#65 lore raw
Quoted 13 lines · Andre Tomt
Quoted 12 lines · Andre Tomt
Quoted 2 lines · On 09. aug. 2012 22:08, [email protected] wrote:

The following patches contain an updated version of IPv6 NAT against Linus' current tree.

Hmmm. Looking in my crystal ball (hi #ipv6!), I predict that if this lands in mainline - and thus in consumer CPE/routers eventually - many ISP's will have little incentive to actually implement assigning of blocks to their consumer users like they "have to" today.

We have this wonderful chance of fixing a major problem with todays internet, but now we are going down this very slippery slope.

Quoted 7 lines
Quoted 5 lines

I do need this code for a experimental project myself, and acknowledge there may be some valid use cases, but I do not like the global implications one bit.

At least some big fat warnings please?

Clarification: This is about the NAT66 port-based 1:n NAT targets.

We can certainly add a warning to the Kconfig text or (better) the iptables manpage. But only a very small percentage of people who might end up (unknowingly) using this will ever see them.

Feel free to send a patch though.

#66 lore raw
In reply to Andre Tomt
Quoted 8 lines · Andre Tomt
Quoted 2 lines · On 09. aug. 2012 22:08, [email protected] wrote:

The following patches contain an updated version of IPv6 NAT against Linus' current tree.

Hmmm. Looking in my crystal ball (hi #ipv6!), I predict that if this lands in mainline - and thus in consumer CPE/routers eventually - many ISP's will have little incentive to actually implement assigning of blocks to their consumer users like they "have to" today.

I think the brokenness of IPv6 ND is still sufficient incentive to provide the customer with a prefix. Whether this prefix is constant over an extended period of time is a separate question. Even among consumers, preferences vary widely.

Signature · 1 line
Florian Weimer / Red Hat Product Security Team