]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
ip6tables fixes by Fabrice Maurie
authorFabrice MARIE <fabrice_marie_sec@yahoo.com>
Sat, 5 May 2001 21:37:47 +0000 (21:37 +0000)
committerHarald Welte <laforge@gnumonks.org>
Sat, 5 May 2001 21:37:47 +0000 (21:37 +0000)
include/ip6tables.h
ip6tables-standalone.c
ip6tables.c

index 8e20ade7121e572993274300395d99ee513bdcc4..baa3677e32dca3ee82a256fe2ea4bc2bc0db6f71 100644 (file)
@@ -50,6 +50,7 @@ struct ip6tables_match
        unsigned int option_offset;
        struct ip6t_entry_match *m;
        unsigned int mflags;
+       unsigned int used;
 };
 
 struct ip6tables_target
@@ -96,6 +97,7 @@ struct ip6tables_target
        unsigned int option_offset;
        struct ip6t_entry_target *t;
        unsigned int tflags;
+       unsigned int used;
 };
 
 /* Your shared library should call one of these. */
@@ -114,8 +116,8 @@ enum ip6t_tryload {
        LOAD_MUST_SUCCEED
 };
 
-extern struct ip6tables_target *find_target6(const char *name, enum ip6t_tryload);
-extern struct ip6tables_match *find_match6(const char *name, enum ip6t_tryload);
+extern struct ip6tables_target *find_target(const char *name, enum ip6t_tryload);
+extern struct ip6tables_match *find_match(const char *name, enum ip6t_tryload);
 
 extern int for_each_chain(int (*fn)(const ip6t_chainlabel, int, ip6tc_handle_t *), int verbose, int builtinstoo, ip6tc_handle_t *handle);
 extern int flush_entries(const ip6t_chainlabel chain, int verbose, ip6tc_handle_t *handle);
