Merge remote branch 'origin/iface'

This commit is contained in:
Jan Engelhardt
2010-11-03 23:58:35 +01:00
5 changed files with 101 additions and 40 deletions

View File

@@ -7,6 +7,7 @@ HEAD
--with-xtlibdir is no longer needed for ./configure in most cases --with-xtlibdir is no longer needed for ./configure in most cases
(If I still see a distro using it, I will scold you for not (If I still see a distro using it, I will scold you for not
reading this changelog.) reading this changelog.)
- xt_iface: allow matching against incoming/outgoing interface
v1.30 (October 02 2010) v1.30 (October 02 2010)

View File

@@ -17,8 +17,14 @@
#include "xt_iface.h" #include "xt_iface.h"
#include "compat_user.h" #include "compat_user.h"
enum {
XT_IFACE_IFACE = 1 << 16,
};
static const struct option iface_mt_opts[] = { static const struct option iface_mt_opts[] = {
{.name = "iface", .has_arg = true, .val = 'i'}, {.name = "iface", .has_arg = true, .val = 'i'},
{.name = "dev-in", .has_arg = false, .val = 'I'},
{.name = "dev-out", .has_arg = false, .val = 'O'},
{.name = "up", .has_arg = false, .val = 'u'}, {.name = "up", .has_arg = false, .val = 'u'},
{.name = "down", .has_arg = false, .val = 'U'}, /* not up */ {.name = "down", .has_arg = false, .val = 'U'}, /* not up */
{.name = "broadcast", .has_arg = false, .val = 'b'}, {.name = "broadcast", .has_arg = false, .val = 'b'},
@@ -40,9 +46,7 @@ static void iface_print_opt(const struct xt_iface_mtinfo *info,
const unsigned int option, const char *command) const unsigned int option, const char *command)
{ {
if (info->flags & option) if (info->flags & option)
printf(" %s", command); printf(" %s%s", (info->invflags & option) ? "! " : "", command);
if (info->invflags & option)
printf(" ! %s", command);
} }
static void iface_setflag(struct xt_iface_mtinfo *info, static void iface_setflag(struct xt_iface_mtinfo *info,
@@ -51,10 +55,9 @@ static void iface_setflag(struct xt_iface_mtinfo *info,
if (*flags & flag) if (*flags & flag)
xtables_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"iface: \"--%s\" flag already specified", command); "iface: \"--%s\" flag already specified", command);
info->flags |= flag;
if (invert) if (invert)
info->invflags |= flag; info->invflags |= flag;
else
info->flags |= flag;
*flags |= flag; *flags |= flag;
} }
@@ -70,6 +73,7 @@ static void iface_mt_help(void)
printf( printf(
"iface match options:\n" "iface match options:\n"
" --iface interface Name of interface\n" " --iface interface Name of interface\n"
" --dev-in / --dev-out Use incoming/outgoing interface instead\n"
"[!] --up / --down match if UP flag (not) set\n" "[!] --up / --down match if UP flag (not) set\n"
"[!] --broadcast match if BROADCAST flag (not) set\n" "[!] --broadcast match if BROADCAST flag (not) set\n"
"[!] --loopback match if LOOPBACK flag (not) set\n" "[!] --loopback match if LOOPBACK flag (not) set\n"
@@ -111,6 +115,18 @@ static int iface_mt_parse(int c, char **argv, int invert, unsigned int *flags,
strcpy(info->ifname, optarg); strcpy(info->ifname, optarg);
*flags |= XT_IFACE_IFACE; *flags |= XT_IFACE_IFACE;
return true; return true;
case 'I': /* --dev-in */
xtables_param_act(XTF_ONLY_ONCE, "iface", "--dev-in",
*flags & XT_IFACE_IFACE);
*flags |= XT_IFACE_IFACE;
iface_setflag(info, flags, invert, XT_IFACE_DEV_IN, "dev-in");
return true;
case 'O': /* --dev-out */
xtables_param_act(XTF_ONLY_ONCE, "iface", "--dev-out",
*flags & XT_IFACE_IFACE);
*flags |= XT_IFACE_IFACE;
iface_setflag(info, flags, invert, XT_IFACE_DEV_OUT, "dev-out");
return true;
case 'u': /* UP */ case 'u': /* UP */
iface_setflag(info, flags, invert, XT_IFACE_UP, "up"); iface_setflag(info, flags, invert, XT_IFACE_UP, "up");
return true; return true;
@@ -153,7 +169,8 @@ static void iface_mt_check(unsigned int flags)
if (!(flags & XT_IFACE_IFACE)) if (!(flags & XT_IFACE_IFACE))
xtables_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"iface: You must specify an interface"); "iface: You must specify an interface");
if (flags == 0 || flags == XT_IFACE_IFACE) if ((flags & ~(XT_IFACE_IFACE | XT_IFACE_DEV_IN |
XT_IFACE_DEV_OUT)) == 0)
xtables_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"iface: You must specify at least one option"); "iface: You must specify at least one option");
} }
@@ -163,7 +180,14 @@ static void iface_mt_print(const void *ip, const struct xt_entry_match *match,
{ {
const struct xt_iface_mtinfo *info = (const void *)match->data; const struct xt_iface_mtinfo *info = (const void *)match->data;
printf("iface: \"%s\" [state:", info->ifname); printf("iface: ");
if (info->flags & XT_IFACE_DEV_IN)
printf("(in)");
else if (info->flags & XT_IFACE_DEV_OUT)
printf("(out)");
else
printf("%s", info->ifname);
printf(" [state:");
iface_print_opt(info, XT_IFACE_UP, "up"); iface_print_opt(info, XT_IFACE_UP, "up");
iface_print_opt(info, XT_IFACE_BROADCAST, "broadcast"); iface_print_opt(info, XT_IFACE_BROADCAST, "broadcast");
iface_print_opt(info, XT_IFACE_LOOPBACK, "loopback"); iface_print_opt(info, XT_IFACE_LOOPBACK, "loopback");
@@ -182,6 +206,11 @@ static void iface_mt_save(const void *ip, const struct xt_entry_match *match)
{ {
const struct xt_iface_mtinfo *info = (const void *)match->data; const struct xt_iface_mtinfo *info = (const void *)match->data;
if (info->flags & XT_IFACE_DEV_IN)
printf("--dev-in");
else if (info->flags & XT_IFACE_DEV_OUT)
printf("--dev-out");
else
printf("--iface %s", info->ifname); printf("--iface %s", info->ifname);
iface_print_opt(info, XT_IFACE_UP, "--up"); iface_print_opt(info, XT_IFACE_UP, "--up");
iface_print_opt(info, XT_IFACE_BROADCAST, "--broadcast"); iface_print_opt(info, XT_IFACE_BROADCAST, "--broadcast");

View File

@@ -1,7 +1,20 @@
Allows you to check interface states. Allows you to check interface states. First, an interface needs to be selected
for comparison. Exactly one option of the following three must be specified:
.TP .TP
\fB\-\-iface\fP \fIname\fP \fB\-\-iface\fP \fIname\fP
Check the states on the given interface. This option is required. Check the states on the given interface.
.TP
\fB\-\-dev\-in\fP
Check the states on the interface on which the packet came in. If the input
device is not set, because for example you are using \-m iface in the OUTPUT
chain, this submatch returns false.
.TP
\fB\-\-dev\-out\fP
Check the states on the interface on which the packet will go out. If the
output device is not set, because for example you are using \-m iface in the
INPUT chain, this submatch returns false.
.PP
Following that, one can select the interface properties to check for:
.TP .TP
[\fB!\fP] \fB\-\-up\fP, [\fB!\fP] \fB\-\-down\fP [\fB!\fP] \fB\-\-up\fP, [\fB!\fP] \fB\-\-down\fP
Check the UP flag. Check the UP flag.

View File

@@ -40,29 +40,46 @@ static const struct xt_iface_flag_pairs xt_iface_lookup[] =
{.iface_flag = XT_IFACE_DORMANT, .iff_flag = IFF_DORMANT}, {.iface_flag = XT_IFACE_DORMANT, .iff_flag = IFF_DORMANT},
}; };
static const struct net_device *iface_get(const struct xt_iface_mtinfo *info,
const struct xt_action_param *par, struct net_device **put)
{
if (info->flags & XT_IFACE_DEV_IN)
return par->in;
else if (info->flags & XT_IFACE_DEV_OUT)
return par->out;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
return *put = dev_get_by_name(&init_net, info->ifname);
#else
return *put = dev_get_by_name(info->ifname);
#endif
}
static bool iface_flagtest(unsigned int devflags, unsigned int flags,
unsigned int invflags)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(xt_iface_lookup); ++i)
if ((flags & xt_iface_lookup[i].iface_flag) &&
!!(devflags & xt_iface_lookup[i].iff_flag) ^
!(invflags & xt_iface_lookup[i].iface_flag))
return false;
return true;
}
static bool xt_iface_mt(const struct sk_buff *skb, static bool xt_iface_mt(const struct sk_buff *skb,
struct xt_action_param *par) struct xt_action_param *par)
{ {
const struct xt_iface_mtinfo *info = par->matchinfo; const struct xt_iface_mtinfo *info = par->matchinfo;
struct net_device *dev; struct net_device *put = NULL;
const struct net_device *dev = iface_get(info, par, &put);
bool retval; bool retval;
int i;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) if (dev == NULL)
dev = dev_get_by_name(&init_net, info->ifname); return false;
#else retval = iface_flagtest(dev->flags, info->flags, info->invflags);
dev = dev_get_by_name(info->ifname); if (put != NULL)
#endif dev_put(put);
retval = dev != NULL;
if (retval) {
for (i = 0; i < ARRAY_SIZE(xt_iface_lookup) && retval; ++i) {
if (info->flags & xt_iface_lookup[i].iface_flag)
retval &= dev->flags & xt_iface_lookup[i].iff_flag;
if (info->invflags & xt_iface_lookup[i].iface_flag)
retval &= !(dev->flags & xt_iface_lookup[i].iff_flag);
}
dev_put(dev);
}
return retval; return retval;
} }

View File

@@ -13,7 +13,8 @@ enum {
XT_IFACE_DYNAMIC = 1 << 8, XT_IFACE_DYNAMIC = 1 << 8,
XT_IFACE_LOWER_UP = 1 << 9, XT_IFACE_LOWER_UP = 1 << 9,
XT_IFACE_DORMANT = 1 << 10, XT_IFACE_DORMANT = 1 << 10,
XT_IFACE_IFACE = 1 << 15, XT_IFACE_DEV_IN = 1 << 11,
XT_IFACE_DEV_OUT = 1 << 12,
}; };
struct xt_iface_mtinfo { struct xt_iface_mtinfo {