[PATCH] selective IP NATing on a bridge (like NETMAP)

Carl-Daniel Hailfinger <[email protected]>
Newsgroups gmane.linux.network.bridge.ebtables.devel
Message-ID <[email protected]>
Bart De Schuymer schrieb:
> Op za, 26-03-2005 te 15:11 +0100, schreef Carl-Daniel Hailfinger:
> 
>>arptables -A FORWARD -i eth1 -o eth0 -s 192.168.101.0/24 \
>>  -d 192.168.101.0/24 -p Reply -j mangle \
>>  --mangle-ip-s 192.168.100.0/24 --mangle-ip-d 192.168.100.0/24
>>
>>However, it seems the mangle target doesn't like source or destination
>>to be a network address. The documentation doesn't mention this
>>possibility, either. Looking at the kernel code, it seems I can patch
>>it to fit my needs, but I'd have to change struct arpt_mangle.
> 
> Interesting idea. Does iptables allow something like this?

Yes, with the NETMAP target.


>>Proposed patch follows, please criticize it.
>> [...]
> 
> This change will need to be done so that backwards compatibility
> is maintained.
> I guess a versioning system like the one introduced in iptables
> could be used, but I don't thinks that's worth it, since we only
> have one target. I think the approach mentioned in
> http://lists.netfilter.org/pipermail/netfilter-devel/2004-November/017522.html
> is the one to take. The arpt_mangle struct has a flags field.

Yes, but the new flags I introduce take up all 8 bits of the flags
field (and may need more in the future), so I decided to check the
length. The patch is now modeled after the current version of
ipt_MARK.


>>I plan to extend the patch to also allow MAC masks for those who
>>might be crazy enough to need that.
> 
> Yes, it's better to provide all options in one patch.

Done.

Please find two patches attached (to avoid whitespace mangling):
- lindent of the files I worked on
- functional changes only.
Patches are against 2.6.15-rc5 and are compile tested only.

What do you think?


Regards,
Carl-Daniel
-- 
http://www.hailfinger.org/
arptables_Lindent.diff (text/x-patch, 3.7 KB)
diff -urp linux-2.6.15-rc5/include/linux/netfilter_arp/arpt_mangle.h linux-2.6.15-rc5-modified/include/linux/netfilter_arp/arpt_mangle.h
--- linux-2.6.15-rc5/include/linux/netfilter_arp/arpt_mangle.h	2005-12-04 06:10:42.000000000 +0100
+++ linux-2.6.15-rc5-modified/include/linux/netfilter_arp/arpt_mangle.h	2005-12-19 03:35:34.000000000 +0100
@@ -3,8 +3,7 @@
 #include <linux/netfilter_arp/arp_tables.h>
 
 #define ARPT_MANGLE_ADDR_LEN_MAX sizeof(struct in_addr)
-struct arpt_mangle
-{
+struct arpt_mangle {
 	char src_devaddr[ARPT_DEV_ADDR_LEN_MAX];
 	char tgt_devaddr[ARPT_DEV_ADDR_LEN_MAX];
 	union {
@@ -23,4 +22,4 @@ struct arpt_mangle
 #define ARPT_MANGLE_TIP 0x08
 #define ARPT_MANGLE_MASK 0x0f
 
-#endif /* _ARPT_MANGLE_H */
+#endif				/* _ARPT_MANGLE_H */
diff -urp linux-2.6.15-rc5/net/ipv4/netfilter/arpt_mangle.c linux-2.6.15-rc5-modified/net/ipv4/netfilter/arpt_mangle.c
--- linux-2.6.15-rc5/net/ipv4/netfilter/arpt_mangle.c	2005-12-04 06:10:42.000000000 +0100
+++ linux-2.6.15-rc5-modified/net/ipv4/netfilter/arpt_mangle.c	2005-12-19 03:31:53.000000000 +0100
@@ -7,9 +7,10 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Bart De Schuymer <[email protected]>");
 MODULE_DESCRIPTION("arptables arp payload mangle target");
 
-static unsigned int
-target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in,
-   const struct net_device *out, const void *targinfo, void *userinfo)
+static unsigned int target(struct sk_buff **pskb, unsigned int hooknum,
+			   const struct net_device *in,
+			   const struct net_device *out, const void *targinfo,
+			   void *userinfo)
 {
 	const struct arpt_mangle *mangle = targinfo;
 	struct arphdr *arp;
@@ -35,37 +36,37 @@ target(struct sk_buff **pskb, unsigned i
 	/* We assume that pln and hln were checked in the match */
 	if (mangle->flags & ARPT_MANGLE_SDEV) {
 		if (ARPT_DEV_ADDR_LEN_MAX < hln ||
-		   (arpptr + hln > (**pskb).tail))
+		    (arpptr + hln > (**pskb).tail))
 			return NF_DROP;
 		memcpy(arpptr, mangle->src_devaddr, hln);
 	}
 	arpptr += hln;
 	if (mangle->flags & ARPT_MANGLE_SIP) {
 		if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
-		   (arpptr + pln > (**pskb).tail))
+		    (arpptr + pln > (**pskb).tail))
 			return NF_DROP;
 		memcpy(arpptr, &mangle->u_s.src_ip, pln);
 	}
 	arpptr += pln;
 	if (mangle->flags & ARPT_MANGLE_TDEV) {
 		if (ARPT_DEV_ADDR_LEN_MAX < hln ||
-		   (arpptr + hln > (**pskb).tail))
+		    (arpptr + hln > (**pskb).tail))
 			return NF_DROP;
 		memcpy(arpptr, mangle->tgt_devaddr, hln);
 	}
 	arpptr += hln;
 	if (mangle->flags & ARPT_MANGLE_TIP) {
 		if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
-		   (arpptr + pln > (**pskb).tail))
+		    (arpptr + pln > (**pskb).tail))
 			return NF_DROP;
 		memcpy(arpptr, &mangle->u_t.tgt_ip, pln);
 	}
 	return mangle->target;
 }
 
