summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extensions/Makefile2
-rw-r--r--extensions/libipt_physdev.c182
-rw-r--r--include/linux/netfilter_ipv4/ipt_physdev.h19
3 files changed, 202 insertions, 1 deletions
diff --git a/extensions/Makefile b/extensions/Makefile
index 5d0d844..2513b8b 100644
--- a/extensions/Makefile
+++ b/extensions/Makefile
@@ -5,7 +5,7 @@
# header files are present in the include/linux directory of this iptables
# package (HW)
#
-PF_EXT_SLIB:=ah conntrack dscp ecn esp helper icmp iplimit length limit mac mark multiport owner pkttype rpc standard state tcp tcpmss tos ttl udp unclean DNAT DSCP ECN LOG MARK MASQUERADE MIRROR REDIRECT REJECT SAME SNAT TARPIT TCPMSS TOS TTL ULOG
+PF_EXT_SLIB:=ah conntrack dscp ecn esp helper icmp iplimit length limit mac mark multiport owner physdev pkttype rpc standard state tcp tcpmss tos ttl udp unclean DNAT DSCP ECN LOG MARK MASQUERADE MIRROR REDIRECT REJECT SAME SNAT TARPIT TCPMSS TOS TTL ULOG
PF6_EXT_SLIB:=eui64 hl icmpv6 length limit mac mark multiport owner standard tcp udp HL LOG MARK
# Optionals
diff --git a/extensions/libipt_physdev.c b/extensions/libipt_physdev.c
new file mode 100644
index 0000000..30fcce9
--- /dev/null
+++ b/extensions/libipt_physdev.c
@@ -0,0 +1,182 @@
+/* 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 <iptables.h>
+#include <linux/netfilter_ipv4/ipt_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"
+"\n", IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+ { "physdev-in", 1, 0, '1' },
+ { "physdev-out", 1, 0, '2' },
+ {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 ipt_entry_match *m, unsigned int *nfcache)
+{
+}
+
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ unsigned int *nfcache,
+ struct ipt_entry_match **match)
+{
+ struct ipt_physdev_info *info =
+ (struct ipt_physdev_info*)(*match)->data;
+
+ switch (c) {
+ case '1':
+ if (*flags & IPT_PHYSDEV_OP_MATCH_IN)
+ exit_error(PARAMETER_PROBLEM,
+ "multiple --physdev-in not allowed");
+ check_inverse(optarg, &invert, &optind, 0);
+ parse_interface(argv[optind-1], info->physindev, info->in_mask);
+ if (invert)
+ info->invert |= IPT_PHYSDEV_OP_MATCH_IN;
+ *flags |= IPT_PHYSDEV_OP_MATCH_IN;
+ break;
+
+ case '2':
+ if (*flags & IPT_PHYSDEV_OP_MATCH_OUT)
+ exit_error(PARAMETER_PROBLEM,
+ "multiple --physdev-out not allowed");
+ check_inverse(optarg, &invert, &optind, 0);
+ parse_interface(argv[optind-1], info->physoutdev,
+ info->out_mask);
+ if (invert)
+ info->invert |= IPT_PHYSDEV_OP_MATCH_OUT;
+ *flags |= IPT_PHYSDEV_OP_MATCH_OUT;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static void final_check(unsigned int flags)
+{
+}
+
+static void print_iface(u_int8_t invert, char *dev, char *prefix)
+{
+ char iface[IFNAMSIZ+2];
+
+ if (invert) {
+ iface[0] = '!';
+ iface[1] = '\0';
+ } else
+ iface[0] = '\0';
+
+ if (dev[0] != '\0') {
+ strcat(iface, dev);
+ printf("%s%s", prefix, iface);
+ }
+}
+
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match,
+ int numeric)
+{
+ struct ipt_physdev_info *info =
+ (struct ipt_physdev_info*)match->data;
+
+ printf("PHYSDEV match");
+ print_iface(info->invert & IPT_PHYSDEV_OP_MATCH_IN, info->physindev,
+ " physindev=");
+ print_iface(info->invert & IPT_PHYSDEV_OP_MATCH_OUT, info->physoutdev,
+ " physoutdev=");
+ printf(" ");
+}
+
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ struct ipt_physdev_info *info =
+ (struct ipt_physdev_info*)match->data;
+
+ print_iface(info->invert & IPT_PHYSDEV_OP_MATCH_IN, info->physindev,
+ "--physdev-in ");
+ print_iface(info->invert & IPT_PHYSDEV_OP_MATCH_OUT, info->physoutdev,
+ "--physdev-out ");
+ printf(" ");
+}
+
+static
+struct iptables_match physdev
+= { NULL,
+ "physdev",
+ IPTABLES_VERSION,
+ IPT_ALIGN(sizeof(struct ipt_physdev_info)),
+ IPT_ALIGN(sizeof(struct ipt_physdev_info)),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_match(&physdev);
+}
diff --git a/include/linux/netfilter_ipv4/ipt_physdev.h b/include/linux/netfilter_ipv4/ipt_physdev.h
new file mode 100644
index 0000000..668e1a9
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ipt_physdev.h
@@ -0,0 +1,19 @@
+#ifndef _IPT_PHYSDEV_H
+#define _IPT_PHYSDEV_H
+
+#ifdef __KERNEL__
+#include <linux/if.h>
+#endif
+
+#define IPT_PHYSDEV_OP_MATCH_IN 0x01
+#define IPT_PHYSDEV_OP_MATCH_OUT 0x02
+
+struct ipt_physdev_info {
+ u_int8_t invert;
+ char physindev[IFNAMSIZ];
+ char in_mask[IFNAMSIZ];
+ char physoutdev[IFNAMSIZ];
+ char out_mask[IFNAMSIZ];
+};
+
+#endif /*_IPT_PHYSDEV_H*/