summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'extensions')
-rw-r--r--extensions/Makefile14
-rw-r--r--extensions/libipt_DNAT.c244
-rw-r--r--extensions/libipt_LOG.c260
-rw-r--r--extensions/libipt_MARK.c120
-rw-r--r--extensions/libipt_MASQUERADE.c166
-rw-r--r--extensions/libipt_REDIRECT.c166
-rw-r--r--extensions/libipt_REJECT.c159
-rw-r--r--extensions/libipt_SNAT.c244
-rw-r--r--extensions/libipt_TOS.c173
-rw-r--r--extensions/libipt_icmp.c295
-rw-r--r--extensions/libipt_limit.c196
-rw-r--r--extensions/libipt_mac.c144
-rw-r--r--extensions/libipt_mark.c128
-rw-r--r--extensions/libipt_multiport.c262
-rw-r--r--extensions/libipt_owner.c219
-rw-r--r--extensions/libipt_standard.c67
-rw-r--r--extensions/libipt_state.c162
-rw-r--r--extensions/libipt_tcp.c439
-rw-r--r--extensions/libipt_tos.c171
-rw-r--r--extensions/libipt_udp.c252
-rw-r--r--extensions/libipt_unclean.c66
21 files changed, 3947 insertions, 0 deletions
diff --git a/extensions/Makefile b/extensions/Makefile
new file mode 100644
index 00000000..8e0dec1c
--- /dev/null
+++ b/extensions/Makefile
@@ -0,0 +1,14 @@
+#! /usr/bin/make
+
+PF_EXT_SLIB:=tcp udp icmp mac limit standard REJECT LOG unclean state multiport tos TOS mark MARK owner SNAT DNAT MASQUERADE REDIRECT
+SHARED_LIBS+=$(foreach T,$(PF_EXT_SLIB),extensions/libipt_$(T).so)
+EXTRA_INSTALLS+=$(foreach T, $(PF_EXT_SLIB), $(DESTDIR)$(LIBDIR)/iptables/libipt_$(T).so)
+
+ifndef TOPLEVEL_INCLUDED
+local:
+ cd .. && $(MAKE) $(SHARED_LIBS)
+endif
+
+$(DESTDIR)$(LIBDIR)/iptables/libipt_%.so: extensions/libipt_%.so
+ @[ -d $(DESTDIR)$(LIBDIR)/iptables ] || mkdir -p $(DESTDIR)$(LIBDIR)/iptables
+ cp $< $@
diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c
new file mode 100644
index 00000000..e3c37222
--- /dev/null
+++ b/extensions/libipt_DNAT.c
@@ -0,0 +1,244 @@
+/* Shared library add-on to iptables to add destination-NAT support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+/* Dest NAT data consists of a multi-range, indicating where to map
+ to. */
+struct ipt_natinfo
+{
+ struct ipt_entry_target t;
+ struct ip_nat_multi_range mr;
+};
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"DNAT v%s options:\n"
+" --to-destination <ipaddr>[-<ipaddr>][:port-port]\n"
+" Address to map destination to.\n"
+" (You can use this more than once)\n\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "to-destination", 1, 0, '1' },
+ { 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ipt_entry_target *t, unsigned int *nfcache)
+{
+ /* Can't cache this */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+static struct ipt_natinfo *
+append_range(struct ipt_natinfo *info, const struct ip_nat_range *range)
+{
+ unsigned int size;
+
+ /* One rangesize already in struct ipt_natinfo */
+ size = IPT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
+
+ info = realloc(info, size);
+ if (!info)
+ exit_error(OTHER_PROBLEM, "Out of memory\n");
+
+ info->t.target_size = size;
+ info->mr.range[info->mr.rangesize] = *range;
+ info->mr.rangesize++;
+
+ return info;
+}
+
+/* Ranges expected in network order. */
+static struct ipt_entry_target *
+parse_to(char *arg, int portok, struct ipt_natinfo *info)
+{
+ struct ip_nat_range range;
+ char *colon, *dash;
+ struct in_addr *ip;
+
+ memset(&range, 0, sizeof(range));
+ colon = strchr(arg, ':');
+
+ if (colon) {
+ int port;
+
+ if (!portok)
+ exit_error(PARAMETER_PROBLEM,
+ "Need TCP or UDP with port specification");
+
+ range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+ port = atoi(colon+1);
+ if (port == 0 || port > 65535)
+ exit_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid\n", colon+1);
+
+ dash = strchr(colon, '-');
+ if (!dash) {
+ range.min.tcp.port
+ = range.max.tcp.port
+ = htons(port);
+ } else {
+ int maxport;
+
+ maxport = atoi(dash + 1);
+ if (maxport == 0 || maxport > 65535)
+ exit_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid\n", dash+1);
+ if (maxport < port)
+ /* People are stupid. */
+ exit_error(PARAMETER_PROBLEM,
+ "Port range `%s' funky\n", colon+1);
+ range.min.tcp.port = htons(port);
+ range.max.tcp.port = htons(maxport);
+ }
+ /* Starts with a colon? No IP info...*/
+ if (colon == arg)
+ return &(append_range(info, &range)->t);
+ *colon = '\0';
+ }
+
+ range.flags |= IP_NAT_RANGE_MAP_IPS;
+ dash = strchr(arg, '-');
+ if (colon && dash && dash > colon)
+ dash = NULL;
+
+ if (dash)
+ *dash = '\0';
+
+ ip = dotted_to_addr(arg);
+ if (!ip)
+ exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+ arg);
+ range.min_ip = ip->s_addr;
+ if (dash) {
+ ip = dotted_to_addr(dash+1);
+ if (!ip)
+ exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+ dash+1);
+ range.max_ip = ip->s_addr;
+ } else
+ range.max_ip = range.min_ip;
+
+ return &(append_range(info, &range)->t);
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ struct ipt_natinfo *info = (void *)*target;
+ int portok;
+
+ if (entry->ip.proto == IPPROTO_TCP
+ || entry->ip.proto == IPPROTO_UDP)
+ portok = 1;
+ else
+ portok = 0;
+
+ switch (c) {
+ case '1':
+ if (check_inverse(optarg, &invert))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --to-destination");
+
+ *target = parse_to(optarg, portok, info);
+ *flags = 1;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Final check; must have specfied --to-source. */
+static void final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM,
+ "You must specify --to-destination");
+}
+
+static void print_range(const struct ip_nat_range *r)
+{
+ if (r->flags & IP_NAT_RANGE_MAP_IPS) {
+ struct in_addr a;
+
+ a.s_addr = r->min_ip;
+ printf("%s", addr_to_dotted(&a));
+ if (r->max_ip != r->min_ip) {
+ a.s_addr = r->max_ip;
+ printf("-%s", addr_to_dotted(&a));
+ }
+ }
+ if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+ printf(":");
+ printf("%hu", ntohs(r->min.tcp.port));
+ if (r->max.tcp.port != r->min.tcp.port)
+ printf("-%hu", ntohs(r->max.tcp.port));
+ }
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_target *target,
+ int numeric)
+{
+ struct ipt_natinfo *info = (void *)target;
+ unsigned int i = 0;
+
+ printf("to:");
+ for (i = 0; i < info->mr.rangesize; i++) {
+ print_range(&info->mr.range[i]);
+ printf(" ");
+ }
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+ struct ipt_natinfo *info = (void *)target;
+ unsigned int i = 0;
+
+ for (i = 0; i < info->mr.rangesize; i++) {
+ printf("--to-destination ");
+ print_range(&info->mr.range[i]);
+ printf(" ");
+ }
+}
+
+struct iptables_target dnat
+= { NULL,
+ "DNAT",
+ NETFILTER_VERSION,
+ sizeof(struct ip_nat_multi_range),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_target(&dnat);
+}
diff --git a/extensions/libipt_LOG.c b/extensions/libipt_LOG.c
new file mode 100644
index 00000000..cab5739d
--- /dev/null
+++ b/extensions/libipt_LOG.c
@@ -0,0 +1,260 @@
+/* Shared library add-on to iptables to add LOG support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_LOG.h>
+
+#define LOG_DEFAULT_LEVEL LOG_WARNING
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"LOG v%s options:\n"
+" --log-level level Level of logging (numeric or see syslog.conf)\n"
+" --log-prefix prefix Prefix log messages with this prefix.\n\n"
+" --log-tcp-sequence Log TCP sequence numbers.\n\n"
+" --log-tcp-options Log TCP options.\n\n"
+" --log-ip-options Log IP options.\n\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "log-level", 1, 0, '!' },
+ { "log-prefix", 1, 0, '#' },
+ { "log-tcp-sequence", 0, 0, '1' },
+ { "log-tcp-options", 0, 0, '2' },
+ { "log-ip-options", 0, 0, '3' },
+ { 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ipt_entry_target *t, unsigned int *nfcache)
+{
+ struct ipt_log_info *loginfo = (struct ipt_log_info *)t->data;
+
+ loginfo->level = LOG_DEFAULT_LEVEL;
+
+ /* Can't cache this */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+struct ipt_log_names {
+ const char *name;
+ unsigned int level;
+};
+
+static struct ipt_log_names ipt_log_names[]
+= { { "alert", LOG_ALERT },
+ { "crit", LOG_CRIT },
+ { "debug", LOG_DEBUG },
+ { "emerg", LOG_EMERG },
+ { "error", LOG_ERR }, /* DEPRECATED */
+ { "info", LOG_INFO },
+ { "notice", LOG_NOTICE },
+ { "panic", LOG_EMERG }, /* DEPRECATED */
+ { "warning", LOG_WARNING }
+};
+
+static u_int8_t
+parse_level(const char *level)
+{
+ int lev;
+
+ lev = string_to_number(level, 0, 7);
+ if (lev == -1) {
+ unsigned int i = 0;
+
+ for (i = 0;
+ i < sizeof(ipt_log_names) / sizeof(struct ipt_log_names);
+ i++) {
+ if (strncasecmp(level, ipt_log_names[i].name,
+ strlen(level)) == 0) {
+ if (lev != -1)
+ exit_error(PARAMETER_PROBLEM,
+ "log-level `%s' ambiguous",
+ level);
+ lev = ipt_log_names[i].level;
+ }
+ }
+
+ if (lev == -1)
+ exit_error(PARAMETER_PROBLEM,
+ "log-level `%s' unknown", level);
+ }
+
+ return (u_int8_t)lev;
+}
+
+#define IPT_LOG_OPT_LEVEL 0x01
+#define IPT_LOG_OPT_PREFIX 0x02
+#define IPT_LOG_OPT_TCPSEQ 0x04
+#define IPT_LOG_OPT_TCPOPT 0x08
+#define IPT_LOG_OPT_IPOPT 0x10
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ struct ipt_log_info *loginfo = (struct ipt_log_info *)(*target)->data;
+
+ switch (c) {
+ case '!':
+ if (*flags & IPT_LOG_OPT_LEVEL)
+ exit_error(PARAMETER_PROBLEM,
+ "Can't specify --log-level twice");
+
+ if (check_inverse(optarg, &invert))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --log-level");
+
+ loginfo->level = parse_level(optarg);
+ *flags |= IPT_LOG_OPT_LEVEL;
+ break;
+
+ case '#':
+ if (*flags & IPT_LOG_OPT_PREFIX)
+ exit_error(PARAMETER_PROBLEM,
+ "Can't specify --log-prefix twice");
+
+ if (check_inverse(optarg, &invert))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --log-prefix");
+
+ if (strlen(optarg) > sizeof(loginfo->prefix) - 1)
+ exit_error(PARAMETER_PROBLEM,
+ "Maximum prefix length %u for --log-prefix",
+ sizeof(loginfo->prefix) - 1);
+
+ strcpy(loginfo->prefix, optarg);
+ *flags |= IPT_LOG_OPT_PREFIX;
+ break;
+
+ case '1':
+ if (*flags & IPT_LOG_OPT_TCPSEQ)
+ exit_error(PARAMETER_PROBLEM,
+ "Can't specify --log-tcp-sequence "
+ "twice");
+
+ loginfo->logflags |= IPT_LOG_TCPSEQ;
+ *flags |= IPT_LOG_OPT_TCPSEQ;
+ break;
+
+ case '2':
+ if (*flags & IPT_LOG_OPT_TCPOPT)
+ exit_error(PARAMETER_PROBLEM,
+ "Can't specify --log-tcp-options twice");
+
+ loginfo->logflags |= IPT_LOG_TCPOPT;
+ *flags |= IPT_LOG_OPT_TCPOPT;
+ break;
+
+ case '3':
+ if (*flags & IPT_LOG_OPT_IPOPT)
+ exit_error(PARAMETER_PROBLEM,
+ "Can't specify --log-ip-options twice");
+
+ loginfo->logflags |= IPT_LOG_IPOPT;
+ *flags |= IPT_LOG_OPT_IPOPT;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Final check; nothing. */
+static void final_check(unsigned int flags)
+{
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_target *target,
+ int numeric)
+{
+ const struct ipt_log_info *loginfo
+ = (const struct ipt_log_info *)target->data;
+ unsigned int i = 0;
+
+ printf("LOG ");
+ if (numeric)
+ printf("flags %u level %u ",
+ loginfo->logflags, loginfo->level);
+ else {
+ for (i = 0;
+ i < sizeof(ipt_log_names) / sizeof(struct ipt_log_names);
+ i++) {
+ if (loginfo->level == ipt_log_names[i].level) {
+ printf("level %s ", ipt_log_names[i].name);
+ break;
+ }
+ }
+ if (i == sizeof(ipt_log_names) / sizeof(struct ipt_log_names))
+ printf("UNKNOWN level %u ", loginfo->level);
+ if (loginfo->logflags & IPT_LOG_TCPSEQ)
+ printf("tcp-sequence ");
+ if (loginfo->logflags & IPT_LOG_TCPOPT)
+ printf("tcp-options ");
+ if (loginfo->logflags & IPT_LOG_IPOPT)
+ printf("ip-options ");
+ if (loginfo->logflags & ~(IPT_LOG_MASK))
+ printf("unknown-flags ");
+ }
+
+ if (strcmp(loginfo->prefix, "") != 0)
+ printf("prefix `%s' ", loginfo->prefix);
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+ const struct ipt_log_info *loginfo
+ = (const struct ipt_log_info *)target->data;
+
+ if (strcmp(loginfo->prefix, "") != 0)
+ printf("--log-prefix %s ", loginfo->prefix);
+
+ if (loginfo->level != LOG_DEFAULT_LEVEL)
+ printf("--log-level %u ", loginfo->level);
+
+ if (loginfo->logflags & IPT_LOG_TCPSEQ)
+ printf("--log-tcp-sequence ");
+ if (loginfo->logflags & IPT_LOG_TCPOPT)
+ printf("--log-tcp-options ");
+ if (loginfo->logflags & IPT_LOG_IPOPT)
+ printf("--log-ip-options ");
+}
+
+struct iptables_target log
+= { NULL,
+ "LOG",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_log_info),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_target(&log);
+}
diff --git a/extensions/libipt_MARK.c b/extensions/libipt_MARK.c
new file mode 100644
index 00000000..ef5a60d5
--- /dev/null
+++ b/extensions/libipt_MARK.c
@@ -0,0 +1,120 @@
+/* Shared library add-on to iptables to add MARK target support. */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_MARK.h>
+
+struct markinfo {
+ struct ipt_entry_target t;
+ struct ipt_mark_target_info mark;
+};
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"MARK target v%s options:\n"
+" --set-mark value Set nfmark value\n"
+"\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "set-mark", 1, 0, '1' },
+ { 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ipt_entry_target *t, unsigned int *nfcache)
+{
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ struct ipt_mark_target_info *markinfo
+ = (struct ipt_mark_target_info *)(*target)->data;
+
+ switch (c) {
+ char *end;
+ case '1':
+ markinfo->mark = strtoul(optarg, &end, 0);
+ if (*end != '\0' || end == optarg)
+ exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
+ if (*flags)
+ exit_error(PARAMETER_PROBLEM,
+ "MARK target: Can't specify --set-mark twice");
+ *flags = 1;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM,
+ "MARK target: Parameter --set-mark is required");
+}
+
+static void
+print_mark(unsigned long mark, int numeric)
+{
+ printf("0x%lx ", mark);
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_target *target,
+ int numeric)
+{
+ const struct ipt_mark_target_info *markinfo =
+ (const struct ipt_mark_target_info *)target->data;
+ printf("MARK set ");
+ print_mark(markinfo->mark, numeric);
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+ const struct ipt_mark_target_info *markinfo =
+ (const struct ipt_mark_target_info *)target->data;
+
+ printf("--set-mark 0x%lx ", markinfo->mark);
+}
+
+struct iptables_target mark
+= { NULL,
+ "MARK",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_mark_target_info),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_target(&mark);
+}
diff --git a/extensions/libipt_MASQUERADE.c b/extensions/libipt_MASQUERADE.c
new file mode 100644
index 00000000..a1151bbc
--- /dev/null
+++ b/extensions/libipt_MASQUERADE.c
@@ -0,0 +1,166 @@
+/* Shared library add-on to iptables to add masquerade support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"MASQUERADE v%s options:\n"
+" --to-ports <port>[-<port>]\n"
+" Port (range) to map to.\n\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "to-ports", 1, 0, '1' },
+ { 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ipt_entry_target *t, unsigned int *nfcache)
+{
+ struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data;
+
+ /* Actually, it's 0, but it's ignored at the moment. */
+ mr->rangesize = 1;
+
+ /* Can't cache this */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+/* Parses ports */
+static void
+parse_ports(const char *arg, struct ip_nat_multi_range *mr)
+{
+ const char *dash;
+ int port;
+
+ mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+ port = atoi(arg);
+ if (port == 0 || port > 65535)
+ exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", arg);
+
+ dash = strchr(arg, '-');
+ if (!dash) {
+ mr->range[0].min.tcp.port
+ = mr->range[0].max.tcp.port
+ = port;
+ } else {
+ int maxport;
+
+ maxport = atoi(dash + 1);
+ if (maxport == 0 || maxport > 65535)
+ exit_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid\n", dash+1);
+ if (maxport < port)
+ /* People are stupid. Present reader excepted. */
+ exit_error(PARAMETER_PROBLEM,
+ "Port range `%s' funky\n", arg);
+ mr->range[0].min.tcp.port = port;
+ mr->range[0].max.tcp.port = maxport;
+ }
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ int portok;
+ struct ip_nat_multi_range *mr
+ = (struct ip_nat_multi_range *)(*target)->data;
+
+ if (entry->ip.proto == IPPROTO_TCP
+ || entry->ip.proto == IPPROTO_UDP)
+ portok = 1;
+ else
+ portok = 0;
+
+ switch (c) {
+ case '1':
+ if (!portok)
+ exit_error(PARAMETER_PROBLEM,
+ "Need TCP or UDP with port specification");
+
+ if (check_inverse(optarg, &invert))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --to-ports");
+
+ parse_ports(optarg, mr);
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Final check; don't care. */
+static void final_check(unsigned int flags)
+{
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_target *target,
+ int numeric)
+{
+ struct ip_nat_multi_range *mr
+ = (struct ip_nat_multi_range *)target->data;
+ struct ip_nat_range *r = &mr->range[0];
+
+ printf("MASQUERADE ");
+ if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+ printf("%hu", r->min.tcp.port);
+ if (r->max.tcp.port != r->min.tcp.port)
+ printf("-%hu", r->max.tcp.port);
+ printf(" ");
+ }
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+ struct ip_nat_multi_range *mr
+ = (struct ip_nat_multi_range *)target->data;
+ struct ip_nat_range *r = &mr->range[0];
+
+ if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+ printf("%hu", r->min.tcp.port);
+ if (r->max.tcp.port != r->min.tcp.port)
+ printf("-%hu", r->max.tcp.port);
+ printf(" ");
+ }
+}
+
+struct iptables_target masq
+= { NULL,
+ "MASQUERADE",
+ NETFILTER_VERSION,
+ sizeof(struct ip_nat_multi_range),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_target(&masq);
+}
diff --git a/extensions/libipt_REDIRECT.c b/extensions/libipt_REDIRECT.c
new file mode 100644
index 00000000..aaafaaf1
--- /dev/null
+++ b/extensions/libipt_REDIRECT.c
@@ -0,0 +1,166 @@
+/* Shared library add-on to iptables to add redirect support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"REDIRECT v%s options:\n"
+" --to-ports <port>[-<port>]\n"
+" Port (range) to map to.\n\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "to-ports", 1, 0, '1' },
+ { 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ipt_entry_target *t, unsigned int *nfcache)
+{
+ struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data;
+
+ /* Actually, it's 0, but it's ignored at the moment. */
+ mr->rangesize = 1;
+
+ /* Can't cache this */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+/* Parses ports */
+static void
+parse_ports(const char *arg, struct ip_nat_multi_range *mr)
+{
+ const char *dash;
+ int port;
+
+ mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+ port = atoi(arg);
+ if (port == 0 || port > 65535)
+ exit_error(PARAMETER_PROBLEM, "Port `%s' not valid\n", arg);
+
+ dash = strchr(arg, '-');
+ if (!dash) {
+ mr->range[0].min.tcp.port
+ = mr->range[0].max.tcp.port
+ = port;
+ } else {
+ int maxport;
+
+ maxport = atoi(dash + 1);
+ if (maxport == 0 || maxport > 65535)
+ exit_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid\n", dash+1);
+ if (maxport < port)
+ /* People are stupid. */
+ exit_error(PARAMETER_PROBLEM,
+ "Port range `%s' funky\n", arg);
+ mr->range[0].min.tcp.port = port;
+ mr->range[0].max.tcp.port = maxport;
+ }
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ struct ip_nat_multi_range *mr
+ = (struct ip_nat_multi_range *)(*target)->data;
+ int portok;
+
+ if (entry->ip.proto == IPPROTO_TCP
+ || entry->ip.proto == IPPROTO_UDP)
+ portok = 1;
+ else
+ portok = 0;
+
+ switch (c) {
+ case '1':
+ if (!portok)
+ exit_error(PARAMETER_PROBLEM,
+ "Need TCP or UDP with port specification");
+
+ if (check_inverse(optarg, &invert))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --to-ports");
+
+ parse_ports(optarg, mr);
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Final check; don't care. */
+static void final_check(unsigned int flags)
+{
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_target *target,
+ int numeric)
+{
+ struct ip_nat_multi_range *mr
+ = (struct ip_nat_multi_range *)target->data;
+ struct ip_nat_range *r = &mr->range[0];
+
+ printf("REDIRECT ");
+ if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+ printf("%hu", r->min.tcp.port);
+ if (r->max.tcp.port != r->min.tcp.port)
+ printf("-%hu", r->max.tcp.port);
+ printf(" ");
+ }
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+ struct ip_nat_multi_range *mr
+ = (struct ip_nat_multi_range *)target->data;
+ struct ip_nat_range *r = &mr->range[0];
+
+ if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+ printf("%hu", r->min.tcp.port);
+ if (r->max.tcp.port != r->min.tcp.port)
+ printf("-%hu", r->max.tcp.port);
+ printf(" ");
+ }
+}
+
+struct iptables_target redir
+= { NULL,
+ "REDIRECT",
+ NETFILTER_VERSION,
+ sizeof(struct ip_nat_multi_range),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_target(&redir);
+}
diff --git a/extensions/libipt_REJECT.c b/extensions/libipt_REJECT.c
new file mode 100644
index 00000000..e3365873
--- /dev/null
+++ b/extensions/libipt_REJECT.c
@@ -0,0 +1,159 @@
+/* Shared library add-on to iptables to add customized REJECT support.
+ *
+ * (C) 2000 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_REJECT.h>
+
+struct reject_names {
+ const char *name;
+ const char *alias;
+ enum ipt_reject_with with;
+ const char *desc;
+};
+
+static const struct reject_names reject_table[] = {
+ {"icmp-net-unreachable", "net-unreach",
+ IPT_ICMP_NET_UNREACHABLE, "ICMP network unreachable"},
+ {"icmp-host-unreachable", "host-unreach",
+ IPT_ICMP_HOST_UNREACHABLE, "ICMP host unreachable"},
+ {"icmp-port-unreachable", "port-unreach",
+ IPT_ICMP_PORT_UNREACHABLE, "ICMP port unreachable (default)"},
+ {"icmp-proto-unreachable", "proto-unreach",
+ IPT_ICMP_PROT_UNREACHABLE, "ICMP protocol unreachable"},
+ {"tcp-reset", "rst",
+ IPT_TCP_RESET, "for TCP only: faked TCP RST"},
+ {"echo-reply", "echoreply",
+ IPT_ICMP_ECHOREPLY, "for ICMP echo only: faked ICMP echo reply"},
+};
+
+static void
+print_reject_types()
+{
+ unsigned int i;
+
+ printf("Valid reject types:\n");
+
+ for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) {
+ printf(" %-25s\t%s\n", reject_table[i].name, reject_table[i].desc);
+ printf(" %-25s\talias\n", reject_table[i].alias);
+ }
+ printf("\n");
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"REJECT options:\n"
+"--reject-with type drop input packet and send back\n"
+" a reply packet according to type:\n");
+
+ print_reject_types();
+}
+
+static struct option opts[] = {
+ { "reject-with", 1, 0, '1' },
+ { 0 }
+};
+
+/* Allocate and initialize the target. */
+static void
+init(struct ipt_entry_target *t, unsigned int *nfcache)
+{
+ struct ipt_reject_info *reject = (struct ipt_reject_info *)t->data;
+
+ /* default */
+ reject->with = IPT_ICMP_PORT_UNREACHABLE;
+
+ /* Can't cache this */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ struct ipt_reject_info *reject = (struct ipt_reject_info *)(*target)->data;
+ unsigned int limit = sizeof(reject_table)/sizeof(struct reject_names);
+ unsigned int i;
+
+ switch(c) {
+ case '1':
+ if (check_inverse(optarg, &invert))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --reject-with");
+ for (i = 0; i < limit; i++) {
+ if ((strncasecmp(reject_table[i].name, optarg, strlen(optarg)) == 0)
+ || (strncasecmp(reject_table[i].alias, optarg, strlen(optarg)) == 0)) {
+ reject->with = reject_table[i].with;
+ return 1;
+ }
+ }
+ exit_error(PARAMETER_PROBLEM, "unknown reject type `%s'",optarg);
+ default:
+ /* Fall through */
+ }
+ return 0;
+}
+
+/* Final check; nothing. */
+static void final_check(unsigned int flags)
+{
+}
+
+/* Prints out ipt_reject_info. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_target *target,
+ int numeric)
+{
+ const struct ipt_reject_info *reject
+ = (const struct ipt_reject_info *)target->data;
+ unsigned int i;
+
+ for (i = 0; i < sizeof(reject_table)/sizeof(struct reject_names); i++) {
+ if (reject_table[i].with == reject->with)
+ break;
+ }
+ printf("reject-with %s ", reject_table[i].name);
+}
+
+/* Saves ipt_reject in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+ const struct ipt_reject_info *reject
+ = (const struct ipt_reject_info *)target->data;
+
+ printf("--reject-with %s ", reject_table[reject->with].name);
+}
+
+struct iptables_target reject
+= { NULL,
+ "REJECT",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_reject_info),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_target(&reject);
+}
diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c
new file mode 100644
index 00000000..86ba39b9
--- /dev/null
+++ b/extensions/libipt_SNAT.c
@@ -0,0 +1,244 @@
+/* Shared library add-on to iptables to add source-NAT support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+/* Source NAT data consists of a multi-range, indicating where to map
+ to. */
+struct ipt_natinfo
+{
+ struct ipt_entry_target t;
+ struct ip_nat_multi_range mr;
+};
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"SNAT v%s options:\n"
+" --to-source <ipaddr>[-<ipaddr>][:port-port]\n"
+" Address to map source to.\n"
+" (You can use this more than once)\n\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "to-source", 1, 0, '1' },
+ { 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ipt_entry_target *t, unsigned int *nfcache)
+{
+ /* Can't cache this */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+static struct ipt_natinfo *
+append_range(struct ipt_natinfo *info, const struct ip_nat_range *range)
+{
+ unsigned int size;
+
+ /* One rangesize already in struct ipt_natinfo */
+ size = IPT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
+
+ info = realloc(info, size);
+ if (!info)
+ exit_error(OTHER_PROBLEM, "Out of memory\n");
+
+ info->t.target_size = size;
+ info->mr.range[info->mr.rangesize] = *range;
+ info->mr.rangesize++;
+
+ return info;
+}
+
+/* Ranges expected in network order. */
+static struct ipt_entry_target *
+parse_to(char *arg, int portok, struct ipt_natinfo *info)
+{
+ struct ip_nat_range range;
+ char *colon, *dash;
+ struct in_addr *ip;
+
+ memset(&range, 0, sizeof(range));
+ colon = strchr(arg, ':');
+
+ if (colon) {
+ int port;
+
+ if (!portok)
+ exit_error(PARAMETER_PROBLEM,
+ "Need TCP or UDP with port specification");
+
+ range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+ port = atoi(colon+1);
+ if (port == 0 || port > 65535)
+ exit_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid\n", colon+1);
+
+ dash = strchr(colon, '-');
+ if (!dash) {
+ range.min.tcp.port
+ = range.max.tcp.port
+ = htons(port);
+ } else {
+ int maxport;
+
+ maxport = atoi(dash + 1);
+ if (maxport == 0 || maxport > 65535)
+ exit_error(PARAMETER_PROBLEM,
+ "Port `%s' not valid\n", dash+1);
+ if (maxport < port)
+ /* People are stupid. */
+ exit_error(PARAMETER_PROBLEM,
+ "Port range `%s' funky\n", colon+1);
+ range.min.tcp.port = htons(port);
+ range.max.tcp.port = htons(maxport);
+ }
+ /* Starts with a colon? No IP info...*/
+ if (colon == arg)
+ return &(append_range(info, &range)->t);
+ *colon = '\0';
+ }
+
+ range.flags |= IP_NAT_RANGE_MAP_IPS;
+ dash = strchr(arg, '-');
+ if (colon && dash && dash > colon)
+ dash = NULL;
+
+ if (dash)
+ *dash = '\0';
+
+ ip = dotted_to_addr(arg);
+ if (!ip)
+ exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+ arg);
+ range.min_ip = ip->s_addr;
+ if (dash) {
+ ip = dotted_to_addr(dash+1);
+ if (!ip)
+ exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+ dash+1);
+ range.max_ip = ip->s_addr;
+ } else
+ range.max_ip = range.min_ip;
+
+ return &(append_range(info, &range)->t);
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ struct ipt_natinfo *info = (void *)*target;
+ int portok;
+
+ if (entry->ip.proto == IPPROTO_TCP
+ || entry->ip.proto == IPPROTO_UDP)
+ portok = 1;
+ else
+ portok = 0;
+
+ switch (c) {
+ case '1':
+ if (check_inverse(optarg, &invert))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --to-source");
+
+ *target = parse_to(optarg, portok, info);
+ *flags = 1;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Final check; must have specfied --to-source. */
+static void final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM,
+ "You must specify --to-source");
+}
+
+static void print_range(const struct ip_nat_range *r)
+{
+ if (r->flags & IP_NAT_RANGE_MAP_IPS) {
+ struct in_addr a;
+
+ a.s_addr = r->min_ip;
+ printf("%s", addr_to_dotted(&a));
+ if (r->max_ip != r->min_ip) {
+ a.s_addr = r->max_ip;
+ printf("-%s", addr_to_dotted(&a));
+ }
+ }
+ if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+ printf(":");
+ printf("%hu", ntohs(r->min.tcp.port));
+ if (r->max.tcp.port != r->min.tcp.port)
+ printf("-%hu", ntohs(r->max.tcp.port));
+ }
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_target *target,
+ int numeric)
+{
+ struct ipt_natinfo *info = (void *)target;
+ unsigned int i = 0;
+
+ printf("to:");
+ for (i = 0; i < info->mr.rangesize; i++) {
+ print_range(&info->mr.range[i]);
+ printf(" ");
+ }
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+ struct ipt_natinfo *info = (void *)target;
+ unsigned int i = 0;
+
+ for (i = 0; i < info->mr.rangesize; i++) {
+ printf("--to-source ");
+ print_range(&info->mr.range[i]);
+ printf(" ");
+ }
+}
+
+struct iptables_target snat
+= { NULL,
+ "SNAT",
+ NETFILTER_VERSION,
+ sizeof(struct ip_nat_multi_range),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_target(&snat);
+}
diff --git a/extensions/libipt_TOS.c b/extensions/libipt_TOS.c
new file mode 100644
index 00000000..4a8e91ba
--- /dev/null
+++ b/extensions/libipt_TOS.c
@@ -0,0 +1,173 @@
+/* Shared library add-on to iptables to add TOS target support. */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_TOS.h>
+
+struct tosinfo {
+ struct ipt_entry_target t;
+ struct ipt_tos_target_info tos;
+};
+
+/* TOS names and values. */
+struct TOS_value
+{
+ unsigned char TOS;
+ const char *name;
+} TOS_values[] = {
+ { IPTOS_LOWDELAY, "Minimize-Delay" },
+ { IPTOS_THROUGHPUT, "Maximize-Throughput" },
+ { IPTOS_RELIABILITY, "Maximize-Reliability" },
+ { IPTOS_MINCOST, "Minimize-Cost" },
+ { IPTOS_NORMALSVC, "Normal-Service" },
+};
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ unsigned int i;
+
+ printf(
+"TOS target v%s options:\n"
+" --set-tos value Set Type of Service field to one of the\n"
+" following numeric or descriptive values:\n",
+NETFILTER_VERSION);
+
+ for (i = 0; i < sizeof(TOS_values)/sizeof(struct TOS_value);i++)
+ printf(" %s %u (0x%02x)\n",
+ TOS_values[i].name,
+ TOS_values[i].TOS,
+ TOS_values[i].TOS);
+ fputc('\n', stdout);
+}
+
+static struct option opts[] = {
+ { "set-tos", 1, 0, '1' },
+ { 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ipt_entry_target *t, unsigned int *nfcache)
+{
+}
+
+static void
+parse_tos(const unsigned char *s, struct ipt_tos_target_info *info)
+{
+ unsigned int i;
+ int tos = string_to_number(s, 0, 255);
+
+ if (tos != -1) {
+ if (tos == IPTOS_LOWDELAY
+ || tos == IPTOS_THROUGHPUT
+ || tos == IPTOS_RELIABILITY
+ || tos == IPTOS_MINCOST
+ || tos == IPTOS_NORMALSVC) {
+ info->tos = (u_int8_t )tos;
+ return;
+ }
+ } else {
+ for (i = 0; i<sizeof(TOS_values)/sizeof(struct TOS_value); i++)
+ if (strcasecmp(s,TOS_values[i].name) == 0) {
+ info->tos = TOS_values[i].TOS;
+ return;
+ }
+ }
+ exit_error(PARAMETER_PROBLEM, "Bad TOS value `%s'", s);
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ struct ipt_tos_target_info *tosinfo
+ = (struct ipt_tos_target_info *)(*target)->data;
+
+ switch (c) {
+ case '1':
+ if (*flags)
+ exit_error(PARAMETER_PROBLEM,
+ "TOS target: Cant specify --set-tos twice");
+ parse_tos(optarg, tosinfo);
+ *flags = 1;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static void
+final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM,
+ "TOS target: Parameter --set-tos is required");
+}
+
+static void
+print_tos(u_int8_t tos, int numeric)
+{
+ unsigned int i;
+
+ if (!numeric) {
+ for (i = 0; i<sizeof(TOS_values)/sizeof(struct TOS_value); i++)
+ if (TOS_values[i].TOS == tos) {
+ printf("%s ", TOS_values[i].name);
+ return;
+ }
+ }
+ printf("0x%02x ", tos);
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_target *target,
+ int numeric)
+{
+ const struct ipt_tos_target_info *tosinfo =
+ (const struct ipt_tos_target_info *)target->data;
+ printf("TOS set ");
+ print_tos(tosinfo->tos, numeric);
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+ const struct ipt_tos_target_info *tosinfo =
+ (const struct ipt_tos_target_info *)target->data;
+
+ printf("--set-tos 0x%02x ", tosinfo->tos);
+}
+
+struct iptables_target tos
+= { NULL,
+ "TOS",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_tos_target_info),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_target(&tos);
+}
diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c
new file mode 100644
index 00000000..65857ce3
--- /dev/null
+++ b/extensions/libipt_icmp.c
@@ -0,0 +1,295 @@
+/* Shared library add-on to iptables to add ICMP support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+struct icmp_names {
+ const char *name;
+ u_int8_t type;
+ u_int8_t code_min, code_max;
+};
+
+static const struct icmp_names icmp_codes[] = {
+ { "echo-reply", 0, 0, 0xFF },
+ /* Alias */ { "pong", 0, 0, 0xFF },
+
+ { "destination-unreachable", 3, 0, 0xFF },
+ { "network-unreachable", 3, 0, 0 },
+ { "host-unreachable", 3, 1, 1 },
+ { "protocol-unreachable", 3, 2, 2 },
+ { "port-unreachable", 3, 3, 3 },
+ { "fragmentation-needed", 3, 4, 4 },
+ { "source-route-failed", 3, 5, 5 },
+ { "network-unknown", 3, 6, 6 },
+ { "host-unknown", 3, 7, 7 },
+ { "network-prohibited", 3, 9, 9 },
+ { "host-prohibited", 3, 10, 10 },
+ { "TOS-network-unreachable", 3, 11, 11 },
+ { "TOS-host-unreachable", 3, 12, 12 },
+ { "communication-prohibited", 3, 13, 13 },
+ { "host-precedence-violation", 3, 14, 14 },
+ { "precedence-cutoff", 3, 15, 15 },
+
+ { "source-quench", 4, 0, 0xFF },
+
+ { "redirect", 5, 0, 0xFF },
+ { "network-redirect", 5, 0, 0 },
+ { "host-redirect", 5, 1, 1 },
+ { "TOS-network-redirect", 5, 2, 2 },
+ { "TOS-host-redirect", 5, 3, 3 },
+
+ { "echo-request", 8, 0, 0xFF },
+ /* Alias */ { "ping", 8, 0, 0xFF },
+
+ { "router-advertisement", 9, 0, 0xFF },
+
+ { "router-solicitation", 10, 0, 0xFF },
+
+ { "time-exceeded", 11, 0, 0xFF },
+ /* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
+ { "ttl-zero-during-transit", 11, 0, 0 },
+ { "ttl-zero-during-reassembly", 11, 1, 1 },
+
+ { "parameter-problem", 12, 0, 0xFF },
+ { "ip-header-bad", 12, 0, 0 },
+ { "required-option-missing", 12, 1, 1 },
+
+ { "timestamp-request", 13, 0, 0xFF },
+
+ { "timestamp-reply", 14, 0, 0xFF },
+
+ { "address-mask-request", 17, 0, 0xFF },
+
+ { "address-mask-reply", 18, 0, 0xFF }
+};
+
+static void
+print_icmptypes()
+{
+ unsigned int i;
+ printf("Valid ICMP Types:");
+
+ for (i = 0; i < sizeof(icmp_codes)/sizeof(struct icmp_names); i++) {
+ if (i && icmp_codes[i].type == icmp_codes[i-1].type) {
+ if (icmp_codes[i].code_min == icmp_codes[i-1].code_min
+ && (icmp_codes[i].code_max
+ == icmp_codes[i-1].code_max))
+ printf(" (%s)", icmp_codes[i].name);
+ else
+ printf("\n %s", icmp_codes[i].name);
+ }
+ else
+ printf("\n%s", icmp_codes[i].name);
+ }
+ printf("\n");
+}
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"ICMP v%s options:\n"
+" --icmp-type [!] typename match icmp type\n"
+" (or numeric type or type/code)\n"
+"\n", NETFILTER_VERSION);
+ print_icmptypes();
+}
+
+static struct option opts[] = {
+ { "icmp-type", 1, 0, '1' },
+ {0}
+};
+
+static unsigned int
+parse_icmp(const char *icmptype, u_int8_t *type, u_int8_t code[])
+{
+ unsigned int limit = sizeof(icmp_codes)/sizeof(struct icmp_names);
+ unsigned int match = limit;
+ unsigned int i;
+
+ for (i = 0; i < limit; i++) {
+ if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype))
+ == 0) {
+ if (match != limit)
+ exit_error(PARAMETER_PROBLEM,
+ "Ambiguous ICMP type `%s':"
+ " `%s' or `%s'?",
+ icmptype,
+ icmp_codes[match].name,
+ icmp_codes[i].name);
+ match = i;
+ }
+ }
+
+ if (match != limit) {
+ *type = icmp_codes[match].type;
+ code[0] = icmp_codes[match].code_min;
+ code[1] = icmp_codes[match].code_max;
+ } else {
+ char *slash;
+ char buffer[strlen(icmptype) + 1];
+ int number;
+
+ strcpy(buffer, icmptype);
+ slash = strchr(buffer, '/');
+
+ if (slash)
+ *slash = '\0';
+
+ number = string_to_number(buffer, 0, 255);
+ if (number == -1)
+ exit_error(PARAMETER_PROBLEM,
+ "Invalid ICMP type `%s'\n", buffer);
+ *type = number;
+ if (slash) {
+ number = string_to_number(slash+1, 0, 255);
+ if (number == -1)
+ exit_error(PARAMETER_PROBLEM,
+ "Invalid ICMP code `%s'\n",
+ slash+1);
+ code[0] = code[1] = number;
+ } else {
+ code[0] = 0;
+ code[1] = 0xFF;
+ }
+ }
+
+ if (code[0] == 0 && code[1] == 0xFF)
+ return NFC_IP_SRC_PT;
+ else return NFC_IP_SRC_PT | NFC_IP_DST_PT;
+}
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ struct ipt_icmp *icmpinfo = (struct ipt_icmp *)m->data;
+
+ icmpinfo->code[1] = 0xFF;
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+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_icmp *icmpinfo = (struct ipt_icmp *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ if (check_inverse(optarg, &invert))
+ optind++;
+ *nfcache |= parse_icmp(argv[optind-1],
+ &icmpinfo->type,
+ icmpinfo->code);
+ if (invert)
+ icmpinfo->invflags |= IPT_ICMP_INV;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static void print_icmptype(u_int8_t type,
+ u_int8_t code_min, u_int8_t code_max,
+ int invert,
+ int numeric)
+{
+ if (!numeric) {
+ unsigned int i;
+
+ for (i = 0;
+ i < sizeof(icmp_codes)/sizeof(struct icmp_names);
+ i++) {
+ if (icmp_codes[i].type == type
+ && icmp_codes[i].code_min == code_min
+ && icmp_codes[i].code_max == code_max)
+ break;
+ }
+
+ if (i != sizeof(icmp_codes)/sizeof(struct icmp_names)) {
+ printf("%s%s ",
+ invert ? "!" : "",
+ icmp_codes[i].name);
+ return;
+ }
+ }
+
+ if (invert)
+ printf("!");
+
+ printf("type %u", type);
+ if (code_min == 0 && code_max == 0xFF)
+ printf(" ");
+ else if (code_min == code_max)
+ printf(" code %u ", code_min);
+ else
+ printf(" codes %u-%u ", code_min, code_max);
+}
+
+/* Prints out the union ipt_matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match,
+ int numeric)
+{
+ const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
+
+ printf("icmp ");
+ print_icmptype(icmp->type, icmp->code[0], icmp->code[1],
+ icmp->invflags & IPT_ICMP_INV,
+ numeric);
+
+ if (icmp->invflags & ~IPT_ICMP_INV)
+ printf("Unknown invflags: 0x%X ",
+ icmp->invflags & ~IPT_ICMP_INV);
+}
+
+/* Saves the match in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data;
+
+ if (icmp->invflags & IPT_ICMP_INV)
+ printf("! ");
+
+ printf("--icmp-type %u", icmp->type);
+ if (icmp->code[0] != 0 || icmp->code[1] != 0xFF)
+ printf("/%u", icmp->code[0]);
+ printf(" ");
+}
+
+/* Final check; we don't care. */
+static void final_check(unsigned int flags)
+{
+}
+
+struct iptables_match icmp
+= { NULL,
+ "icmp",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_icmp),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_match(&icmp);
+}
diff --git a/extensions/libipt_limit.c b/extensions/libipt_limit.c
new file mode 100644
index 00000000..aed63059
--- /dev/null
+++ b/extensions/libipt_limit.c
@@ -0,0 +1,196 @@
+/* Shared library add-on to iptables to add limit support.
+ *
+ * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
+ * Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_limit.h>
+
+#define IPT_LIMIT_AVG "3/hour"
+#define IPT_LIMIT_BURST 5
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"limit v%s options:\n"
+"--limit avg max average match rate: default "IPT_LIMIT_AVG"\n"
+" [Packets per second unless followed by \n"
+" /sec /minute /hour /day postfixes]\n"
+"--limit-burst number number to match in a burst, default %u\n"
+"\n", NETFILTER_VERSION, IPT_LIMIT_BURST);
+}
+
+static struct option opts[] = {
+ { "limit", 1, 0, '%' },
+ { "limit-burst", 1, 0, '$' },
+ { 0 }
+};
+
+static
+int parse_rate(const char *rate, u_int32_t *val)
+{
+ const char *delim;
+ u_int32_t r;
+ u_int32_t mult = 1; /* Seconds by default. */
+
+ delim = strchr(rate, '/');
+ if (delim) {
+ if (strlen(delim+1) == 0)
+ return 0;
+
+ if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
+ mult = 1;
+ else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
+ mult = 60;
+ else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
+ mult = 60*60;
+ else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
+ mult = 24*60*60;
+ else
+ return 0;
+ }
+ r = atoi(rate);
+ if (!r)
+ return 0;
+
+ /* This would get mapped to infinite (1/day is minimum they
+ can specify, so we're ok at that end). */
+ if (r / mult > IPT_LIMIT_SCALE)
+ exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate);
+
+ *val = IPT_LIMIT_SCALE * mult / r;
+ return 1;
+}
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ struct ipt_rateinfo *r = (struct ipt_rateinfo *)m->data;
+
+ parse_rate(IPT_LIMIT_AVG, &r->avg);
+ r->burst = IPT_LIMIT_BURST;
+
+ /* Can't cache this */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+/* FIXME: handle overflow:
+ if (r->avg*r->burst/r->burst != r->avg)
+ exit_error(PARAMETER_PROBLEM,
+ "Sorry: burst too large for that avg rate.\n");
+*/
+
+/* Function which parses command options; returns true if it
+ ate an option */
+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_rateinfo *r = (struct ipt_rateinfo *)(*match)->data;
+ int num;
+
+ switch(c) {
+ case '%':
+ if (check_inverse(optarg, &invert))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --limit");
+ if (!parse_rate(optarg, &r->avg))
+ exit_error(PARAMETER_PROBLEM,
+ "bad rate `%s'", optarg);
+ break;
+
+ case '$':
+ if (check_inverse(optarg, &invert))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected `!' after --limit-burst");
+
+ num = string_to_number(optarg, 0, 10000);
+ if (num <= 0)
+ exit_error(PARAMETER_PROBLEM,
+ "bad --limit-burst `%s'", optarg);
+ r->burst = num;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Final check; nothing. */
+static void final_check(unsigned int flags)
+{
+}
+
+static struct rates
+{
+ const char *name;
+ u_int32_t mult;
+} rates[] = { { "day", IPT_LIMIT_SCALE*24*60*60 },
+ { "hour", IPT_LIMIT_SCALE*60*60 },
+ { "min", IPT_LIMIT_SCALE*60 },
+ { "sec", IPT_LIMIT_SCALE } };
+
+static void print_rate(u_int32_t period)
+{
+ unsigned int i;
+
+ for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) {
+ if (period > rates[i].mult
+ || rates[i].mult % period != 0)
+ break;
+ }
+
+ printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name);
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match,
+ int numeric)
+{
+ struct ipt_rateinfo *r = (struct ipt_rateinfo *)match->data;
+ printf("limit: avg "); print_rate(r->avg);
+ printf("burst %u ", r->burst);
+}
+
+/* FIXME: Make minimalist: only print rate if not default --RR */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ struct ipt_rateinfo *r = (struct ipt_rateinfo *)match->data;
+
+ printf("--limit "); print_rate(r->avg);
+ if (r->burst != IPT_LIMIT_BURST)
+ printf("--limit-burst %u ", r->burst);
+}
+
+struct iptables_match limit
+= { NULL,
+ "limit",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_rateinfo),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_match(&limit);
+}
diff --git a/extensions/libipt_mac.c b/extensions/libipt_mac.c
new file mode 100644
index 00000000..36d89692
--- /dev/null
+++ b/extensions/libipt_mac.c
@@ -0,0 +1,144 @@
+/* Shared library add-on to iptables to add MAC address support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#if defined(__GLIBC__) && __GLIBC__ == 2
+#include <net/ethernet.h>
+#else
+#include <linux/if_ether.h>
+#endif
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ipt_mac.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"MAC v%s options:\n"
+" --mac-source [!] XX:XX:XX:XX:XX:XX\n"
+" Match source MAC address\n"
+"\n", NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "mac-source", 1, 0, '1' },
+ {0}
+};
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ /* Can't cache this */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+static void
+parse_mac(const char *mac, struct ipt_mac_info *info)
+{
+ unsigned int i = 0;
+
+ if (strlen(mac) != ETH_ALEN*3-1)
+ exit_error(PARAMETER_PROBLEM, "Bad mac address `%s'", mac);
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ long number;
+ char *end;
+
+ number = strtol(mac + i*3, &end, 16);
+
+ if (end == mac + i*3 + 2
+ && number >= 0
+ && number <= 255)
+ info->srcaddr[i] = number;
+ else
+ exit_error(PARAMETER_PROBLEM,
+ "Bad mac address `%s'", mac);
+ }
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+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_mac_info *macinfo = (struct ipt_mac_info *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ if (check_inverse(optarg, &invert))
+ optind++;
+ parse_mac(argv[optind-1], macinfo);
+ if (invert)
+ macinfo->invert = 1;
+ *flags = 1;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static void print_mac(unsigned char macaddress[ETH_ALEN], int invert)
+{
+ unsigned int i;
+
+ printf("%s%02X", invert ? "!" : "", macaddress[0]);
+ for (i = 1; i < ETH_ALEN; i++)
+ printf(":%02X", macaddress[i]);
+ printf(" ");
+}
+
+/* Final check; must have specified --mac. */
+static void final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM,
+ "You must specify `--mac-source'");
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match,
+ int numeric)
+{
+ printf("MAC ");
+ print_mac(((struct ipt_mac_info *)match->data)->srcaddr,
+ ((struct ipt_mac_info *)match->data)->invert);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ printf("--mac ");
+ print_mac(((struct ipt_mac_info *)match->data)->srcaddr,
+ ((struct ipt_mac_info *)match->data)->invert);
+}
+
+struct iptables_match mac
+= { NULL,
+ "mac",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_mac_info),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_match(&mac);
+}
diff --git a/extensions/libipt_mark.c b/extensions/libipt_mark.c
new file mode 100644
index 00000000..318cd94d
--- /dev/null
+++ b/extensions/libipt_mark.c
@@ -0,0 +1,128 @@
+/* Shared library add-on to iptables to add NFMARK matching support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ipt_mark.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"MARK match v%s options:\n"
+"[!] --mark value[/mask] Match nfmark value with optional mask\n"
+"\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "mark", 1, 0, '1' },
+ {0}
+};
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ /* Can't cache this. */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+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_mark_info *markinfo = (struct ipt_mark_info *)(*match)->data;
+
+ switch (c) {
+ char *end;
+ case '1':
+ if (check_inverse(optarg, &invert))
+ optind++;
+ markinfo->mark = strtoul(optarg, &end, 0);
+ if (*end == '/') {
+ markinfo->mask = strtoul(end+1, &end, 0);
+ } else
+ markinfo->mask = 0xffffffff;
+ if (*end != '\0' || end == optarg)
+ exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
+ if (invert)
+ markinfo->invert = 1;
+ *flags = 1;
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void
+print_mark(unsigned long mark, unsigned long mask, int invert, int numeric)
+{
+ if (invert)
+ fputc('!', stdout);
+
+ if(mask != 0xffffffff)
+ printf("0x%lx/0x%lx ", mark, mask);
+ else
+ printf("0x%lx ", mark);
+}
+
+/* Final check; must have specified --mark. */
+static void
+final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM,
+ "MARK match: You must specify `--mark'");
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match,
+ int numeric)
+{
+ printf("MARK match ");
+ print_mark(((struct ipt_mark_info *)match->data)->mark,
+ ((struct ipt_mark_info *)match->data)->mask,
+ ((struct ipt_mark_info *)match->data)->invert, numeric);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ printf("--mark ");
+ print_mark(((struct ipt_mark_info *)match->data)->mark,
+ ((struct ipt_mark_info *)match->data)->mask,
+ ((struct ipt_mark_info *)match->data)->invert, 0);
+}
+
+struct iptables_match mark
+= { NULL,
+ "mark",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_mark_info),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_match(&mark);
+}
diff --git a/extensions/libipt_multiport.c b/extensions/libipt_multiport.c
new file mode 100644
index 00000000..727f95fc
--- /dev/null
+++ b/extensions/libipt_multiport.c
@@ -0,0 +1,262 @@
+/* Shared library add-on to iptables to add multiple TCP port support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ipt_multiport.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"multiport v%s options:\n"
+" --source-ports port[,port,port...]\n"
+" --sports ...\n"
+" match source port(s)\n"
+" --destination-ports port[,port,port...]\n"
+" --dports ...\n"
+" match destination port(s)\n"
+" --ports port[,port,port]\n"
+" match both source and destination port(s)\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "source-ports", 1, 0, '1' },
+ { "sports", 1, 0, '1' }, /* synonym */
+ { "destination-ports", 1, 0, '2' },
+ { "dports", 1, 0, '2' }, /* synonym */
+ { "ports", 1, 0, '3' },
+ {0}
+};
+
+static int
+service_to_port(const char *name, const char *proto)
+{
+ struct servent *service;
+
+ if ((service = getservbyname(name, proto)) != NULL)
+ return ntohs((unsigned short) service->s_port);
+
+ return -1;
+}
+
+static u_int16_t
+parse_port(const char *port, const char *proto)
+{
+ int portnum;
+ if ((portnum = string_to_number(port, 0, 65535)) != -1 ||
+ (portnum = service_to_port(port, proto)) != -1)
+ return (u_int16_t)portnum;
+
+ exit_error(PARAMETER_PROBLEM,
+ "invalid port/service `%s' specified", port);
+}
+
+static unsigned int
+parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto)
+{
+ char *buffer, *cp, *next;
+ unsigned int i;
+
+ buffer = strdup(portstring);
+ if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
+
+ for (cp=buffer, i=0; cp && i<IPT_MULTI_PORTS; cp=next,i++)
+ {
+ next=strchr(cp, ',');
+ if (next) *next++='\0';
+ ports[i] = parse_port(cp, proto);
+ }
+ if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
+ free(buffer);
+ return i;
+}
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+}
+
+static const char *
+check_proto(const struct ipt_entry *entry)
+{
+ if (entry->ip.proto == IPPROTO_TCP)
+ return "tcp";
+ else if (entry->ip.proto == IPPROTO_UDP)
+ return "udp";
+ else if (!entry->ip.proto)
+ exit_error(PARAMETER_PROBLEM,
+ "multiport needs `-p tcp' or `-p udp'");
+ else
+ exit_error(PARAMETER_PROBLEM,
+ "multiport only works with TCP or UDP");
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+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)
+{
+ const char *proto;
+ struct ipt_multiport *multiinfo
+ = (struct ipt_multiport *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ proto = check_proto(entry);
+ multiinfo->count = parse_multi_ports(argv[optind-1],
+ multiinfo->ports, proto);
+ multiinfo->flags = IPT_MULTIPORT_SOURCE;
+ *nfcache |= NFC_IP_SRC_PT;
+ break;
+
+ case '2':
+ proto = check_proto(entry);
+ multiinfo->count = parse_multi_ports(argv[optind-1],
+ multiinfo->ports, proto);
+ multiinfo->flags = IPT_MULTIPORT_DESTINATION;
+ *nfcache |= NFC_IP_DST_PT;
+ break;
+
+ case '3':
+ proto = check_proto(entry);
+ multiinfo->count = parse_multi_ports(argv[optind-1],
+ multiinfo->ports, proto);
+ multiinfo->flags = IPT_MULTIPORT_EITHER;
+ *nfcache |= NFC_IP_SRC_PT | NFC_IP_DST_PT;
+ break;
+
+ default:
+ return 0;
+ }
+
+ if (*flags)
+ exit_error(PARAMETER_PROBLEM,
+ "multiport can only have one option");
+ *flags = 1;
+ return 1;
+}
+
+/* Final check; must specify something. */
+static void
+final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM, "multiport expection an option");
+}
+
+static char *
+port_to_service(int port, u_int8_t proto)
+{
+ struct servent *service;
+
+ if ((service = getservbyport(htons(port),
+ proto == IPPROTO_TCP ? "tcp" : "udp")))
+ return service->s_name;
+
+ return NULL;
+}
+
+static void
+print_port(u_int16_t port, u_int8_t protocol, int numeric)
+{
+ char *service;
+
+ if (numeric || (service = port_to_service(port, protocol)) == NULL)
+ printf("%u", port);
+ else
+ printf("%s", service);
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match,
+ int numeric)
+{
+ const struct ipt_multiport *multiinfo
+ = (const struct ipt_multiport *)match->data;
+ unsigned int i;
+
+ printf("multiport ");
+
+ switch (multiinfo->flags) {
+ case IPT_MULTIPORT_SOURCE:
+ printf("sports ");
+ break;
+
+ case IPT_MULTIPORT_DESTINATION:
+ printf("dports ");
+ break;
+
+ case IPT_MULTIPORT_EITHER:
+ printf("ports ");
+ break;
+
+ default:
+ printf("ERROR ");
+ break;
+ }
+
+ for (i=0; i < multiinfo->count; i++) {
+ printf("%s", i ? "," : "");
+ print_port(multiinfo->ports[i], ip->proto, numeric);
+ }
+ printf(" ");
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ const struct ipt_multiport *multiinfo
+ = (const struct ipt_multiport *)match->data;
+ unsigned int i;
+
+ switch (multiinfo->flags) {
+ case IPT_MULTIPORT_SOURCE:
+ printf("--sports ");
+ break;
+
+ case IPT_MULTIPORT_DESTINATION:
+ printf("--dports ");
+ break;
+
+ case IPT_MULTIPORT_EITHER:
+ printf("--ports ");
+ break;
+ }
+
+ for (i=0; i < multiinfo->count; i++) {
+ printf("%s", i ? "," : "");
+ print_port(multiinfo->ports[i], ip->proto, 0);
+ }
+ printf(" ");
+}
+
+struct iptables_match multiport
+= { NULL,
+ "multiport",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_multiport),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void
+_init(void)
+{
+ register_match(&multiport);
+}
diff --git a/extensions/libipt_owner.c b/extensions/libipt_owner.c
new file mode 100644
index 00000000..29311022
--- /dev/null
+++ b/extensions/libipt_owner.c
@@ -0,0 +1,219 @@
+/* Shared library add-on to iptables to add OWNER matching support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ipt_owner.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"OWNER match v%s options:\n"
+"[!] --uid-owner userid Match local uid\n"
+"[!] --gid-owner groupid Match local gid\n"
+"[!] --pid-owner processid Match local pid\n"
+"[!] --sid-owner sessionid Match local sid\n"
+"\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "uid-owner", 1, 0, '1' },
+ { "gid-owner", 1, 0, '2' },
+ { "pid-owner", 1, 0, '3' },
+ { "sid-owner", 1, 0, '4' },
+ {0}
+};
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ /* Can't cache this. */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+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_owner_info *ownerinfo = (struct ipt_owner_info *)(*match)->data;
+
+ switch (c) {
+ char *end;
+ struct passwd *pwd;
+ struct group *grp;
+ case '1':
+ if (check_inverse(optarg, &invert))
+ optind++;
+
+ if ((pwd = getpwnam(optarg)))
+ ownerinfo->uid = pwd->pw_uid;
+ else {
+ ownerinfo->uid = strtoul(optarg, &end, 0);
+ if (*end != '\0' || end == optarg)
+ exit_error(PARAMETER_PROBLEM, "Bad OWNER UID value `%s'", optarg);
+ }
+ if (invert)
+ ownerinfo->invert |= IPT_OWNER_UID;
+ ownerinfo->match |= IPT_OWNER_UID;
+ *flags = 1;
+ break;
+
+ case '2':
+ if (check_inverse(optarg, &invert))
+ optind++;
+ if ((grp = getgrnam(optarg)))
+ ownerinfo->gid = grp->gr_gid;
+ else {
+ ownerinfo->gid = strtoul(optarg, &end, 0);
+ if (*end != '\0' || end == optarg)
+ exit_error(PARAMETER_PROBLEM, "Bad OWNER GID value `%s'", optarg);
+ }
+ if (invert)
+ ownerinfo->invert |= IPT_OWNER_GID;
+ ownerinfo->match |= IPT_OWNER_GID;
+ *flags = 1;
+ break;
+
+ case '3':
+ if (check_inverse(optarg, &invert))
+ optind++;
+ ownerinfo->pid = strtoul(optarg, &end, 0);
+ if (*end != '\0' || end == optarg)
+ exit_error(PARAMETER_PROBLEM, "Bad OWNER PID value `%s'", optarg);
+ if (invert)
+ ownerinfo->invert |= IPT_OWNER_PID;
+ ownerinfo->match |= IPT_OWNER_PID;
+ *flags = 1;
+ break;
+
+ case '4':
+ if (check_inverse(optarg, &invert))
+ optind++;
+ ownerinfo->sid = strtoul(optarg, &end, 0);
+ if (*end != '\0' || end == optarg)
+ exit_error(PARAMETER_PROBLEM, "Bad OWNER SID value `%s'", optarg);
+ if (invert)
+ ownerinfo->invert |= IPT_OWNER_SID;
+ ownerinfo->match |= IPT_OWNER_SID;
+ *flags = 1;
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void
+print_item(struct ipt_owner_info *info, u_int8_t flag, int numeric, char *label)
+{
+ if(info->match & flag) {
+
+ printf(label);
+
+ if (info->invert & flag)
+ fputc('!', stdout);
+
+ switch(info->match & flag) {
+ case IPT_OWNER_UID:
+ if(!numeric) {
+ struct passwd *pwd = getpwuid(info->uid);
+
+ if(pwd && pwd->pw_name) {
+ printf("%s ", pwd->pw_name);
+ break;
+ }
+ /* FALLTHROUGH */
+ }
+ printf("%u ", info->uid);
+ break;
+ case IPT_OWNER_GID:
+ if(!numeric) {
+ struct group *grp = getgrgid(info->gid);
+
+ if(grp && grp->gr_name) {
+ printf("%s ", grp->gr_name);
+ break;
+ }
+ /* FALLTHROUGH */
+ }
+ printf("%u ", info->gid);
+ break;
+ case IPT_OWNER_PID:
+ printf("%u ", info->pid);
+ break;
+ case IPT_OWNER_SID:
+ printf("%u ", info->sid);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/* Final check; must have specified --own. */
+static void
+final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM,
+ "OWNER match: You must specify one or more options");
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match,
+ int numeric)
+{
+ struct ipt_owner_info *info = (struct ipt_owner_info *)match->data;
+
+ print_item(info, IPT_OWNER_UID, numeric, "OWNER UID match ");
+ print_item(info, IPT_OWNER_GID, numeric, "OWNER GID match ");
+ print_item(info, IPT_OWNER_PID, numeric, "OWNER PID match ");
+ print_item(info, IPT_OWNER_SID, numeric, "OWNER SID match ");
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ struct ipt_owner_info *info = (struct ipt_owner_info *)match->data;
+
+ print_item(info, IPT_OWNER_UID, 0, "--uid-owner ");
+ print_item(info, IPT_OWNER_GID, 0, "--gid-owner ");
+ print_item(info, IPT_OWNER_PID, 0, "--pid-owner ");
+ print_item(info, IPT_OWNER_SID, 0, "--sid-owner ");
+}
+
+struct iptables_match owner
+= { NULL,
+ "owner",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_owner_info),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_match(&owner);
+}
diff --git a/extensions/libipt_standard.c b/extensions/libipt_standard.c
new file mode 100644
index 00000000..9a746b2d
--- /dev/null
+++ b/extensions/libipt_standard.c
@@ -0,0 +1,67 @@
+/* Shared library add-on to iptables for standard target support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <getopt.h>
+#include <iptables.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"Standard v%s options:\n"
+"(If target is DROP, ACCEPT, RETURN or nothing)\n", NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ {0}
+};
+
+/* Initialize the target. */
+static void
+init(struct ipt_entry_target *t, unsigned int *nfcache)
+{
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ return 0;
+}
+
+/* Final check; don't care. */
+static void final_check(unsigned int flags)
+{
+}
+
+/* Saves the targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+}
+
+struct iptables_target standard
+= { NULL,
+ "standard",
+ NETFILTER_VERSION,
+ sizeof(int),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ NULL, /* print */
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_target(&standard);
+}
diff --git a/extensions/libipt_state.c b/extensions/libipt_state.c
new file mode 100644
index 00000000..19751d72
--- /dev/null
+++ b/extensions/libipt_state.c
@@ -0,0 +1,162 @@
+/* Shared library add-on to iptables to add state tracking support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ipt_state.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"state v%s options:\n"
+" [!] --state [INVALID|ESTABLISHED|NEW|RELATED][,...]\n"
+" State(s) to match\n"
+"\n", NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "state", 1, 0, '1' },
+ {0}
+};
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ /* Can't cache this */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+static int
+parse_state(const char *state, size_t strlen, struct ipt_state_info *sinfo)
+{
+ if (strncasecmp(state, "INVALID", strlen) == 0)
+ sinfo->statemask |= IPT_STATE_INVALID;
+ else if (strncasecmp(state, "NEW", strlen) == 0)
+ sinfo->statemask |= IPT_STATE_BIT(IP_CT_NEW);
+ else if (strncasecmp(state, "ESTABLISHED", strlen) == 0)
+ sinfo->statemask |= IPT_STATE_BIT(IP_CT_ESTABLISHED);
+ else if (strncasecmp(state, "RELATED", strlen) == 0)
+ sinfo->statemask |= IPT_STATE_BIT(IP_CT_RELATED);
+ else
+ return 0;
+ return 1;
+}
+
+static void
+parse_states(const char *arg, struct ipt_state_info *sinfo)
+{
+ const char *comma;
+
+ while ((comma = strchr(arg, ',')) != NULL) {
+ if (comma == arg || !parse_state(arg, comma-arg, sinfo))
+ exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg);
+ arg = comma+1;
+ }
+
+ if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo))
+ exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg);
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+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_state_info *sinfo = (struct ipt_state_info *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ if (check_inverse(optarg, &invert))
+ optind++;
+
+ parse_states(argv[optind-1], sinfo);
+ if (invert)
+ sinfo->statemask = ~sinfo->statemask;
+ *flags = 1;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Final check; must have specified --state. */
+static void final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM, "You must specify `--state'");
+}
+
+static void print_state(unsigned int statemask)
+{
+ const char *sep = "";
+
+ if (statemask & IPT_STATE_INVALID) {
+ printf("%sINVALID", sep);
+ sep = ",";
+ }
+ if (statemask & IPT_STATE_BIT(IP_CT_NEW)) {
+ printf("%sNEW", sep);
+ sep = ",";
+ }
+ if (statemask & IPT_STATE_BIT(IP_CT_RELATED)) {
+ printf("%sRELATED", sep);
+ sep = ",";
+ }
+ if (statemask & IPT_STATE_BIT(IP_CT_ESTABLISHED)) {
+ printf("%sESTABLISHED", sep);
+ sep = ",";
+ }
+ printf(" ");
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match,
+ int numeric)
+{
+ struct ipt_state_info *sinfo = (struct ipt_state_info *)match->data;
+
+ printf("state ");
+ print_state(sinfo->statemask);
+}
+
+/* Saves the matchinfo in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ struct ipt_state_info *sinfo = (struct ipt_state_info *)match->data;
+
+ printf("--state ");
+ print_state(sinfo->statemask);
+}
+
+struct iptables_match state
+= { NULL,
+ "state",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_state_info),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_match(&state);
+}
diff --git a/extensions/libipt_tcp.c b/extensions/libipt_tcp.c
new file mode 100644
index 00000000..94285a09
--- /dev/null
+++ b/extensions/libipt_tcp.c
@@ -0,0 +1,439 @@
+/* Shared library add-on to iptables to add TCP support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"TCP v%s options:\n"
+" --tcp-flags [!] mask comp match when TCP flags & mask == comp\n"
+" (Flags: SYN ACK FIN RST URG PSH ALL NONE)\n"
+"[!] --syn match when only SYN flag set\n"
+" (equivalent to --tcp-flags SYN,RST,ACK SYN)\n"
+" --source-port [!] port[:port]\n"
+" --sport ...\n"
+" match source port(s)\n"
+" --destination-port [!] port[:port]\n"
+" --dport ...\n"
+" match destination port(s)\n"
+" --tcp-option [!] number match if TCP option set\n\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "source-port", 1, 0, '1' },
+ { "sport", 1, 0, '1' }, /* synonym */
+ { "destination-port", 1, 0, '2' },
+ { "dport", 1, 0, '2' }, /* synonym */
+ { "syn", 0, 0, '3' },
+ { "tcp-flags", 1, 0, '4' },
+ { "tcp-option", 1, 0, '5' },
+ {0}
+};
+
+static int
+service_to_port(const char *name)
+{
+ struct servent *service;
+
+ if ((service = getservbyname(name, "tcp")) != NULL)
+ return ntohs((unsigned short) service->s_port);
+
+ return -1;
+}
+
+static u_int16_t
+parse_tcp_port(const char *port)
+{
+ int portnum;
+
+ if ((portnum = string_to_number(port, 0, 65535)) != -1 ||
+ (portnum = service_to_port(port)) != -1)
+ return (u_int16_t)portnum;
+
+ exit_error(PARAMETER_PROBLEM,
+ "invalid TCP port/service `%s' specified", port);
+}
+
+static void
+parse_tcp_ports(const char *portstring, u_int16_t *ports)
+{
+ char *buffer;
+ char *cp;
+
+ buffer = strdup(portstring);
+ if ((cp = strchr(buffer, ':')) == NULL)
+ ports[0] = ports[1] = parse_tcp_port(buffer);
+ else {
+ *cp = '\0';
+ cp++;
+
+ ports[0] = buffer[0] ? parse_tcp_port(buffer) : 0;
+ ports[1] = cp[0] ? parse_tcp_port(cp) : 0xFFFF;
+ }
+ free(buffer);
+}
+
+struct tcp_flag_names {
+ const char *name;
+ unsigned int flag;
+};
+
+static struct tcp_flag_names tcp_flag_names[]
+= { { "FIN", 0x01 },
+ { "SYN", 0x02 },
+ { "RST", 0x04 },
+ { "PSH", 0x08 },
+ { "ACK", 0x10 },
+ { "URG", 0x20 },
+ { "ALL", 0x3F },
+ { "NONE", 0 },
+};
+
+static unsigned int
+parse_tcp_flag(const char *flags)
+{
+ unsigned int ret = 0;
+ char *ptr;
+ char *buffer;
+
+ buffer = strdup(flags);
+
+ for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
+ unsigned int i;
+ for (i = 0;
+ i < sizeof(tcp_flag_names)/sizeof(struct tcp_flag_names);
+ i++) {
+ if (strcasecmp(tcp_flag_names[i].name, ptr) == 0) {
+ ret |= tcp_flag_names[i].flag;
+ break;
+ }
+ }
+ if (i == sizeof(tcp_flag_names)/sizeof(struct tcp_flag_names))
+ exit_error(PARAMETER_PROBLEM,
+ "Unknown TCP flag `%s'", buffer);
+ }
+
+ free(buffer);
+ return ret;
+}
+
+static void
+parse_tcp_flags(struct ipt_tcp *tcpinfo,
+ const char *mask,
+ const char *cmp,
+ int invert)
+{
+ tcpinfo->flg_mask = parse_tcp_flag(mask);
+ tcpinfo->flg_cmp = parse_tcp_flag(cmp);
+
+ if (invert)
+ tcpinfo->invflags |= IPT_TCP_INV_FLAGS;
+}
+
+static void
+parse_tcp_option(const char *option, u_int8_t *result)
+{
+ int ret;
+
+ ret = string_to_number(option, 1, 255);
+ if (ret == -1)
+ exit_error(PARAMETER_PROBLEM, "Bad TCP option `%s'", option);
+
+ *result = (u_int8_t)ret;
+}
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ struct ipt_tcp *tcpinfo = (struct ipt_tcp *)m->data;
+
+ tcpinfo->spts[1] = tcpinfo->dpts[1] = 0xFFFF;
+}
+
+#define TCP_SRC_PORTS 0x01
+#define TCP_DST_PORTS 0x02
+#define TCP_FLAGS 0x04
+#define TCP_OPTION 0x08
+
+/* Function which parses command options; returns true if it
+ ate an option. */
+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_tcp *tcpinfo = (struct ipt_tcp *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ if (*flags & TCP_SRC_PORTS)
+ exit_error(PARAMETER_PROBLEM,
+ "Only one `--source-port' allowed");
+ if (check_inverse(optarg, &invert))
+ optind++;
+ parse_tcp_ports(argv[optind-1], tcpinfo->spts);
+ if (invert)
+ tcpinfo->invflags |= IPT_TCP_INV_SRCPT;
+ *flags |= TCP_SRC_PORTS;
+ *nfcache |= NFC_IP_SRC_PT;
+ break;
+
+ case '2':
+ if (*flags & TCP_DST_PORTS)
+ exit_error(PARAMETER_PROBLEM,
+ "Only one `--destination-port' allowed");
+ if (check_inverse(optarg, &invert))
+ optind++;
+ parse_tcp_ports(argv[optind-1], tcpinfo->dpts);
+ if (invert)
+ tcpinfo->invflags |= IPT_TCP_INV_DSTPT;
+ *flags |= TCP_DST_PORTS;
+ *nfcache |= NFC_IP_DST_PT;
+ break;
+
+ case '3':
+ if (*flags & TCP_FLAGS)
+ exit_error(PARAMETER_PROBLEM,
+ "Only one of `--syn' or `--tcp-flags' "
+ " allowed");
+ parse_tcp_flags(tcpinfo, "SYN,RST,ACK", "SYN", invert);
+ *flags |= TCP_FLAGS;
+ *nfcache |= NFC_IP_TCPFLAGS;
+ break;
+
+ case '4':
+ if (*flags & TCP_FLAGS)
+ exit_error(PARAMETER_PROBLEM,
+ "Only one of `--syn' or `--tcp-flags' "
+ " allowed");
+ if (check_inverse(optarg, &invert))
+ optind++;
+
+ if (!argv[optind]
+ || argv[optind][0] == '-' || argv[optind][0] == '!')
+ exit_error(PARAMETER_PROBLEM,
+ "--tcp-flags requires two args.");
+
+ parse_tcp_flags(tcpinfo, optarg, argv[optind++], invert);
+ *flags |= TCP_FLAGS;
+ *nfcache |= NFC_IP_TCPFLAGS;
+ break;
+
+ case '5':
+ if (*flags & TCP_OPTION)
+ exit_error(PARAMETER_PROBLEM,
+ "Only one `--tcp-option' allowed");
+ if (check_inverse(optarg, &invert))
+ optind++;
+ parse_tcp_option(argv[optind-1], &tcpinfo->option);
+ if (invert)
+ tcpinfo->invflags |= IPT_TCP_INV_OPTION;
+ *flags |= TCP_OPTION;
+ *nfcache |= NFC_IP_PROTO_UNKNOWN;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Final check; we don't care. */
+static void
+final_check(unsigned int flags)
+{
+}
+
+static char *
+port_to_service(int port)
+{
+ struct servent *service;
+
+ if ((service = getservbyport(htons(port), "tcp")))
+ return service->s_name;
+
+ return NULL;
+}
+
+static void
+print_port(u_int16_t port, int numeric)
+{
+ char *service;
+
+ if (numeric || (service = port_to_service(port)) == NULL)
+ printf("%u", port);
+ else
+ printf("%s", service);
+}
+
+static void
+print_ports(const char *name, u_int16_t min, u_int16_t max,
+ int invert, int numeric)
+{
+ const char *inv = invert ? "!" : "";
+
+ if (min != 0 || max != 0xFFFF || invert) {
+ printf("%s", name);
+ if (min == max) {
+ printf(":%s", inv);
+ print_port(min, numeric);
+ } else {
+ printf("s:%s", inv);
+ print_port(min, numeric);
+ printf(":");
+ print_port(max, numeric);
+ }
+ printf(" ");
+ }
+}
+
+static void
+print_option(u_int8_t option, int invert, int numeric)
+{
+ if (option || invert)
+ printf("option=%s%u ", invert ? "!" : "", option);
+}
+
+static void
+print_tcpf(u_int8_t flags)
+{
+ int sole_flag = 1;
+
+ do {
+ unsigned int i;
+
+ /* Terminates because last flag is 0 */
+ for (i = 0; !(flags & tcp_flag_names[i].flag); i++);
+
+ if (!sole_flag)
+ printf(",");
+ printf("%s", tcp_flag_names[i].name);
+ sole_flag = 0;
+
+ flags &= ~tcp_flag_names[i].flag;
+ } while (flags);
+}
+
+static void
+print_flags(u_int8_t mask, u_int8_t cmp, int invert, int numeric)
+{
+ if (mask || invert) {
+ printf("flags:%s", invert ? "!" : "");
+ if (numeric)
+ printf("0x02%X/0x02%X ", mask, cmp);
+ else {
+ print_tcpf(cmp);
+ printf("/");
+ print_tcpf(mask);
+ printf(" ");
+ }
+ }
+}
+
+/* Prints out the union ipt_matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match, int numeric)
+{
+ const struct ipt_tcp *tcp = (struct ipt_tcp *)match->data;
+
+ printf("tcp ");
+ print_ports("spt", tcp->spts[0], tcp->spts[1],
+ tcp->invflags & IPT_TCP_INV_SRCPT,
+ numeric);
+ print_ports("dpt", tcp->dpts[0], tcp->dpts[1],
+ tcp->invflags & IPT_TCP_INV_DSTPT,
+ numeric);
+ print_option(tcp->option,
+ tcp->invflags & IPT_TCP_INV_OPTION,
+ numeric);
+ print_flags(tcp->flg_mask, tcp->flg_cmp,
+ tcp->invflags & IPT_TCP_INV_FLAGS,
+ numeric);
+ if (tcp->invflags & ~IPT_TCP_INV_MASK)
+ printf("Unknown invflags: 0x%X ",
+ tcp->invflags & ~IPT_TCP_INV_MASK);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ const struct ipt_tcp *tcpinfo = (struct ipt_tcp *)match->data;
+
+ if (tcpinfo->spts[0] != 0
+ && tcpinfo->spts[1] != 0xFFFF) {
+ if (tcpinfo->invflags & IPT_TCP_INV_SRCPT)
+ printf("! ");
+ if (tcpinfo->spts[0]
+ != tcpinfo->spts[1])
+ printf("--sport %u-%u ",
+ ntohs(tcpinfo->spts[0]),
+ ntohs(tcpinfo->spts[1]));
+ else
+ printf("--sport %u ",
+ ntohs(tcpinfo->spts[0]));
+ }
+
+ if (tcpinfo->dpts[0] != 0
+ && tcpinfo->dpts[1] != 0xFFFF) {
+ if (tcpinfo->invflags & IPT_TCP_INV_DSTPT)
+ printf("! ");
+ if (tcpinfo->dpts[0]
+ != tcpinfo->dpts[1])
+ printf("--dport %u-%u ",
+ ntohs(tcpinfo->dpts[0]),
+ ntohs(tcpinfo->dpts[1]));
+ else
+ printf("--dport %u ",
+ ntohs(tcpinfo->dpts[0]));
+ }
+
+ if (tcpinfo->option
+ || (tcpinfo->invflags & IPT_TCP_INV_OPTION)) {
+ if (tcpinfo->invflags & IPT_TCP_INV_OPTION)
+ printf("! ");
+ printf("--tcp-option %u ", tcpinfo->option);
+ }
+
+ if (tcpinfo->flg_mask
+ || (tcpinfo->invflags & IPT_TCP_INV_FLAGS)) {
+ if (tcpinfo->invflags & IPT_TCP_INV_FLAGS)
+ printf("! ");
+
+ print_tcpf(tcpinfo->flg_cmp);
+ if (tcpinfo->flg_mask != 0xFF) {
+ printf("/");
+ print_tcpf(tcpinfo->flg_mask);
+ }
+ }
+}
+
+struct iptables_match tcp
+= { NULL,
+ "tcp",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_tcp),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts };
+
+void
+_init(void)
+{
+ register_match(&tcp);
+}
diff --git a/extensions/libipt_tos.c b/extensions/libipt_tos.c
new file mode 100644
index 00000000..eb62081e
--- /dev/null
+++ b/extensions/libipt_tos.c
@@ -0,0 +1,171 @@
+/* Shared library add-on to iptables to add TOS matching support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ipt_tos.h>
+
+/* TOS names and values. */
+struct TOS_value
+{
+ unsigned char TOS;
+ const char *name;
+} TOS_values[] = {
+ { IPTOS_LOWDELAY, "Minimize-Delay" },
+ { IPTOS_THROUGHPUT, "Maximize-Throughput" },
+ { IPTOS_RELIABILITY, "Maximize-Reliability" },
+ { IPTOS_MINCOST, "Minimize-Cost" },
+ { IPTOS_NORMALSVC, "Normal-Service" },
+};
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ unsigned int i;
+
+ printf(
+"TOS match v%s options:\n"
+"[!] --tos value Match Type of Service field from one of the\n"
+" following numeric or descriptive values:\n",
+NETFILTER_VERSION);
+
+ for (i = 0; i < sizeof(TOS_values)/sizeof(struct TOS_value);i++)
+ printf(" %s %u (0x%02x)\n",
+ TOS_values[i].name,
+ TOS_values[i].TOS,
+ TOS_values[i].TOS);
+ fputc('\n', stdout);
+}
+
+static struct option opts[] = {
+ { "tos", 1, 0, '1' },
+ {0}
+};
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ *nfcache |= NFC_IP_TOS;
+}
+
+static void
+parse_tos(const unsigned char *s, struct ipt_tos_info *info)
+{
+ unsigned int i;
+ int tos = string_to_number(s, 0, 255);
+
+ if (tos != -1) {
+ if (tos == IPTOS_LOWDELAY
+ || tos == IPTOS_THROUGHPUT
+ || tos == IPTOS_RELIABILITY
+ || tos == IPTOS_MINCOST
+ || tos == IPTOS_NORMALSVC) {
+ info->tos = (u_int8_t )tos;
+ return;
+ }
+ } else {
+ for (i = 0; i<sizeof(TOS_values)/sizeof(struct TOS_value); i++)
+ if (strcasecmp(s,TOS_values[i].name) == 0) {
+ info->tos = TOS_values[i].TOS;
+ return;
+ }
+ }
+ exit_error(PARAMETER_PROBLEM, "Bad TOS value `%s'", s);
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+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_tos_info *tosinfo = (struct ipt_tos_info *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ if (check_inverse(optarg, &invert))
+ optind++;
+ parse_tos(argv[optind-1], tosinfo);
+ if (invert)
+ tosinfo->invert = 1;
+ *flags = 1;
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void
+print_tos(u_int8_t tos, int invert, int numeric)
+{
+ unsigned int i;
+
+ if (invert)
+ fputc('!', stdout);
+
+ if (!numeric) {
+ for (i = 0; i<sizeof(TOS_values)/sizeof(struct TOS_value); i++)
+ if (TOS_values[i].TOS == tos) {
+ printf("%s ", TOS_values[i].name);
+ return;
+ }
+ }
+ printf("0x%02x ", tos);
+}
+
+/* Final check; must have specified --tos. */
+static void
+final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM,
+ "TOS match: You must specify `--tos'");
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match,
+ int numeric)
+{
+ printf("TOS match ");
+ print_tos(((struct ipt_tos_info *)match->data)->tos,
+ ((struct ipt_tos_info *)match->data)->invert, numeric);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ printf("--tos ");
+ print_tos(((struct ipt_tos_info *)match->data)->tos,
+ ((struct ipt_tos_info *)match->data)->invert, 0);
+}
+
+struct iptables_match tos
+= { NULL,
+ "tos",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_tos_info),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_match(&tos);
+}
diff --git a/extensions/libipt_udp.c b/extensions/libipt_udp.c
new file mode 100644
index 00000000..e3593579
--- /dev/null
+++ b/extensions/libipt_udp.c
@@ -0,0 +1,252 @@
+/* Shared library add-on to iptables to add UDP support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"UDP v%s options:\n"
+" --source-port [!] port[:port]\n"
+" --sport ...\n"
+" match source port(s)\n"
+" --destination-port [!] port[:port]\n"
+" --dport ...\n"
+" match destination port(s)\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "source-port", 1, 0, '1' },
+ { "sport", 1, 0, '1' }, /* synonym */
+ { "destination-port", 1, 0, '2' },
+ { "dport", 1, 0, '2' }, /* synonym */
+ {0}
+};
+
+static int
+service_to_port(const char *name)
+{
+ struct servent *service;
+
+ if ((service = getservbyname(name, "udp")) != NULL)
+ return ntohs((unsigned short) service->s_port);
+
+ return -1;
+}
+
+static u_int16_t
+parse_udp_port(const char *port)
+{
+ int portnum;
+
+ if ((portnum = string_to_number(port, 0, 65535)) != -1 ||
+ (portnum = service_to_port(port)) != -1)
+ return (u_int16_t)portnum;
+
+ exit_error(PARAMETER_PROBLEM,
+ "invalid UDP port/service `%s' specified", port);
+ }
+
+static void
+parse_udp_ports(const char *portstring, u_int16_t *ports)
+{
+ char *buffer;
+ char *cp;
+
+ buffer = strdup(portstring);
+ if ((cp = strchr(buffer, ':')) == NULL)
+ ports[0] = ports[1] = parse_udp_port(buffer);
+ else {
+ *cp = '\0';
+ cp++;
+
+ ports[0] = buffer[0] ? parse_udp_port(buffer) : 0;
+ ports[1] = cp[0] ? parse_udp_port(cp) : 0xFFFF;
+ }
+ free(buffer);
+}
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ struct ipt_udp *udpinfo = (struct ipt_udp *)m->data;
+
+ udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF;
+}
+
+#define UDP_SRC_PORTS 0x01
+#define UDP_DST_PORTS 0x02
+
+/* Function which parses command options; returns true if it
+ ate an option */
+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_udp *udpinfo = (struct ipt_udp *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ if (*flags & UDP_SRC_PORTS)
+ exit_error(PARAMETER_PROBLEM,
+ "Only one `--source-port' allowed");
+ if (check_inverse(optarg, &invert))
+ optind++;
+ parse_udp_ports(argv[optind-1], udpinfo->spts);
+ if (invert)
+ udpinfo->invflags |= IPT_UDP_INV_SRCPT;
+ *flags |= UDP_SRC_PORTS;
+ *nfcache |= NFC_IP_SRC_PT;
+ break;
+
+ case '2':
+ if (*flags & UDP_DST_PORTS)
+ exit_error(PARAMETER_PROBLEM,
+ "Only one `--destination-port' allowed");
+ if (check_inverse(optarg, &invert))
+ optind++;
+ parse_udp_ports(argv[optind-1], udpinfo->dpts);
+ if (invert)
+ udpinfo->invflags |= IPT_UDP_INV_DSTPT;
+ *flags |= UDP_DST_PORTS;
+ *nfcache |= NFC_IP_DST_PT;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Final check; we don't care. */
+static void
+final_check(unsigned int flags)
+{
+}
+
+static char *
+port_to_service(int port)
+{
+ struct servent *service;
+
+ if ((service = getservbyport(htons(port), "udp")))
+ return service->s_name;
+
+ return NULL;
+}
+
+static void
+print_port(u_int16_t port, int numeric)
+{
+ char *service;
+
+ if (numeric || (service = port_to_service(port)) == NULL)
+ printf("%u", port);
+ else
+ printf("%s", service);
+}
+
+static void
+print_ports(const char *name, u_int16_t min, u_int16_t max,
+ int invert, int numeric)
+{
+ const char *inv = invert ? "!" : "";
+
+ if (min != 0 || max != 0xFFFF || invert) {
+ printf("%s", name);
+ if (min == max) {
+ printf(":%s", inv);
+ print_port(min, numeric);
+ } else {
+ printf("s:%s", inv);
+ print_port(min, numeric);
+ printf(":");
+ print_port(max, numeric);
+ }
+ printf(" ");
+ }
+}
+
+/* Prints out the union ipt_matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match, int numeric)
+{
+ const struct ipt_udp *udp = (struct ipt_udp *)match->data;
+
+ printf("udp ");
+ print_ports("spt", udp->spts[0], udp->spts[1],
+ udp->invflags & IPT_UDP_INV_SRCPT,
+ numeric);
+ print_ports("dpt", udp->dpts[0], udp->dpts[1],
+ udp->invflags & IPT_UDP_INV_DSTPT,
+ numeric);
+ if (udp->invflags & ~IPT_UDP_INV_MASK)
+ printf("Unknown invflags: 0x%X ",
+ udp->invflags & ~IPT_UDP_INV_MASK);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ const struct ipt_udp *udpinfo = (struct ipt_udp *)match->data;
+
+ if (udpinfo->spts[0] != 0
+ && udpinfo->spts[1] != 0xFFFF) {
+ if (udpinfo->invflags & IPT_UDP_INV_SRCPT)
+ printf("! ");
+ if (udpinfo->spts[0]
+ != udpinfo->spts[1])
+ printf("--sport %u-%u ",
+ ntohs(udpinfo->spts[0]),
+ ntohs(udpinfo->spts[1]));
+ else
+ printf("--sport %u ",
+ ntohs(udpinfo->spts[0]));
+ }
+
+ if (udpinfo->dpts[0] != 0
+ && udpinfo->dpts[1] != 0xFFFF) {
+ if (udpinfo->invflags & IPT_UDP_INV_DSTPT)
+ printf("! ");
+ if (udpinfo->dpts[0]
+ != udpinfo->dpts[1])
+ printf("--dport %u-%u ",
+ ntohs(udpinfo->dpts[0]),
+ ntohs(udpinfo->dpts[1]));
+ else
+ printf("--dport %u ",
+ ntohs(udpinfo->dpts[0]));
+ }
+}
+
+struct iptables_match udp
+= { NULL,
+ "udp",
+ NETFILTER_VERSION,
+ sizeof(struct ipt_udp),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void
+_init(void)
+{
+ register_match(&udp);
+}
diff --git a/extensions/libipt_unclean.c b/extensions/libipt_unclean.c
new file mode 100644
index 00000000..50f62bdc
--- /dev/null
+++ b/extensions/libipt_unclean.c
@@ -0,0 +1,66 @@
+/* Shared library add-on to iptables for unclean. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"unclean v%s takes no options\n"
+"\n", NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ {0}
+};
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ /* Can't cache this. */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+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)
+{
+ return 0;
+}
+
+/* Final check; must have specified --mac. */
+static void final_check(unsigned int flags)
+{
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+}
+
+struct iptables_match unclean
+= { NULL,
+ "unclean",
+ NETFILTER_VERSION,
+ 0,
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ NULL, /* print */
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_match(&unclean);
+}