-static int
-checkentry(const char *tablename, const struct arpt_entry *e, void *targinfo,
-   unsigned int targinfosize, unsigned int hook_mask)
+static int checkentry(const char *tablename, const struct arpt_entry *e,
+		      void *targinfo, unsigned int targinfosize,
+		      unsigned int hook_mask)
 {
 	const struct arpt_mangle *mangle = targinfo;
 
@@ -74,17 +75,16 @@ checkentry(const char *tablename, const 
 		return 0;
 
 	if (mangle->target != NF_DROP && mangle->target != NF_ACCEPT &&
-	   mangle->target != ARPT_CONTINUE)
+	    mangle->target != ARPT_CONTINUE)
 		return 0;
 	return 1;
 }
 
-static struct arpt_target arpt_mangle_reg
-= {
-        .name		= "mangle",
-        .target		= target,
-        .checkentry	= checkentry,
-        .me		= THIS_MODULE,
+static struct arpt_target arpt_mangle_reg = {
+	.name = "mangle",
+	.target = target,
+	.checkentry = checkentry,
+	.me = THIS_MODULE,
 };
 
 static int __init init(void)
arptables_mask2.diff (text/x-patch, 7.3 KB)
diff -urp linux-2.6.15-rc5-whitespace/include/linux/netfilter_arp/arpt_mangle.h linux-2.6.15-rc5-modified/include/linux/netfilter_arp/arpt_mangle.h
--- linux-2.6.15-rc5-whitespace/include/linux/netfilter_arp/arpt_mangle.h	2005-12-19 03:35:34.000000000 +0100
+++ linux-2.6.15-rc5-modified/include/linux/netfilter_arp/arpt_mangle.h	2005-12-19 04:19:25.000000000 +0100
@@ -3,7 +3,7 @@
 #include <linux/netfilter_arp/arp_tables.h>
 
 #define ARPT_MANGLE_ADDR_LEN_MAX sizeof(struct in_addr)
-struct arpt_mangle {
+struct arpt_mangle_v0 {
 	char src_devaddr[ARPT_DEV_ADDR_LEN_MAX];
 	char tgt_devaddr[ARPT_DEV_ADDR_LEN_MAX];
 	union {
@@ -16,10 +16,38 @@ struct arpt_mangle {
 	int target;
 };
 
+struct arpt_mangle_v1 {
+	char src_devaddr[ARPT_DEV_ADDR_LEN_MAX];
+	char src_devmask[ARPT_DEV_ADDR_LEN_MAX];
+	char tgt_devaddr[ARPT_DEV_ADDR_LEN_MAX];
+	char tgt_devmask[ARPT_DEV_ADDR_LEN_MAX];
+	union {
+		struct in_addr src_ip;
+	} u_s;
+	union {
+		struct in_addr src_ipmask;
+	} u_sm;
+	union {
+		struct in_addr tgt_ip;
+	} u_t;
+	union {
+		struct in_addr tgt_ipmask;
+	} u_tm;
+	u_int32_t flags;
+	int target;
+};
+
 #define ARPT_MANGLE_SDEV 0x01
 #define ARPT_MANGLE_TDEV 0x02
 #define ARPT_MANGLE_SIP 0x04
 #define ARPT_MANGLE_TIP 0x08
 #define ARPT_MANGLE_MASK 0x0f
 
+#define ARPT_BITREPLACE_SDEV 0x10
+#define ARPT_BITREPLACE_TDEV 0x20
+#define ARPT_BITREPLACE_SIP 0x40
+#define ARPT_BITREPLACE_TIP 0x80
+#define ARPT_BITREPLACE_MASK 0xf0
+#define ARPT_BITREPLACE_SHIFT 4
+
 #endif				/* _ARPT_MANGLE_H */
diff -urp linux-2.6.15-rc5-whitespace/net/ipv4/netfilter/arpt_mangle.c linux-2.6.15-rc5-modified/net/ipv4/netfilter/arpt_mangle.c
--- linux-2.6.15-rc5-whitespace/net/ipv4/netfilter/arpt_mangle.c	2005-12-19 03:31:53.000000000 +0100
+++ linux-2.6.15-rc5-modified/net/ipv4/netfilter/arpt_mangle.c	2005-12-19 04:30:29.000000000 +0100
@@ -7,12 +7,12 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Bart De Schuymer <[email protected]>");
 MODULE_DESCRIPTION("arptables arp payload mangle target");
 
-static unsigned int target(struct sk_buff **pskb, unsigned int hooknum,
-			   const struct net_device *in,
-			   const struct net_device *out, const void *targinfo,
-			   void *userinfo)
+static unsigned int target_v0(struct sk_buff **pskb, unsigned int hooknum,
+			      const struct net_device *in,
+			      const struct net_device *out,
+			      const void *targinfo, void *userinfo)
 {
-	const struct arpt_mangle *mangle = targinfo;
+	const struct arpt_mangle_v0 *mangle = targinfo;
 	struct arphdr *arp;
 	unsigned char *arpptr;
 	int pln, hln;
@@ -64,11 +64,97 @@ static unsigned int target(struct sk_buf
 	return mangle->target;
 }
 
-static int checkentry(const char *tablename, const struct arpt_entry *e,
-		      void *targinfo, unsigned int targinfosize,
-		      unsigned int hook_mask)
+static unsigned int target_v1(struct sk_buff **pskb, unsigned int hooknum,
+			      const struct net_device *in,
+			      const struct net_device *out,
+			      const void *targinfo, void *userinfo)
 {
-	const struct arpt_mangle *mangle = targinfo;
+	const struct arpt_mangle_v1 *mangle = targinfo;
+	struct arphdr *arp;
+	unsigned char *arpptr;
+	int pln, hln;
+	unsigned char *addr;
+	unsigned char *mask;
+	unsigned int i;
+
+	if (skb_shared(*pskb) || skb_cloned(*pskb)) {
+		struct sk_buff *nskb;
+
+		nskb = skb_copy(*pskb, GFP_ATOMIC);
+		if (!nskb)
+			return NF_DROP;
+		if ((*pskb)->sk)
+			skb_set_owner_w(nskb, (*pskb)->sk);
+		kfree_skb(*pskb);
+		*pskb = nskb;
+	}
+
+	arp = (*pskb)->nh.arph;
+	arpptr = (*pskb)->nh.raw + sizeof(*arp);
+	pln = arp->ar_pln;
+	hln = arp->ar_hln;
+	/* We assume that pln and hln were checked in the match */
+	if (mangle->flags & ARPT_BITREPLACE_SDEV) {
+		if (ARPT_DEV_ADDR_LEN_MAX < hln ||
+		    (arpptr + hln > (**pskb).tail))
+			return NF_DROP;
+		addr = (unsigned char *)&mangle->src_devaddr;
+		mask = (unsigned char *)&mangle->src_devmask;
+		for (i = 0; i < hln; i++)
+			arpptr[i] =
+			    (arpptr[i] & ~mask[i]) | (addr[i] & mask[i]);
+
+		memcpy(arpptr, mangle->src_devaddr, hln);
+	}
+	arpptr += hln;
+	if (mangle->flags & ARPT_BITREPLACE_SIP) {
+		if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
+		    (arpptr + pln > (**pskb).tail))
+			return NF_DROP;
+		addr = (unsigned char *)&mangle->u_s.src_ip;
+		mask = (unsigned char *)&mangle->u_sm.src_ipmask;
+		for (i = 0; i < pln; i++)
+			arpptr[i] =
+			    (arpptr[i] & ~mask[i]) | (addr[i] & mask[i]);
+
+	}
+	arpptr += pln;
+	if (mangle->flags & ARPT_BITREPLACE_TDEV) {
+		if (ARPT_DEV_ADDR_LEN_MAX < hln ||
+		    (arpptr + hln > (**pskb).tail))
+			return NF_DROP;
+		addr = (unsigned char *)&mangle->tgt_devaddr;
+		mask = (unsigned char *)&mangle->tgt_devmask;
+		for (i = 0; i < hln; i++)
+			arpptr[i] =
+			    (arpptr[i] & ~mask[i]) | (addr[i] & mask[i]);
+		memcpy(arpptr, mangle->tgt_devaddr, hln);
+	}
+	arpptr += hln;
+	if (mangle->flags & ARPT_BITREPLACE_TIP) {
+		if (ARPT_MANGLE_ADDR_LEN_MAX < pln ||
+		    (arpptr + pln > (**pskb).tail))
+			return NF_DROP;
+		addr = (unsigned char *)&mangle->u_t.tgt_ip;
+		mask = (unsigned char *)&mangle->u_tm.tgt_ipmask;
+		for (i = 0; i < pln; i++)
+			arpptr[i] =
+			    (arpptr[i] & ~mask[i]) | (addr[i] & mask[i]);
+	}
+	return mangle->target;
+}
+
+static int checkentry_v0(const char *tablename, const struct arpt_entry *e,
+			 void *targinfo, unsigned int targinfosize,
+			 unsigned int hook_mask)
+{
+	const struct arpt_mangle_v0 *mangle = targinfo;
+
+	if (targinfosize != ARPT_ALIGN(sizeof(struct arpt_mangle_v0))) {
+		printk(KERN_WARNING "arpt_mangle: targinfosize %u != %Zu\n",
+		       targinfosize, ARPT_ALIGN(sizeof(struct arpt_mangle_v0)));
+		return 0;
+	}
 
 	if (mangle->flags & ~ARPT_MANGLE_MASK ||
 	    !(mangle->flags & ARPT_MANGLE_MASK))
@@ -80,24 +166,59 @@ static int checkentry(const char *tablen
 	return 1;
 }
 
-static struct arpt_target arpt_mangle_reg = {
+static int checkentry_v1(const char *tablename, const struct arpt_entry *e,
+			 void *targinfo, unsigned int targinfosize,
+			 unsigned int hook_mask)
+{
+	const struct arpt_mangle_v1 *mangle = targinfo;
+
+	if (targinfosize != ARPT_ALIGN(sizeof(struct arpt_mangle_v1))) {
+		printk(KERN_WARNING "arpt_mangle: targinfosize %u != %Zu\n",
+		       targinfosize, ARPT_ALIGN(sizeof(struct arpt_mangle_v1)));
+		return 0;
+	}
+
+	if (mangle->flags & ~ARPT_BITREPLACE_MASK ||
+	    !(mangle->flags & ARPT_BITREPLACE_MASK))
+		return 0;
+
+	if (mangle->target != NF_DROP && mangle->target != NF_ACCEPT &&
+	    mangle->target != ARPT_CONTINUE)
+		return 0;
+	return 1;
+}
+
+static struct arpt_target arpt_mangle_v0_reg = {
+	.name = "mangle",
+	.target = target_v0,
+	.checkentry = checkentry_v0,
+	.me = THIS_MODULE,
+};
+
+static struct arpt_target arpt_mangle_v1_reg = {
 	.name = "mangle",
-	.target = target,
-	.checkentry = checkentry,
+	.target = target_v1,
+	.checkentry = checkentry_v1,
 	.me = THIS_MODULE,
 };
 
 static int __init init(void)
 {
-	if (arpt_register_target(&arpt_mangle_reg))
-		return -EINVAL;
+	int err;
 
-	return 0;
+	err = arpt_register_target(&arpt_mangle_v0_reg);
+	if (!err) {
+		err = arpt_register_target(&arpt_mangle_v1_reg);
+		if (err)
+			arpt_unregister_target(&arpt_mangle_v0_reg);
+	}
+	return err;
 }
 
 static void __exit fini(void)
 {
-	arpt_unregister_target(&arpt_mangle_reg);
+	arpt_unregister_target(&arpt_mangle_v1_reg);
+	arpt_unregister_target(&arpt_mangle_v0_reg);
 }
 
 module_init(init);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.