index f6b362c2aab71f1f79d24adf8335cce03a2f9d7d..1120590f1d85229450e39ce06dbd8f2a5d9355d7 100644 (file)
@@ -34,7 +34,7 @@ main(int argc, char *argv[])
 {
        int ret;
        char *table = "filter";
-       ip6tc_handle_t handle;
+       ip6tc_handle_t handle = NULL;
 
        program_name = "ip6tables";
        program_version = NETFILTER_VERSION;
index a32d418cf2fc2437c6273d40a65186891f75fd2a..ad2fc80c8c3c57d7e9d0b86fc9cff2bede7c8218 100644 (file)
 #include <limits.h>
 #include <ip6tables.h>
 #include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
 
 #ifndef TRUE
 #define TRUE 1
 #define IP6T_LIB_DIR "/usr/local/lib/iptables"
 #endif
 
+#ifndef PROC_SYS_MODPROBE
+#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
+#endif
+
 #define FMT_NUMERIC    0x0001
 #define FMT_NOCOUNTS   0x0002
 #define FMT_KILOMEGAGIGA 0x0004
@@ -124,6 +133,14 @@ static struct option original_opts[] = {
        { 0 }
 };
 
+#ifndef __OPTIMIZE__
+struct ip6t_entry_target *
+ip6t_get_target(struct ipt_entry *e)
+{
+               return (void *)e + e->target_offset;
+}
+#endif
+
 static struct option *opts = original_opts;
 static unsigned int global_option_offset = 0;
 
@@ -186,6 +203,17 @@ struct pprot {
        u_int8_t num;
 };
 
+/* Primitive headers... */
+/* defined in netinet/in.h */
+#if 0
+#ifndef IPPROTO_ESP
+#define IPPROTO_ESP 50
+#endif
+#ifndef IPPROTO_AH
+#define IPPROTO_AH 51
+#endif
+#endif
+
 static const struct pprot chain_protos[] = {
        { "tcp", IPPROTO_TCP },
        { "udp", IPPROTO_UDP },
@@ -406,7 +434,7 @@ fw_calloc(size_t count, size_t size)
        void *p;
 
        if ((p = calloc(count, size)) == NULL) {
-               perror("iptables: calloc failed");
+               perror("ip6tables: calloc failed");
                exit(1);
        }
        return p;
@@ -418,7 +446,7 @@ fw_malloc(size_t size)
        void *p;
 
        if ((p = malloc(size)) == NULL) {
-               perror("iptables: malloc failed");
+               perror("ip6tables: malloc failed");
                exit(1);
        }
        return p;
@@ -427,14 +455,15 @@ fw_malloc(size_t size)
 static struct in6_addr *
 host_to_addr(const char *name, unsigned int *naddr)
 {
+#if 0
+       /* TODO: getipnodebyname() missing */
        struct hostent *host;
        struct in6_addr *addr;
        unsigned int i;
 
        *naddr = 0;
-       if ((host = gethostbyname2(name, AF_INET6)) != NULL) {
-               if (host->h_addrtype != AF_INET6 ||
-                   host->h_length != sizeof(struct in6_addr))
+       if ((host = getipnodebyname(name, AF_INET6, 0, NULL)) != NULL) {
+               if (host->h_length != sizeof(struct in6_addr))
                        return (struct in6_addr *) NULL;
 
                while (host->h_addr_list[*naddr] != (char *) NULL)
@@ -443,8 +472,10 @@ host_to_addr(const char *name, unsigned int *naddr)
                for (i = 0; i < *naddr; i++)
                        in6addrcpy(&(addr[i]),
                                  (struct in6_addr *) host->h_addr_list[i]);
+               freehostent(host);
                return addr;
        }
+#endif
 
        return (struct in6_addr *) NULL;
 }
@@ -452,12 +483,15 @@ host_to_addr(const char *name, unsigned int *naddr)
 static char *
 addr_to_host(const struct in6_addr *addr)
 {
+#if 0
+       /* TODO: getipnodebyaddr missing */
        struct hostent *host;
 
-       /* TODO: gets errno 96 (EPFNOSUPPORT) on Debian/Sid. Got only AF_INET! */
-       if ((host = gethostbyaddr((char *) addr,
-                                 sizeof(struct in_addr), AF_INET6)) != NULL)
+       if ((host = getipnodebyaddr((char *) addr,
+                                 sizeof(struct in6_addr), AF_INET6, NULL)) != NULL)
                return (char *) host->h_name;
+       /*TODO: freehostent()*/
+#endif
 
        return (char *) NULL;
 }
@@ -633,6 +667,10 @@ find_match(const char *name, enum ip6t_tryload tryload)
                                   "Couldn't load match `%s'\n", name);
        }
 
+        if (ptr)
+                ptr->used = 1;
+
+
        return ptr;
 }
 
@@ -820,9 +858,13 @@ find_target(const char *name, enum ip6t_tryload tryload)
                                           name);
                } else if (tryload == LOAD_MUST_SUCCEED)
                        exit_error(PARAMETER_PROBLEM,
-                                  "Couldn't load target `%s'\n", name);
+                                  "Couldn't load target `%s'%s\n", 
+                                  name, dlerror());
        }
 
+        if (ptr)
+                ptr->used = 1;
+
        return ptr;
 }
 
@@ -865,13 +907,19 @@ register_match6(struct ip6tables_match *me)
                exit(1);
        }
 
+        if (me->size != IP6T_ALIGN(me->size)) {
+                fprintf(stderr, "%s: match `%s' has invalid size %u.\n",
+                        program_name, me->name, me->size);
+                exit(1);
+        }
+
        /* Prepend to list. */
        me->next = ip6tables_matches;
        ip6tables_matches = me;
        me->m = NULL;
        me->mflags = 0;
 
-       opts = merge_options(opts, me->extra_opts, &me->option_offset);
+       /* opts = merge_options(opts, me->extra_opts, &me->option_offset);*/
 }
 
 void
