]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
Andreas Ferber's mulitport with ranges patch.
authorAndreas Ferber <af@devcon.net>
Tue, 5 Jun 2001 11:56:38 +0000 (11:56 +0000)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 5 Jun 2001 11:56:38 +0000 (11:56 +0000)
extensions/.mport-test [new file with mode: 0755]
extensions/libipt_mport.c [new file with mode: 0644]

diff --git a/extensions/.mport-test b/extensions/.mport-test
new file mode 100755 (executable)
index 0000000..411a083
--- /dev/null
@@ -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 (file)
index 0000000..38474cd
--- /dev/null
@@ -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);
+}