Commit dacfd283 authored by Bart De Schuymer's avatar Bart De Schuymer Committed by David S. Miller

[NETFILTER]: Add ipt_physdev extension.

parent 103ad90e
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#define BRNF_PKT_TYPE 0x01 #define BRNF_PKT_TYPE 0x01
#define BRNF_BRIDGED_DNAT 0x02 #define BRNF_BRIDGED_DNAT 0x02
#define BRNF_DONT_TAKE_PARENT 0x04 #define BRNF_DONT_TAKE_PARENT 0x04
#define BRNF_BRIDGED 0x08
enum nf_br_hook_priorities { enum nf_br_hook_priorities {
NF_BR_PRI_FIRST = INT_MIN, NF_BR_PRI_FIRST = INT_MIN,
......
...@@ -5,11 +5,16 @@ ...@@ -5,11 +5,16 @@
#include <linux/if.h> #include <linux/if.h>
#endif #endif
#define IPT_PHYSDEV_OP_MATCH_IN 0x01 #define IPT_PHYSDEV_OP_IN 0x01
#define IPT_PHYSDEV_OP_MATCH_OUT 0x02 #define IPT_PHYSDEV_OP_OUT 0x02
#define IPT_PHYSDEV_OP_BRIDGED 0x04
#define IPT_PHYSDEV_OP_ISIN 0x08
#define IPT_PHYSDEV_OP_ISOUT 0x10
#define IPT_PHYSDEV_OP_MASK (0x20 - 1)
struct ipt_physdev_info { struct ipt_physdev_info {
u_int8_t invert; u_int8_t invert;
u_int8_t bitmask;
char physindev[IFNAMSIZ]; char physindev[IFNAMSIZ];
char in_mask[IFNAMSIZ]; char in_mask[IFNAMSIZ];
char physoutdev[IFNAMSIZ]; char physoutdev[IFNAMSIZ];
......
...@@ -348,6 +348,8 @@ static unsigned int br_nf_forward(unsigned int hook, struct sk_buff **pskb, ...@@ -348,6 +348,8 @@ static unsigned int br_nf_forward(unsigned int hook, struct sk_buff **pskb,
if (skb->pkt_type == PACKET_OTHERHOST) { if (skb->pkt_type == PACKET_OTHERHOST) {
skb->pkt_type = PACKET_HOST; skb->pkt_type = PACKET_HOST;
nf_bridge->mask |= BRNF_PKT_TYPE; nf_bridge->mask |= BRNF_PKT_TYPE;
/* The physdev module checks on this */
nf_bridge->mask |= BRNF_BRIDGED;
} }
nf_bridge->physoutdev = skb->dev; nf_bridge->physoutdev = skb->dev;
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ipt_physdev.h> #include <linux/netfilter_ipv4/ipt_physdev.h>
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_bridge.h>
#define MATCH 1
#define NOMATCH 0
static int static int
match(const struct sk_buff *skb, match(const struct sk_buff *skb,
...@@ -25,29 +28,62 @@ match(const struct sk_buff *skb, ...@@ -25,29 +28,62 @@ match(const struct sk_buff *skb,
/* Not a bridged IP packet or no info available yet: /* Not a bridged IP packet or no info available yet:
* LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if * LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
* the destination device will be a bridge. */ * the destination device will be a bridge. */
if (!(nf_bridge = skb->nf_bridge)) if (!(nf_bridge = skb->nf_bridge)) {
return 1; /* Return MATCH if the invert flags of the used options are on */
if ((info->bitmask & IPT_PHYSDEV_OP_BRIDGED) &&
!(info->invert & IPT_PHYSDEV_OP_BRIDGED))
return NOMATCH;
if ((info->bitmask & IPT_PHYSDEV_OP_ISIN) &&
!(info->invert & IPT_PHYSDEV_OP_ISIN))
return NOMATCH;
if ((info->bitmask & IPT_PHYSDEV_OP_ISOUT) &&
!(info->invert & IPT_PHYSDEV_OP_ISOUT))
return NOMATCH;
if ((info->bitmask & IPT_PHYSDEV_OP_IN) &&
!(info->invert & IPT_PHYSDEV_OP_IN))
return NOMATCH;
if ((info->bitmask & IPT_PHYSDEV_OP_OUT) &&
!(info->invert & IPT_PHYSDEV_OP_OUT))
return NOMATCH;
return MATCH;
}
indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; /* This only makes sense in the FORWARD and POSTROUTING chains */
outdev = nf_bridge->physoutdev ? if ((info->bitmask & IPT_PHYSDEV_OP_BRIDGED) &&
nf_bridge->physoutdev->name : nulldevname; (!!(nf_bridge->mask & BRNF_BRIDGED) ^
!(info->invert & IPT_PHYSDEV_OP_BRIDGED)))
return NOMATCH;
if ((info->bitmask & IPT_PHYSDEV_OP_ISIN &&
(!nf_bridge->physindev ^ !!(info->invert & IPT_PHYSDEV_OP_ISIN))) ||
(info->bitmask & IPT_PHYSDEV_OP_ISOUT &&
(!nf_bridge->physoutdev ^ !!(info->invert & IPT_PHYSDEV_OP_ISOUT))))
return NOMATCH;
if (!(info->bitmask & IPT_PHYSDEV_OP_IN))
goto match_outdev;
indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
ret |= (((const unsigned long *)indev)[i] ret |= (((const unsigned long *)indev)[i]
^ ((const unsigned long *)info->physindev)[i]) ^ ((const unsigned long *)info->physindev)[i])
& ((const unsigned long *)info->in_mask)[i]; & ((const unsigned long *)info->in_mask)[i];
} }
if ((ret == 0) ^ !(info->invert & IPT_PHYSDEV_OP_MATCH_IN)) if ((ret == 0) ^ !(info->invert & IPT_PHYSDEV_OP_IN))
return 0; return NOMATCH;
match_outdev:
if (!(info->bitmask & IPT_PHYSDEV_OP_OUT))
return MATCH;
outdev = nf_bridge->physoutdev ?
nf_bridge->physoutdev->name : nulldevname;
for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
ret |= (((const unsigned long *)outdev)[i] ret |= (((const unsigned long *)outdev)[i]
^ ((const unsigned long *)info->physoutdev)[i]) ^ ((const unsigned long *)info->physoutdev)[i])
& ((const unsigned long *)info->out_mask)[i]; & ((const unsigned long *)info->out_mask)[i];
} }
return (ret != 0) ^ !(info->invert & IPT_PHYSDEV_OP_MATCH_OUT); return (ret != 0) ^ !(info->invert & IPT_PHYSDEV_OP_OUT);
} }
static int static int
...@@ -57,9 +93,13 @@ checkentry(const char *tablename, ...@@ -57,9 +93,13 @@ checkentry(const char *tablename,
unsigned int matchsize, unsigned int matchsize,
unsigned int hook_mask) unsigned int hook_mask)
{ {
const struct ipt_physdev_info *info = matchinfo;
if (matchsize != IPT_ALIGN(sizeof(struct ipt_physdev_info))) if (matchsize != IPT_ALIGN(sizeof(struct ipt_physdev_info)))
return 0; return 0;
if (!(info->bitmask & IPT_PHYSDEV_OP_MASK) ||
info->bitmask & ~IPT_PHYSDEV_OP_MASK)
return 0;
return 1; return 1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment