summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaber <kaber>2004-09-12 22:37:31 +0000
committerkaber <kaber>2004-09-12 22:37:31 +0000
commit77c628a2a4e60852a3ea2e352219689444abfe70 (patch)
tree3629724ccb5b905f2f2399a3edd32e4700dd84b9
parent771d8309efa1555cbd0015592f082434f444e14f (diff)
[PATCH] port physdev to ip6tables (Bart De Schuymer)
-rw-r--r--extensions/Makefile2
-rw-r--r--extensions/libip6t_physdev.c232
-rw-r--r--extensions/libip6t_physdev.man42
-rw-r--r--include/linux/netfilter_ipv6/ip6t_physdev.h24
4 files changed, 299 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.
diff --git a/include/linux/netfilter_ipv6/ip6t_physdev.h b/include/linux/netfilter_ipv6/ip6t_physdev.h
new file mode 100644
index 0000000..c234731
--- /dev/null
+++ b/include/linux/netfilter_ipv6/ip6t_physdev.h
@@ -0,0 +1,24 @@
+#ifndef _IP6T_PHYSDEV_H
+#define _IP6T_PHYSDEV_H
+
+#ifdef __KERNEL__
+#include <linux/if.h>
+#endif
+
+#define IP6T_PHYSDEV_OP_IN 0x01
+#define IP6T_PHYSDEV_OP_OUT 0x02
+#define IP6T_PHYSDEV_OP_BRIDGED 0x04
+#define IP6T_PHYSDEV_OP_ISIN 0x08
+#define IP6T_PHYSDEV_OP_ISOUT 0x10
+#define IP6T_PHYSDEV_OP_MASK (0x20 - 1)
+
+struct ip6t_physdev_info {
+ char physindev[IFNAMSIZ];
+ char in_mask[IFNAMSIZ];
+ char physoutdev[IFNAMSIZ];
+ char out_mask[IFNAMSIZ];
+ u_int8_t invert;
+ u_int8_t bitmask;
+};
+
+#endif /*_IP6T_PHYSDEV_H*/