@@ -889,13 +937,40 @@ register_target6(struct ip6tables_target *me)
                exit(1);
        }
 
+        if (me->size != IP6T_ALIGN(me->size)) {
+                fprintf(stderr, "%s: target `%s' has invalid size %u.\n",
+                        program_name, me->name, me->size);
+                exit(1);
+        }
+
        /* Prepend to list. */
        me->next = ip6tables_targets;
        ip6tables_targets = me;
        me->t = NULL;
        me->tflags = 0;
 
-       opts = merge_options(opts, me->extra_opts, &me->option_offset);
+       /*opts = merge_options(opts, me->extra_opts, &me->option_offset);*/
+}
+
+static void
+print_num(u_int64_t number, unsigned int format)
+{
+        if (format & FMT_KILOMEGAGIGA) {
+                if (number > 99999) {
+                        number = (number + 500) / 1000;
+                        if (number > 9999) {
+                                number = (number + 500) / 1000;
+                                if (number > 9999) {
+                                        number = (number + 500) / 1000;
+                                        printf(FMT("%4lluG ","%lluG "),number);
+                                }
+                                else printf(FMT("%4lluM ","%lluM "), number);
+                        } else
+                                printf(FMT("%4lluK ","%lluK "), number);
+                } else
+                        printf(FMT("%5llu ","%llu "), number);
+        } else
+                printf(FMT("%8llu ","%llu "), number);
 }
 
 static void
@@ -906,9 +981,15 @@ print_header(unsigned int format, const char *chain, ip6tc_handle_t *handle)
        printf("Chain %s", chain);
        if (pol) {
                printf(" (policy %s", pol);
-               if (!(format & FMT_NOCOUNTS))
-                       printf(" %llu packets, %llu bytes",
-                              counters.pcnt, counters.bcnt);
+               if (!(format & FMT_NOCOUNTS)) {
+                       /*printf(" %llu packets, %llu bytes",
+                              counters.pcnt, counters.bcnt);*/
+                        fputc(' ', stdout);
+                        print_num(counters.pcnt, (format|FMT_NOTABLE));
+                        fputs("packets, ", stdout);
+                        print_num(counters.bcnt, (format|FMT_NOTABLE));
+                        fputs("bytes", stdout);
+               }
                printf(")\n");
        } else {
                unsigned int refs;
@@ -943,27 +1024,6 @@ print_header(unsigned int format, const char *chain, ip6tc_handle_t *handle)
        printf("\n");
 }
 
