[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);