diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c index fbcc7ce..75cdc51 100644 --- a/net/netfilter/xt_physdev.c +++ b/net/netfilter/xt_physdev.c @@ -23,6 +23,23 @@ MODULE_DESCRIPTION("iptables bridge physical device match module"); MODULE_ALIAS("ipt_physdev"); MODULE_ALIAS("ip6t_physdev"); +static inline bool +ifgroup_match_in(u_int32_t ingroup, + const struct xt_physdev_info *info) +{ + + return ((ingroup & info->ingroupmask) == info->ingroup) ^ + ((info->invert & XT_PHYSDEV_OP_GROUPIN) == XT_PHYSDEV_OP_GROUPIN); +} + +static inline bool +ifgroup_match_out(u_int32_t outgroup, + const struct xt_physdev_info *info) +{ + return ((outgroup & info->outgroupmask) == info->outgroup) ^ + ((info->invert & XT_PHYSDEV_OP_GROUPOUT) == XT_PHYSDEV_OP_GROUPOUT); +} + static int match(const struct sk_buff *skb, const struct net_device *in, @@ -38,6 +55,7 @@ match(const struct sk_buff *skb, const struct xt_physdev_info *info = matchinfo; unsigned int ret; const char *indev, *outdev; + u_int32_t ingroup, outgroup; struct nf_bridge_info *nf_bridge; /* Not a bridged IP packet or no info available yet: @@ -60,6 +78,12 @@ match(const struct sk_buff *skb, if ((info->bitmask & XT_PHYSDEV_OP_OUT) && !(info->invert & XT_PHYSDEV_OP_OUT)) return NOMATCH; + if ((info->bitmask & XT_PHYSDEV_OP_GROUPIN) && + !(info->invert & XT_PHYSDEV_OP_GROUPIN)) + return NOMATCH; + if ((info->bitmask & XT_PHYSDEV_OP_GROUPOUT) && + !(info->invert & XT_PHYSDEV_OP_GROUPOUT)) + return NOMATCH; return MATCH; } @@ -75,6 +99,18 @@ match(const struct sk_buff *skb, (!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT)))) return NOMATCH; + if (info->bitmask & XT_PHYSDEV_OP_GROUPIN) { + ingroup = nf_bridge->physindev ? nf_bridge->physindev->ifgroup : -1; + if (!ifgroup_match_in(ingroup, info)) + return NOMATCH; + } + + if (info->bitmask & XT_PHYSDEV_OP_GROUPOUT) { + outgroup = nf_bridge->physoutdev ? nf_bridge->physoutdev->ifgroup : -1; + if (!ifgroup_match_out(outgroup, info)) + return NOMATCH; + } + if (!(info->bitmask & XT_PHYSDEV_OP_IN)) goto match_outdev; indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; @@ -114,6 +150,7 @@ checkentry(const char *tablename, info->bitmask & ~XT_PHYSDEV_OP_MASK) return 0; if (brnf_deferred_hooks == 0 && + info->bitmask & XT_PHYSDEV_OP_GROUPOUT && info->bitmask & XT_PHYSDEV_OP_OUT && (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) || info->invert & XT_PHYSDEV_OP_BRIDGED) &&