-static void
-print_num(u_int64_t number, unsigned int format)
-{
-       if (format & FMT_KILOMEGAGIGA) {
-               if (number > 99999) {
-                       number = (number + 500) / 1000;
-                       if (number > 9999) {
-                               number = (number + 500) / 1000;
-                               if (number > 9999) {
-                                       number = (number + 500) / 1000;
-                                       printf(FMT("%4lluG ","%lluG "),number);
-                               }
-                               else printf(FMT("%4lluM ","%lluM "), number);
-                       } else
-                               printf(FMT("%4lluK ","%lluK "), number);
-               } else
-                       printf(FMT("%5llu ","%llu "), number);
-       } else
-               printf(FMT("%8llu ","%llu "), number);
-}
-
 static int
 print_match(const struct ip6t_entry_match *m,
            const struct ip6t_ip6 *ip,
@@ -974,6 +1034,8 @@ print_match(const struct ip6t_entry_match *m,
        if (match) {
                if (match->print)
                        match->print(ip, m, numeric);
+                else
+                        printf("%s ", match->name);
        } else {
                if (m->u.user.name[0])
                        printf("UNKNOWN match `%s' ", m->u.user.name);
@@ -1205,8 +1267,12 @@ make_delete_mask(struct ip6t_entry *fw)
        unsigned char *mask, *mptr;
 
        size = sizeof(struct ip6t_entry);
-       for (m = ip6tables_matches; m; m = m->next)
-               size += sizeof(struct ip6t_entry_match) + m->size;
+       for (m = ip6tables_matches; m; m = m->next) {
+                if (!m->used)
+                        continue;
+
+               size += IP6T_ALIGN(sizeof(struct ip6t_entry_match)) + m->size;
+       }
 
        mask = fw_calloc(1, size
                         + sizeof(struct ip6t_entry_target)
@@ -1216,14 +1282,20 @@ make_delete_mask(struct ip6t_entry *fw)
        mptr = mask + sizeof(struct ip6t_entry);
 
        for (m = ip6tables_matches; m; m = m->next) {
+                if (!m->used)
+                        continue;
+
                memset(mptr, 0xFF,
-                      sizeof(struct ip6t_entry_match) + m->userspacesize);
-               mptr += sizeof(struct ip6t_entry_match) + m->size;
+                      IP6T_ALIGN(sizeof(struct ip6t_entry_match)) + 
+                      m->userspacesize);
+               mptr += IP6T_ALIGN(sizeof(struct ip6t_entry_match)) + m->size;
        }
 
-       memset(mptr, 0xFF, sizeof(struct ip6t_entry_target));
-       mptr += sizeof(struct ip6t_entry_target);
-       memset(mptr, 0xFF, ip6tables_targets->userspacesize);
+       memset(mptr, 0xFF, 
+              IP6T_ALIGN(sizeof(struct ip6t_entry_target))
+              + ip6tables_targets->userspacesize);
+       /*mptr += sizeof(struct ip6t_entry_target);
+       memset(mptr, 0xFF, ip6tables_targets->userspacesize);*/
 
        return mask;
 }
@@ -1285,7 +1357,7 @@ check_packet(const ip6t_chainlabel chain,
        return ret;
 }
 
-//static int
+/*static int*/
 int
 for_each_chain(int (*fn)(const ip6t_chainlabel, int, ip6tc_handle_t *),
               int verbose, int builtinstoo, ip6tc_handle_t *handle)
@@ -1322,7 +1394,7 @@ for_each_chain(int (*fn)(const ip6t_chainlabel, int, ip6tc_handle_t *),
         return ret;
 }
 
-//static int
+/*static int*/
 int
 flush_entries(const ip6t_chainlabel chain, int verbose,
              ip6tc_handle_t *handle)
@@ -1347,7 +1419,7 @@ zero_entries(const ip6t_chainlabel chain, int verbose,
        return ip6tc_zero_entries(chain, handle);
 }
 
-//static int
+/*static int*/
 int
 delete_chain(const ip6t_chainlabel chain, int verbose,
             ip6tc_handle_t *handle)
@@ -1413,6 +1485,65 @@ list_entries(const ip6t_chainlabel chain, int verbose, int numeric,
        return found;
 }
 
+static char *get_modprobe(void)
+{
+        int procfile;
+        char *ret;
+
+        procfile = open(PROC_SYS_MODPROBE, O_RDONLY);
+        if (procfile < 0)
+                return NULL;
+
+        ret = malloc(1024);
+        if (ret) {
+                switch (read(procfile, ret, 1024)) {
+                case -1: goto fail;
+                case 1024: goto fail; /* Partial read.  Wierd */
+                }
+                if (ret[strlen(ret)-1]=='\n')
+                        ret[strlen(ret)-1]=0;
+                close(procfile);
+                return ret;
+        }
+ fail:
+        free(ret);
+        close(procfile);
+        return NULL;
+}
+
+static int ip6tables_insmod(const char *modname, const char *modprobe)
+{
+        char *buf = NULL;
+        char *argv[3];
+
+        /* If they don't explicitly set it, read out of kernel */
+        if (!modprobe) {
+                buf = get_modprobe();
+                if (!buf)
+                        return -1;
+                modprobe = buf;
+        }
+
+        switch (fork()) {
+        case 0:
+                argv[0] = (char *)modprobe;
+                argv[1] = (char *)modname;
+                argv[2] = NULL;
+                execv(argv[0], argv);
+
+                /* not usually reached */
+                exit(0);
+        case -1:
+                return -1;
+
+        default: /* parent */
+                wait(NULL);
+        }
+
+        free(buf);
+        return 0;
+}
+
 static struct ip6t_entry *
 generate_entry(const struct ip6t_entry *fw,
               struct ip6tables_match *matches,
@@ -1423,8 +1554,12 @@ generate_entry(const struct ip6t_entry *fw,
        struct ip6t_entry *e;
 
        size = sizeof(struct ip6t_entry);
-       for (m = matches; m; m = m->next)
+       for (m = matches; m; m = m->next) {
+                if (!m->used)
+                        continue;
+
                size += m->m->u.match_size;
+       }
 
        e = fw_malloc(size + target->u.target_size);
        *e = *fw;
@@ -1433,6 +1568,9 @@ generate_entry(const struct ip6t_entry *fw,
 
        size = 0;
        for (m = matches; m; m = m->next) {
+                if (!m->used)
+                        continue;
+
                memcpy(e->elems + size, m->m, m->m->u.match_size);
                size += m->m->u.match_size;
        }
@@ -1459,6 +1597,7 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
        struct ip6tables_target *t;
        const char *jumpto = "";
        char *protocol = NULL;
+        const char *modprobe = NULL;
 
        memset(&fw, 0, sizeof(fw));
 
@@ -1473,10 +1612,12 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
          * (we clear the global list of all matches for security)*/
         for (m = ip6tables_matches; m; m = m->next) {
                 m->mflags = 0;
+                m->used = 0;
         }
 
         for (t = ip6tables_targets; t; t = t->next) {
                 t->tflags = 0;
+                t->used = 0;
         }
 
        /* Suppress error messages: we may add new options if we
@@ -1777,6 +1918,9 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
                                               &target->tflags,
                                               &fw, &target->t))) {
                                for (m = ip6tables_matches; m; m = m->next) {
+                                        if (!m->used)
+                                                continue;
+
                                        if (m->parse(c - m->option_offset,
                                                     argv, invert,
                                                     &m->mflags,
@@ -1820,10 +1964,14 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
                invert = FALSE;
        }
 
-       for (m = ip6tables_matches; m; m = m->next) 
+       for (m = ip6tables_matches; m; m = m->next) {
+                if (!m->used)
+                        continue;
+
                m->final_check(m->mflags);
+       }
 
-       if (target)
+       if (target) 
                target->final_check(target->tflags);
 
        /* Fix me: must put inverse options checking here --MN */
@@ -1877,6 +2025,12 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
         if (!*handle)
                 *handle = ip6tc_init(*table);
 
+        if (!*handle) {
+                /* try to insmod the module if iptc_init failed */
+                ip6tables_insmod("ip6_tables", modprobe);
+                *handle = ip6tc_init(*table);
+        }
+
         if (!*handle)
                 exit_error(VERSION_PROBLEM,
                            "can't initialize ip6tables table `%s': %s",
@@ -1945,6 +2099,7 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
                }
 
                if (!target) {
+#if 0
                        struct ip6t_entry_target unknown_target;
 
                        /* Don't know it.  Must be extension with no
@@ -1954,6 +2109,12 @@ int do_command6(int argc, char *argv[], char **table, ip6tc_handle_t *handle)
 
                        e = generate_entry(&fw, ip6tables_matches,
                                           &unknown_target);
+#endif
+                        /* it is no chain, and we can't load a plugin.
+                         * We cannot know if the plugin is corrupt, non
+                         * existant OR if the user just misspelled a
+                         * chain. */
+                        find_target(jumpto, LOAD_MUST_SUCCEED);
                } else {
                        e = generate_entry(&fw, ip6tables_matches, target->t);
                }