summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xextensions/.mport-test2
-rw-r--r--extensions/libipt_mport.c306
2 files changed, 308 insertions, 0 deletions
diff --git a/extensions/.mport-test b/extensions/.mport-test
new file mode 100755
index 00000000..411a0839
--- /dev/null
+++ b/extensions/.mport-test
@@ -0,0 +1,2 @@
+#! /bin/sh
+[ -f $KERNEL_DIR/net/ipv4/netfilter/ipt_mport.c ] && echo mport
diff --git a/extensions/libipt_mport.c b/extensions/libipt_mport.c
new file mode 100644
index 00000000..38474cde
--- /dev/null
+++ b/extensions/libipt_mport.c
@@ -0,0 +1,306 @@
+/* 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_mport.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"mport v%s options:\n"
+" --source-ports port[,port:port,port...]\n"
+" --sports ...\n"
+" match source port(s)\n"
+" --destination-ports port[,port:port,port...]\n"
+" --dports ...\n"
+" match destination port(s)\n"
+" --ports port[,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 void
+parse_multi_ports(const char *portstring, struct ipt_mport *minfo,
+ const char *proto)
+{
+ char *buffer, *cp, *next, *range;
+ unsigned int i;
+ u_int16_t m;
+
+ buffer = strdup(portstring);
+ if (!buffer) exit_error(OTHER_PROBLEM, "strdup failed");
+
+ minfo->pflags = 0;
+
+ for (cp=buffer, i=0, m=1; cp && i<IPT_MULTI_PORTS; cp=next,i++,m<<=1)
+ {
+ next=strchr(cp, ',');
+ if (next) *next++='\0';
+ range = strchr(cp, ':');
+ if (range) {
+ if (i == IPT_MULTI_PORTS-1)
+ exit_error(PARAMETER_PROBLEM,
+ "too many ports specified");
+ *range++ = '\0';
+ }
+ minfo->ports[i] = parse_port(cp, proto);
+ if (range) {
+ minfo->pflags |= m;
+ minfo->ports[++i] = parse_port(range, proto);
+ if (minfo->ports[i-1] >= minfo->ports[i])
+ exit_error(PARAMETER_PROBLEM,
+ "invalid portrange specified");
+ m <<= 1;
+ }
+ }
+ if (cp) exit_error(PARAMETER_PROBLEM, "too many ports specified");
+ if (i == IPT_MULTI_PORTS-1)
+ minfo->ports[i] = minfo->ports[i-1];
+ else if (i < IPT_MULTI_PORTS-1) {
+ minfo->ports[i] = ~0;
+ minfo->pflags |= 1<<i;
+ }
+ free(buffer);
+}
+
+/* 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_mport *minfo
+ = (struct ipt_mport *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ proto = check_proto(entry);
+ parse_multi_ports(argv[optind-1], minfo, proto);
+ minfo->flags = IPT_MPORT_SOURCE;
+ *nfcache |= NFC_IP_SRC_PT;
+ break;
+
+ case '2':
+ proto = check_proto(entry);
+ parse_multi_ports(argv[optind-1], minfo, proto);
+ minfo->flags = IPT_MPORT_DESTINATION;
+ *nfcache |= NFC_IP_DST_PT;
+ break;
+
+ case '3':
+ proto = check_proto(entry);
+ parse_multi_ports(argv[optind-1], minfo, proto);
+ minfo->flags = IPT_MPORT_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, "mport expects 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_mport *minfo
+ = (const struct ipt_mport *)match->data;
+ unsigned int i;
+ u_int16_t pflags = minfo->pflags;
+
+ printf("mport ");
+
+ switch (minfo->flags) {
+ case IPT_MPORT_SOURCE:
+ printf("sports ");
+ break;
+
+ case IPT_MPORT_DESTINATION:
+ printf("dports ");
+ break;
+
+ case IPT_MPORT_EITHER:
+ printf("ports ");
+ break;
+
+ default:
+ printf("ERROR ");
+ break;
+ }
+
+ for (i=0; i < IPT_MULTI_PORTS; i++) {
+ if (pflags & (1<<i)
+ && minfo->ports[i] == 65535)
+ break;
+ if (i == IPT_MULTI_PORTS-1
+ && minfo->ports[i-1] == minfo->ports[i])
+ break;
+ printf("%s", i ? "," : "");
+ print_port(minfo->ports[i], ip->proto, numeric);
+ if (pflags & (1<<i)) {
+ printf(":");
+ print_port(minfo->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_mport *minfo
+ = (const struct ipt_mport *)match->data;
+ unsigned int i;
+ u_int16_t pflags = minfo->pflags;
+
+ switch (minfo->flags) {
+ case IPT_MPORT_SOURCE:
+ printf("--sports ");
+ break;
+
+ case IPT_MPORT_DESTINATION:
+ printf("--dports ");
+ break;
+
+ case IPT_MPORT_EITHER:
+ printf("--ports ");
+ break;
+ }
+
+ for (i=0; i < IPT_MULTI_PORTS; i++) {
+ if (pflags & (1<<i)
+ && !(~minfo->ports[i]))
+ break;
+ if (i == IPT_MULTI_PORTS-1
+ && minfo->ports[i-1] == minfo->ports[i])
+ break;
+ printf("%s", i ? "," : "");
+ print_port(minfo->ports[i], ip->proto, 0);
+ if (pflags & (1<<i)) {
+ printf(":");
+ print_port(minfo->ports[i++], ip->proto, 0);
+ }
+ }
+ printf(" ");
+}
+
+struct iptables_match mport
+= { NULL,
+ "mport",
+ NETFILTER_VERSION,
+ IPT_ALIGN(sizeof(struct ipt_mport)),
+ IPT_ALIGN(sizeof(struct ipt_mport)),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void
+_init(void)
+{
+ register_match(&mport);
+}