summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'extensions')
-rw-r--r--extensions/Makefile2
-rw-r--r--extensions/libip6t_physdev.c232
-rw-r--r--extensions/libip6t_physdev.man42
3 files changed, 275 insertions, 1 deletions
diff --git a/extensions/Makefile b/extensions/Makefile
index 1bb5cbe..81631c4 100644
--- a/extensions/Makefile
+++ b/extensions/Makefile
@@ -6,7 +6,7 @@
# package (HW)
#
PF_EXT_SLIB:=ah addrtype connlimit connmark conntrack dscp ecn esp helper icmp iprange length limit mac mark multiport owner physdev pkttype realm rpc sctp standard state tcp tcpmss tos ttl udp unclean CLASSIFY CONNMARK DNAT DSCP ECN LOG MARK MASQUERADE MIRROR NETMAP NOTRACK REDIRECT REJECT SAME SNAT TARPIT TCPMSS TOS TRACE TTL ULOG
-PF6_EXT_SLIB:=eui64 hl icmpv6 length limit mac mark multiport owner standard tcp udp HL LOG MARK TRACE
+PF6_EXT_SLIB:=eui64 hl icmpv6 length limit mac mark multiport owner physdev standard tcp udp HL LOG MARK TRACE
# Optionals
PF_EXT_SLIB_OPTS:=$(foreach T,$(wildcard extensions/.*-test),$(shell KERNEL_DIR=$(KERNEL_DIR) $(T)))
diff --git a/extensions/libip6t_physdev.c b/extensions/libip6t_physdev.c
new file mode 100644
index 0000000..d5fc506
--- /dev/null
+++ b/extensions/libip6t_physdev.c
@@ -0,0 +1,232 @@
+/* Shared library add-on to iptables to add bridge port matching support. */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <ip6tables.h>
+#include <linux/netfilter_ipv6/ip6t_physdev.h>
+#if defined(__GLIBC__) && __GLIBC__ == 2
+#include <net/ethernet.h>
+#else
+#include <linux/if_ether.h>
+#endif
+
+static void
+help(void)
+{
+ printf(
+"physdev v%s options:\n"
+" --physdev-in [!] input name[+] bridge port name ([+] for wildcard)\n"
+" --physdev-out [!] output name[+] bridge port name ([+] for wildcard)\n"
+" [!] --physdev-is-in arrived on a bridge device\n"
+" [!] --physdev-is-out will leave on a bridge device\n"
+" [!] --physdev-is-bridged it's a bridged packet\n"
+"\n", IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+ { "physdev-in", 1, 0, '1' },
+ { "physdev-out", 1, 0, '2' },
+ { "physdev-is-in", 0, 0, '3' },
+ { "physdev-is-out", 0, 0, '4' },
+ { "physdev-is-bridged", 0, 0, '5' },
+ {0}
+};
+
+/* copied from iptables.c */
+static void
+parse_interface(const char *arg, char *vianame, unsigned char *mask)
+{
+ int vialen = strlen(arg);
+ unsigned int i;
+
+ memset(mask, 0, IFNAMSIZ);
+ memset(vianame, 0, IFNAMSIZ);
+
+ if (vialen + 1 > IFNAMSIZ)
+ exit_error(PARAMETER_PROBLEM,
+ "interface name `%s' must be shorter than IFNAMSIZ"
+ " (%i)", arg, IFNAMSIZ-1);
+
+ strcpy(vianame, arg);
+ if (vialen == 0)
+ memset(mask, 0, IFNAMSIZ);
+ else if (vianame[vialen - 1] == '+') {
+ memset(mask, 0xFF, vialen - 1);
+ memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1);
+ /* Don't remove `+' here! -HW */
+ } else {
+ /* Include nul-terminator in match */
+ memset(mask, 0xFF, vialen + 1);
+ memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1);
+ for (i = 0; vianame[i]; i++) {
+ if (!isalnum(vianame[i])
+ && vianame[i] != '_'
+ && vianame[i] != '.') {
+ printf("Warning: wierd character in interface"
+ " `%s' (No aliases, :, ! or *).\n",
+ vianame);
+ break;
+ }
+ }
+ }
+}
+
+static void
+init(struct ip6t_entry_match *m, unsigned int *nfcache)
+{
+}
+
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ip6t_entry *entry,
+ unsigned int *nfcache,
+ struct ip6t_entry_match **match)
+{
+ struct ip6t_physdev_info *info =
+ (struct ip6t_physdev_info*)(*match)->data;
+
+ switch (c) {
+ case '1':
+ if (*flags & IP6T_PHYSDEV_OP_IN)
+ goto multiple_use;
+ check_inverse(optarg, &invert, &optind, 0);
+ parse_interface(argv[optind-1], info->physindev, info->in_mask);
+ if (invert)
+ info->invert |= IP6T_PHYSDEV_OP_IN;
+ info->bitmask |= IP6T_PHYSDEV_OP_IN;
+ *flags |= IP6T_PHYSDEV_OP_IN;
+ break;
+
+ case '2':
+ if (*flags & IP6T_PHYSDEV_OP_OUT)
+ goto multiple_use;
+ check_inverse(optarg, &invert, &optind, 0);
+ parse_interface(argv[optind-1], info->physoutdev,
+ info->out_mask);
+ if (invert)
+ info->invert |= IP6T_PHYSDEV_OP_OUT;
+ info->bitmask |= IP6T_PHYSDEV_OP_OUT;
+ *flags |= IP6T_PHYSDEV_OP_OUT;
+ break;
+
+ case '3':
+ if (*flags & IP6T_PHYSDEV_OP_ISIN)
+ goto multiple_use;
+ check_inverse(optarg, &invert, &optind, 0);
+ info->bitmask |= IP6T_PHYSDEV_OP_ISIN;
+ if (invert)
+ info->invert |= IP6T_PHYSDEV_OP_ISIN;
+ *flags |= IP6T_PHYSDEV_OP_ISIN;
+ break;
+
+ case '4':
+ if (*flags & IP6T_PHYSDEV_OP_ISOUT)
+ goto multiple_use;
+ check_inverse(optarg, &invert, &optind, 0);
+ info->bitmask |= IP6T_PHYSDEV_OP_ISOUT;
+ if (invert)
+ info->invert |= IP6T_PHYSDEV_OP_ISOUT;
+ *flags |= IP6T_PHYSDEV_OP_ISOUT;
+ break;
+
+ case '5':
+ if (*flags & IP6T_PHYSDEV_OP_BRIDGED)
+ goto multiple_use;
+ check_inverse(optarg, &invert, &optind, 0);
+ if (invert)
+ info->invert |= IP6T_PHYSDEV_OP_BRIDGED;
+ *flags |= IP6T_PHYSDEV_OP_BRIDGED;
+ info->bitmask |= IP6T_PHYSDEV_OP_BRIDGED;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+multiple_use:
+ exit_error(PARAMETER_PROBLEM,
+ "multiple use of the same physdev option is not allowed");
+
+}
+
+static void final_check(unsigned int flags)
+{
+ if (flags == 0)
+ exit_error(PARAMETER_PROBLEM, "PHYSDEV: no physdev option specified");
+}
+
+static void
+print(const struct ip6t_ip6 *ip,
+ const struct ip6t_entry_match *match,
+ int numeric)
+{
+ struct ip6t_physdev_info *info =
+ (struct ip6t_physdev_info*)match->data;
+
+ printf("PHYSDEV match");
+ if (info->bitmask & IP6T_PHYSDEV_OP_ISIN)
+ printf("%s --physdev-is-in",
+ info->invert & IP6T_PHYSDEV_OP_ISIN ? " !":"");
+ if (info->bitmask & IP6T_PHYSDEV_OP_IN)
+ printf("%s --physdev-in %s",
+ (info->invert & IP6T_PHYSDEV_OP_IN) ? " !":"", info->physindev);
+
+ if (info->bitmask & IP6T_PHYSDEV_OP_ISOUT)
+ printf("%s --physdev-is-out",
+ info->invert & IP6T_PHYSDEV_OP_ISOUT ? " !":"");
+ if (info->bitmask & IP6T_PHYSDEV_OP_OUT)
+ printf("%s --physdev-out %s",
+ (info->invert & IP6T_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev);
+ if (info->bitmask & IP6T_PHYSDEV_OP_BRIDGED)
+ printf("%s --physdev-is-bridged",
+ info->invert & IP6T_PHYSDEV_OP_BRIDGED ? " !":"");
+ printf(" ");
+}
+
+static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
+{
+ struct ip6t_physdev_info *info =
+ (struct ip6t_physdev_info*)match->data;
+
+ if (info->bitmask & IP6T_PHYSDEV_OP_ISIN)
+ printf("%s --physdev-is-in",
+ info->invert & IP6T_PHYSDEV_OP_ISIN ? " !":"");
+ if (info->bitmask & IP6T_PHYSDEV_OP_IN)
+ printf("%s --physdev-in %s",
+ (info->invert & IP6T_PHYSDEV_OP_IN) ? " !":"", info->physindev);
+
+ if (info->bitmask & IP6T_PHYSDEV_OP_ISOUT)
+ printf("%s --physdev-is-out",
+ info->invert & IP6T_PHYSDEV_OP_ISOUT ? " !":"");
+ if (info->bitmask & IP6T_PHYSDEV_OP_OUT)
+ printf("%s --physdev-out %s",
+ (info->invert & IP6T_PHYSDEV_OP_OUT) ? " !":"", info->physoutdev);
+ if (info->bitmask & IP6T_PHYSDEV_OP_BRIDGED)
+ printf("%s --physdev-is-bridged",
+ info->invert & IP6T_PHYSDEV_OP_BRIDGED ? " !":"");
+ printf(" ");
+}
+
+static
+struct ip6tables_match physdev
+= { NULL,
+ "physdev",
+ IPTABLES_VERSION,
+ IP6T_ALIGN(sizeof(struct ip6t_physdev_info)),
+ IP6T_ALIGN(sizeof(struct ip6t_physdev_info)),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_match6(&physdev);
+}
diff --git a/extensions/libip6t_physdev.man b/extensions/libip6t_physdev.man
new file mode 100644
index 0000000..846ec7c
--- /dev/null
+++ b/extensions/libip6t_physdev.man
@@ -0,0 +1,42 @@
+This module matches on the bridge port input and output devices enslaved
+to a bridge device. This module is a part of the infrastructure that enables
+a transparent bridging IP firewall and is only useful for kernel versions
+above version 2.5.44.
+.TP
+.B --physdev-in name
+Name of a bridge port via which a packet is received (only for
+packets entering the
+.BR INPUT ,
+.B FORWARD
+and
+.B PREROUTING
+chains). If the interface name ends in a "+", then any
+interface which begins with this name will match. If the packet didn't arrive
+through a bridge device, this packet won't match this option, unless '!' is used.
+.TP
+.B --physdev-out name
+Name of a bridge port via which a packet is going to be sent (for packets
+entering the
+.BR FORWARD ,
+.B OUTPUT
+and
+.B POSTROUTING
+chains). If the interface name ends in a "+", then any
+interface which begins with this name will match. Note that in the
+.BR nat " and " mangle
+.B OUTPUT
+chains one cannot match on the bridge output port, however one can in the
+.B "filter OUTPUT"
+chain. If the packet won't leave by a bridge device or it is yet unknown what
+the output device will be, then the packet won't match this option, unless
+'!' is used.
+.TP
+.B --physdev-is-in
+Matches if the packet has entered through a bridge interface.
+.TP
+.B --physdev-is-out
+Matches if the packet will leave through a bridge interface.
+.TP
+.B --physdev-is-bridged
+Matches if the packet is being bridged and therefore is not being routed.
+This is only useful in the FORWARD and POSTROUTING chains.