Major changes:
authormarta <marta@8c455092-636d-4788-adf5-e71def0336e8>
Mon, 16 Nov 2009 22:19:32 +0000 (22:19 +0000)
committermarta <marta@8c455092-636d-4788-adf5-e71def0336e8>
Mon, 16 Nov 2009 22:19:32 +0000 (22:19 +0000)
On the kernel side: removed goto from the main ipfw_chk() switch,
splitted the static and dynamic rules requests, added O_JAIL and O_GID match.
On userland: use the reentrant qsort_r() instead of the heapsort() function,
splitted the static and dynamic rules requests.

Minor changes:
removed debug messages, added comments,
sync with the linux version.

13 files changed:
Makefile
README
dummynet/include/sys/malloc.h
dummynet/ip_dummynet.c
dummynet/ip_fw2.c
dummynet/ipfw2_mod.c
dummynet/missing.h
glue.h
ipfw/Makefile
ipfw/add_rules
ipfw/dummynet.c
ipfw/ipfw2.c
slice/netconfig

index a35b722..2410b3d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,15 @@
 # $Id$
 # $Id$
+#
 # Top level makefile for building ipfw kernel and userspace.
 # You can run it manually or also under the Planetlab build.
 # Planetlab wants also the 'install' target.
 # Top level makefile for building ipfw kernel and userspace.
 # You can run it manually or also under the Planetlab build.
 # Planetlab wants also the 'install' target.
+#
+# To build on system with non standard Kernel sources or userland files,
+# you should run this with
+#
+#      make KERNELPATH=/path/to/linux-2.x.y.z USRDIR=/path/to/usr
+#
+# We assume that $(USRDIR) contains include/ and lib/ used to build userland.
 
 DATE ?= $(shell date +%Y%m%d)
 SNAPSHOT_NAME=ipfw_linux-$(DATE)
 
 DATE ?= $(shell date +%Y%m%d)
 SNAPSHOT_NAME=ipfw_linux-$(DATE)
diff --git a/README b/README
index fd40bac..fe5c578 100644 (file)
--- a/README
+++ b/README
@@ -74,14 +74,14 @@ Unless specified otherwise, all the code here is under a BSD license.
       - fetch and extract the code e.g.
 
        (cd ..; \
       - fetch and extract the code e.g.
 
        (cd ..; \
-       wget http://info.iet.unipi.it/~luigi/dummynet/ipfw_linux-20090622.tgz;\
-       tar xvzf ipfw_linux-20090622.tgz)
+       wget http://info.iet.unipi.it/~luigi/dummynet/ipfw_linux-20090724.tgz;\
+       tar xvzf ipfw_linux-20090724.tgz; mv ipfw_linux-20090724 ipfw_mod;)
 
        (but you should have done it already)
 
       - run the following commands:
 
        (but you should have done it already)
 
       - run the following commands:
-       (mkdir packages/ipfw2;
-       cp ../ipfw_mod/Makefile.openwrt packages/ipfw2/Makefile)
+       (mkdir package/ipfw2;
+       cp ../ipfw_linux/Makefile.openwrt package/ipfw2/Makefile)
 
        to create the package/ipfw2 directory in the OpenWrt source
        directory, and copy Makefile.openwrt to package/ipfw2/Makefile:
 
        to create the package/ipfw2 directory in the OpenWrt source
        directory, and copy Makefile.openwrt to package/ipfw2/Makefile:
index 03b9dfb..b6c4ac5 100644 (file)
@@ -8,9 +8,21 @@
  */
 #ifndef _WIN32 /* this is the linux version */
 
  */
 #ifndef _WIN32 /* this is the linux version */
 
+/*
+ * XXX On zeroshell (2.6.25.17) we get a load error
+ *     __you_cannot_kmalloc_that_much
+ * which is triggered when kmalloc() is called with a large
+ * compile-time constant argument (include/linux/slab_def.h)
+ *
+ * I think it may be a compiler (or source) bug because there is no
+ * evidence that such a large request is made.
+ * Making the _size argument to kmalloc volatile prevents the compiler
+ * from making the mistake, though it is clearly not ideal.
+ */
+
 #if !defined (LINUX_24) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)
 #define malloc(_size, type, flags)                     \
 #if !defined (LINUX_24) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)
 #define malloc(_size, type, flags)                     \
-       kmalloc(_size, GFP_ATOMIC | __GFP_ZERO)
+       ({ volatile int _v = _size; kmalloc(_v, GFP_ATOMIC | __GFP_ZERO); })
 #else /* LINUX <= 2.6.22 and LINUX_24 */
 /* linux 2.6.22 does not zero allocated memory */
 #define malloc(_size, type, flags)                     \
 #else /* LINUX <= 2.6.22 and LINUX_24 */
 /* linux 2.6.22 does not zero allocated memory */
 #define malloc(_size, type, flags)                     \
index b8cbc2e..c0399bb 100644 (file)
@@ -1549,9 +1549,15 @@ dropit:
  * Below, the rt_unref is only needed when (pkt->dn_dir == DN_TO_IP_OUT)
  * Doing this would probably save us the initial bzero of dn_pkt
  */
  * Below, the rt_unref is only needed when (pkt->dn_dir == DN_TO_IP_OUT)
  * Doing this would probably save us the initial bzero of dn_pkt
  */
+#if defined( __linux__ )
+#define DN_FREE_PKT(_m) do {                           \
+       netisr_dispatch(-1, _m);                        \
+} while (0)
+#else
 #define        DN_FREE_PKT(_m) do {                            \
        m_freem(_m);                                    \
 } while (0)
 #define        DN_FREE_PKT(_m) do {                            \
        m_freem(_m);                                    \
 } while (0)
+#endif
 
 /*
  * Dispose all packets and flow_queues on a flow_set.
 
 /*
  * Dispose all packets and flow_queues on a flow_set.
index e3483df..4c9b0a3 100644 (file)
@@ -2002,25 +2002,6 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
        int match = 0;
        struct sk_buff *skb = ((struct mbuf *)inp)->m_skb;
 
        int match = 0;
        struct sk_buff *skb = ((struct mbuf *)inp)->m_skb;
 
-#if 0 /* debug */
-       printf("%s opcode %d arg %d oif %p src 0x%x:%d dst 0x%x:%d\n", __FUNCTION__,
-               insn->o.opcode, insn->d[0], oif,
-               ntohl(src_ip.s_addr), ntohs(src_port),
-               ntohl(dst_ip.s_addr), ntohs(dst_port)
-               );
-#endif
-       if (insn->o.opcode == O_JAIL) {
-#ifdef IPFW_PLANETLAB
-               match = (skb->skb_tag == insn->d[0]);
-#if 0 /* debug */
-               printf("JAIL compiled for planetlab xid %d want %d result %d\n",
-                       skb->skb_tag, insn->d[0], match);
-#endif
-
-#endif
-               return match;
-       }
-
        if (*ugid_lookupp == 0) {       /* actively lookup and copy in cache */
 
                /* returns null if any element of the chain up to file is null.
        if (*ugid_lookupp == 0) {       /* actively lookup and copy in cache */
 
                /* returns null if any element of the chain up to file is null.
@@ -2037,6 +2018,11 @@ check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif,
 
        if (insn->o.opcode == O_UID)
                match = (ugp->fw_uid == (uid_t)insn->d[0]);
 
        if (insn->o.opcode == O_UID)
                match = (ugp->fw_uid == (uid_t)insn->d[0]);
+       else if (insn->o.opcode == O_JAIL)
+               match = (ugp->fw_groups[1] == (uid_t)insn->d[0]);
+       else if (insn->o.opcode == O_GID)
+               match = (ugp->fw_groups[0] == (uid_t)insn->d[0]);
        return match;
 
 #else /* FreeBSD */
        return match;
 
 #else /* FreeBSD */
@@ -2273,6 +2259,8 @@ ipfw_chk(struct ip_fw_args *args)
        /* end of ipv6 variables */
        int is_ipv4 = 0;
 
        /* end of ipv6 variables */
        int is_ipv4 = 0;
 
+       int done = 0;           /* flag for actions match */
+
        if (m->m_flags & M_SKIP_FIREWALL)
                return (IP_FW_PASS);    /* accept */
 
        if (m->m_flags & M_SKIP_FIREWALL)
                return (IP_FW_PASS);    /* accept */
 
@@ -2583,7 +2571,7 @@ do {                                                                      \
                uint32_t tablearg = 0;
                int l, cmdlen, skip_or; /* skip rest of OR block */
 
                uint32_t tablearg = 0;
                int l, cmdlen, skip_or; /* skip rest of OR block */
 
-again:
+/* again: */
                if (set_disable & (1 << f->set) )
                        continue;
 
                if (set_disable & (1 << f->set) )
                        continue;
 
@@ -2598,7 +2586,7 @@ again:
                         * the target rule.
                         */
 
                         * the target rule.
                         */
 
-check_body:
+/* check_body: */
                        cmdlen = F_LEN(cmd);
                        /*
                         * An OR block (insn_1 || .. || insn_n) has the
                        cmdlen = F_LEN(cmd);
                        /*
                         * An OR block (insn_1 || .. || insn_n) has the
@@ -3178,8 +3166,8 @@ check_body:
                         * Exceptions:
                         * O_COUNT and O_SKIPTO actions:
                         *   instead of terminating, we jump to the next rule
                         * Exceptions:
                         * O_COUNT and O_SKIPTO actions:
                         *   instead of terminating, we jump to the next rule
-                        *   ('goto next_rule', equivalent to a 'break 2'),
-                        *   or to the SKIPTO target ('goto again' after
+                        *   ('break' after setting match and l)
+                        *   or to the SKIPTO target ('break' after
                         *   having set f, cmd and l), respectively.
                         *
                         * O_TAG, O_LOG and O_ALTQ action parameters:
                         *   having set f, cmd and l), respectively.
                         *
                         * O_TAG, O_LOG and O_ALTQ action parameters:
@@ -3197,19 +3185,24 @@ check_body:
                         * O_PROBE_STATE and O_CHECK_STATE: these opcodes
                         *   cause a lookup of the state table, and a jump
                         *   to the 'action' part of the parent rule
                         * O_PROBE_STATE and O_CHECK_STATE: these opcodes
                         *   cause a lookup of the state table, and a jump
                         *   to the 'action' part of the parent rule
-                        *   ('goto check_body') if an entry is found, or
+                        *   if an entry is found, or
                         *   (CHECK_STATE only) a jump to the next rule if
                         *   the entry is not found ('goto next_rule').
                         *   The result of the lookup is cached to make
                         *   further instances of these opcodes are
                         *   effectively NOPs.
                         *   (CHECK_STATE only) a jump to the next rule if
                         *   the entry is not found ('goto next_rule').
                         *   The result of the lookup is cached to make
                         *   further instances of these opcodes are
                         *   effectively NOPs.
+                        *   The jump to the next rule is done by a break
+                        *   after zeroing the cmdlen value and setting
+                        *   match.
                         */
                        case O_LIMIT:
                        case O_KEEP_STATE:
                                if (install_state(f,
                                    (ipfw_insn_limit *)cmd, args, tablearg)) {
                                        retval = IP_FW_DENY;
                         */
                        case O_LIMIT:
                        case O_KEEP_STATE:
                                if (install_state(f,
                                    (ipfw_insn_limit *)cmd, args, tablearg)) {
                                        retval = IP_FW_DENY;
-                                       goto done; /* error/limit violation */
+                                       /* was goto done; */ /* error/limit violation */
+                                       l = 0;          /* break the inner loop */
+                                       done = 1;       /* break the external loop */
                                }
                                match = 1;
                                break;
                                }
                                match = 1;
                                break;
@@ -3241,7 +3234,10 @@ check_body:
                                        cmd = ACTION_PTR(f);
                                        l = f->cmd_len - f->act_ofs;
                                        IPFW_DYN_UNLOCK();
                                        cmd = ACTION_PTR(f);
                                        l = f->cmd_len - f->act_ofs;
                                        IPFW_DYN_UNLOCK();
-                                       goto check_body;
+                                       /* previously was goto check_body; */
+                                       cmdlen = 0;     /* make null for() changes */
+                                       match = 1;      /* do not break to the external loop */
+                                       break;
                                }
                                /*
                                 * Dynamic entry not found. If CHECK_STATE,
                                }
                                /*
                                 * Dynamic entry not found. If CHECK_STATE,
@@ -3249,13 +3245,16 @@ check_body:
                                 * ignore and continue with next opcode.
                                 */
                                if (cmd->opcode == O_CHECK_STATE)
                                 * ignore and continue with next opcode.
                                 */
                                if (cmd->opcode == O_CHECK_STATE)
-                                       goto next_rule;
+                                       l = 0; /* was goto next_rule; */
                                match = 1;
                                break;
 
                        case O_ACCEPT:
                                retval = 0;     /* accept */
                                match = 1;
                                break;
 
                        case O_ACCEPT:
                                retval = 0;     /* accept */
-                               goto done;
+                               /* was goto done; */
+                               l = 0;          /* break the inner loop */
+                               done = 1;       /* break the external loop */
+                               break;
 
                        case O_PIPE:
                        case O_QUEUE:
 
                        case O_PIPE:
                        case O_QUEUE:
@@ -3265,7 +3264,10 @@ check_body:
                                else
                                        args->cookie = cmd->arg1;
                                retval = IP_FW_DUMMYNET;
                                else
                                        args->cookie = cmd->arg1;
                                retval = IP_FW_DUMMYNET;
-                               goto done;
+                               /* was goto done; */
+                               l = 0;          /* break the inner loop */
+                               done = 1;       /* break the external loop */
+                               break;
 
 #if 0
                        case O_DIVERT:
 
 #if 0
                        case O_DIVERT:
@@ -3292,7 +3294,10 @@ check_body:
                                m_tag_prepend(m, mtag);
                                retval = (cmd->opcode == O_DIVERT) ?
                                    IP_FW_DIVERT : IP_FW_TEE;
                                m_tag_prepend(m, mtag);
                                retval = (cmd->opcode == O_DIVERT) ?
                                    IP_FW_DIVERT : IP_FW_TEE;
-                               goto done;
+                               /* was goto done; */
+                               l = 0;          /* break the inner loop */
+                               done = 1;       /* break the external loop */
+                               break;
                        }
 #endif
 
                        }
 #endif
 
@@ -3301,8 +3306,12 @@ check_body:
                                f->pcnt++;      /* update stats */
                                f->bcnt += pktlen;
                                f->timestamp = time_uptime;
                                f->pcnt++;      /* update stats */
                                f->bcnt += pktlen;
                                f->timestamp = time_uptime;
-                               if (cmd->opcode == O_COUNT)
-                                       goto next_rule;
+                               if (cmd->opcode == O_COUNT) {
+                                       /* was goto next_rule; */
+                                       l = 0;          /* exit the inner loop */
+                                       match = 1;      /* do not break the loop */
+                                       break;
+                               }
                                /* handle skipto */
                                if (cmd->arg1 == IP_FW_TABLEARG) {
                                        f = lookup_next_rule(f, tablearg);
                                /* handle skipto */
                                if (cmd->arg1 == IP_FW_TABLEARG) {
                                        f = lookup_next_rule(f, tablearg);
@@ -3311,7 +3320,26 @@ check_body:
                                                lookup_next_rule(f, 0);
                                        f = f->next_rule;
                                }
                                                lookup_next_rule(f, 0);
                                        f = f->next_rule;
                                }
-                               goto again;
+                               /* previously was "goto again;"
+                                * We emulate by re-entering the inner loop
+                                * with the correct f, l and cmd.
+                                * First, skip over disabled rules.
+                                * Should at least match the default rule,
+                                * but try to be robust.
+                                */
+                               while (f && (set_disable & (1 << f->set)))
+                                       f = f->next;
+                               /* prepare to re-enter the inner loop. */
+                               if (f) {        /* better safe than sorry */
+                                       l = f->cmd_len;
+                                       cmd = f->cmd;
+                               } else {
+                                       l = 0;  /* this will break the inner loop */
+                               }
+                               cmdlen = 0;     /* reset loop condition */
+                               skip_or = 0;
+                               match = 1;      /* do not break the loop */
+                               break;
 
                        case O_REJECT:
                                /*
 
                        case O_REJECT:
                                /*
@@ -3345,7 +3373,10 @@ check_body:
 #endif
                        case O_DENY:
                                retval = IP_FW_DENY;
 #endif
                        case O_DENY:
                                retval = IP_FW_DENY;
-                               goto done;
+                               /* goto done; */
+                               l = 0;          /* break the inner loop */
+                               done = 1;       /* break the external loop */
+                               break;
 
                        case O_FORWARD_IP: {
                                struct sockaddr_in *sa;
 
                        case O_FORWARD_IP: {
                                struct sockaddr_in *sa;
@@ -3366,7 +3397,10 @@ check_body:
                                }
                                retval = IP_FW_PASS;
                            }
                                }
                                retval = IP_FW_PASS;
                            }
-                           goto done;
+                       /* goto done; */
+                       l = 0;              /* break the inner loop */
+                       done = 1;   /* break the external loop */
+                       break;
 
                        case O_NETGRAPH:
                        case O_NGTEE:
 
                        case O_NETGRAPH:
                        case O_NGTEE:
@@ -3377,7 +3411,10 @@ check_body:
                                        args->cookie = cmd->arg1;
                                retval = (cmd->opcode == O_NETGRAPH) ?
                                    IP_FW_NETGRAPH : IP_FW_NGTEE;
                                        args->cookie = cmd->arg1;
                                retval = (cmd->opcode == O_NETGRAPH) ?
                                    IP_FW_NETGRAPH : IP_FW_NGTEE;
-                               goto done;
+                               /* goto done; */
+                               l = 0;          /* break the inner loop */
+                               done = 1;       /* break the external loop */
+                               break;
 
 #if 0
                        case O_SETFIB:
 
 #if 0
                        case O_SETFIB:
@@ -3386,7 +3423,10 @@ check_body:
                                f->timestamp = time_uptime;
                                M_SETFIB(m, cmd->arg1);
                                args->f_id.fib = cmd->arg1;
                                f->timestamp = time_uptime;
                                M_SETFIB(m, cmd->arg1);
                                args->f_id.fib = cmd->arg1;
-                               goto next_rule;
+                               /* was goto next_rule; */
+                               l = 0;
+                               match = 1;
+                               break;
 
                        case O_NAT: {
                                struct cfg_nat *t;
 
                        case O_NAT: {
                                struct cfg_nat *t;
@@ -3401,7 +3441,10 @@ check_body:
                                                LOOKUP_NAT(layer3_chain, nat_id, t);
                                                if (t == NULL) {
                                                        retval = IP_FW_DENY;
                                                LOOKUP_NAT(layer3_chain, nat_id, t);
                                                if (t == NULL) {
                                                        retval = IP_FW_DENY;
-                                                       goto done;
+                                                       /* goto done; */
+                                                       l = 0;          /* break the inner loop */
+                                                       done = 1;       /* break the external loop */
+                                                       break;
                                                }
                                                if (cmd->arg1 != IP_FW_TABLEARG)
                                                        ((ipfw_insn_nat *)cmd)->nat = t;
                                                }
                                                if (cmd->arg1 != IP_FW_TABLEARG)
                                                        ((ipfw_insn_nat *)cmd)->nat = t;
@@ -3409,7 +3452,10 @@ check_body:
                                        retval = ipfw_nat_ptr(args, t, m);
                                } else
                                        retval = IP_FW_DENY;
                                        retval = ipfw_nat_ptr(args, t, m);
                                } else
                                        retval = IP_FW_DENY;
-                               goto done;
+                               /* goto done; */
+                               l = 0;          /* break the inner loop */
+                               done = 1;       /* break the external loop */
+                               break;
                        }
 #endif
 
                        }
 #endif
 
@@ -3431,21 +3477,25 @@ check_body:
 
                }       /* end of inner for, scan opcodes */
 
 
                }       /* end of inner for, scan opcodes */
 
-next_rule:;            /* try next rule                */
+               if (done)
+                       break;
 
 
+/* next_rule:; */              /* try next rule                */
        }               /* end of outer for, scan rules */
        }               /* end of outer for, scan rules */
+
+       if (done) {
+               /* Update statistics */
+               f->pcnt++;
+               f->bcnt += pktlen;
+               f->timestamp = time_uptime;
+               IPFW_RUNLOCK(chain);
+               return (retval);
+       }
+
        printf("ipfw: ouch!, skip past end of rules, denying packet\n");
        IPFW_RUNLOCK(chain);
        return (IP_FW_DENY);
 
        printf("ipfw: ouch!, skip past end of rules, denying packet\n");
        IPFW_RUNLOCK(chain);
        return (IP_FW_DENY);
 
-done:
-       /* Update statistics */
-       f->pcnt++;
-       f->bcnt += pktlen;
-       f->timestamp = time_uptime;
-       IPFW_RUNLOCK(chain);
-       return (retval);
-
 pullup_failed:
        if (fw_verbose)
                printf("ipfw: pullup failed\n");
 pullup_failed:
        if (fw_verbose)
                printf("ipfw: pullup failed\n");
@@ -4147,7 +4197,7 @@ bad_size:
 }
 
 /*
 }
 
 /*
- * Copy the static and dynamic rules to the supplied buffer
+ * Copy the static rules to the supplied buffer
  * and return the amount of space actually used.
  */
 static size_t
  * and return the amount of space actually used.
  */
 static size_t
@@ -4160,6 +4210,7 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
        time_t  boot_seconds;
 
         boot_seconds = boottime.tv_sec;
        time_t  boot_seconds;
 
         boot_seconds = boottime.tv_sec;
+
        /* XXX this can take a long time and locking will block packet flow */
        IPFW_RLOCK(chain);
        for (rule = chain->rules; rule ; rule = rule->next) {
        /* XXX this can take a long time and locking will block packet flow */
        IPFW_RLOCK(chain);
        for (rule = chain->rules; rule ; rule = rule->next) {
@@ -4185,6 +4236,27 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
                }
        }
        IPFW_RUNLOCK(chain);
                }
        }
        IPFW_RUNLOCK(chain);
+
+       return (bp - (char *)buf);
+}
+
+/*
+ * Copy the dynamic rules to the supplied buffer
+ * and return the amount of space actually used.
+ * XXX marta if we allocate X and rules grows
+ * we check for size limit while copying rules into the buffer
+ */
+static size_t
+ipfw_getdynrules(struct ip_fw_chain *chain, void *buf, size_t space)
+{
+       char *bp = buf;
+       char *ep = bp + space;
+       int i;
+       time_t  boot_seconds;
+
+       printf("dynrules requested\n");
+       boot_seconds = boottime.tv_sec;
+
        if (ipfw_dyn_v) {
                ipfw_dyn_rule *p, *last = NULL;
 
        if (ipfw_dyn_v) {
                ipfw_dyn_rule *p, *last = NULL;
 
@@ -4217,12 +4289,16 @@ ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
                                            TIME_LEQ(dst->expire, time_uptime) ?
                                                0 : dst->expire - time_uptime ;
                                        bp += sizeof(ipfw_dyn_rule);
                                            TIME_LEQ(dst->expire, time_uptime) ?
                                                0 : dst->expire - time_uptime ;
                                        bp += sizeof(ipfw_dyn_rule);
+                               } else {
+                                       p = NULL;       /* break the loop */
+                                       i = curr_dyn_buckets;
                                }
                        }
                IPFW_DYN_UNLOCK();
                if (last != NULL) /* mark last dynamic rule */
                        bzero(&last->next, sizeof(last));
        }
                                }
                        }
                IPFW_DYN_UNLOCK();
                if (last != NULL) /* mark last dynamic rule */
                        bzero(&last->next, sizeof(last));
        }
+
        return (bp - (char *)buf);
 }
 
        return (bp - (char *)buf);
 }
 
@@ -4259,10 +4335,8 @@ ipfw_ctl(struct sockopt *sopt)
        switch (sopt->sopt_name) {
        case IP_FW_GET:
                /*
        switch (sopt->sopt_name) {
        case IP_FW_GET:
                /*
-                * pass up a copy of the current rules. Static rules
-                * come first (the last of which has number IPFW_DEFAULT_RULE),
-                * followed by a possibly empty list of dynamic rule.
-                * The last dynamic rule has NULL in the "next" field.
+                * pass up a copy of the current static rules.
+                * The last static rule has number IPFW_DEFAULT_RULE.
                 *
                 * Note that the calculated size is used to bound the
                 * amount of data returned to the user.  The rule set may
                 *
                 * Note that the calculated size is used to bound the
                 * amount of data returned to the user.  The rule set may
@@ -4270,8 +4344,6 @@ ipfw_ctl(struct sockopt *sopt)
                 * data in which case we'll just return what fits.
                 */
                size = static_len;      /* size of static rules */
                 * data in which case we'll just return what fits.
                 */
                size = static_len;      /* size of static rules */
-               if (ipfw_dyn_v)         /* add size of dyn.rules */
-                       size += (dyn_count * sizeof(ipfw_dyn_rule));
 
                /*
                 * XXX todo: if the user passes a short length just to know
 
                /*
                 * XXX todo: if the user passes a short length just to know
@@ -4284,6 +4356,20 @@ ipfw_ctl(struct sockopt *sopt)
                free(buf, M_TEMP);
                break;
 
                free(buf, M_TEMP);
                break;
 
+       case IP_FW_DYN_GET:
+               /*
+                * pass up a copy of the current dynamic rules.
+                * The last dynamic rule has NULL in the "next" field.
+                */
+               /* if (!ipfw_dyn_v) XXX check for empty set ? */
+               size = (dyn_count * sizeof(ipfw_dyn_rule)); /* size of dyn. rules */
+
+               buf = malloc(size, M_TEMP, M_WAITOK);
+               error = sooptcopyout(sopt, buf,
+                               ipfw_getdynrules(&layer3_chain, buf, size));
+               free(buf, M_TEMP);
+               break;
+
        case IP_FW_FLUSH:
                /*
                 * Normally we cannot release the lock on each iteration.
        case IP_FW_FLUSH:
                /*
                 * Normally we cannot release the lock on each iteration.
index 3bf836a..b072ab5 100644 (file)
@@ -282,13 +282,14 @@ static struct nf_sockopt_ops ipfw_sockopts = {
 #endif
 
 /*
 #endif
 
 /*
- * ipfw hooks the POST_ROUTING and the PRE_ROUTING chain.
- * PlanetLab tags the xid in the LOCAL_INPUT and in the
- * POST_ROUTING chain, so if we want to intercept the
- * traffic by using the id we need to hook the LOCAL_INPUT
- * chain instead of the PRE_ROUTING.
+ * ipfw hooks into the POST_ROUTING and the PRE_ROUTING chains.
+ * PlanetLab sets skb_tag to the slice id in the LOCAL_INPUT and
+ * POST_ROUTING chains, so if we want to use that information we
+ * need to hook the LOCAL_INPUT chain instead of the PRE_ROUTING.
+ * However at the moment the skb_tag info is not reliable so
+ * we stay with the standard hooks.
  */
  */
-#ifdef IPFW_PLANETLAB
+#if 0 // defined(IPFW_PLANETLAB)
 #define IPFW_HOOK_IN NF_IP_LOCAL_IN
 #else
 #define IPFW_HOOK_IN NF_IP_PRE_ROUTING
 #define IPFW_HOOK_IN NF_IP_LOCAL_IN
 #else
 #define IPFW_HOOK_IN NF_IP_PRE_ROUTING
@@ -461,8 +462,24 @@ ip_output(struct mbuf *m, struct mbuf __unused *opt,
  *
  * We do this only on selected protocols: TCP, ...
  *
  *
  * We do this only on selected protocols: TCP, ...
  *
- * Note- for locally generated, outgoing packets we don't need to
- * do a lookup because the sk_buff already points to the socket where
+ * The chain is the following
+ *   sk_buff*  sock*  socket*    file*
+ *     skb  ->  sk ->sk_socket->file ->f_owner    ->pid
+ *     skb  ->  sk ->sk_socket->file ->f_uid (direct)
+ *     skb  ->  sk ->sk_socket->file ->f_cred->fsuid (2.6.29+)
+ *
+ * Related headers:
+ * linux/skbuff.h      struct skbuff
+ * net/sock.h          struct sock
+ * linux/net.h         struct socket
+ * linux/fs.h          struct file
+ *
+ * With vserver we may have sk->sk_xid and sk->sk_nid that
+ * which we store in fw_groups[1] (matches O_JAIL) and fw_groups[2]
+ * (no matches yet)
+ *
+ * Note- for locally generated, outgoing packets we should not need
+ * need a lookup because the sk_buff already points to the socket where
  * the info is.
  */
 extern struct inet_hashinfo tcp_hashinfo;
  * the info is.
  */
 extern struct inet_hashinfo tcp_hashinfo;
@@ -491,10 +508,18 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
         */
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
 #define _OPT_NET_ARG
         */
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24)
 #define _OPT_NET_ARG
-#else   /* 2.6.25 and above */
+#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
+/* there is no dev_net() on 2.6.25 */
+#define _OPT_NET_ARG (skb->dev->nd_net),
+#else  /* 2.6.26 and above */
 #define _OPT_NET_ARG dev_net(skb->dev),
 #define _OPT_NET_ARG dev_net(skb->dev),
+#endif
 #endif
 
 #endif
 
+       if (0 && skb->sk) {
+               sk=skb->sk;
+       } else {
        sk =  (dir) ?
                inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
                        daddr, dport, saddr, sport,     // matches outgoing for server sockets
        sk =  (dir) ?
                inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
                        daddr, dport, saddr, sport,     // matches outgoing for server sockets
@@ -502,6 +527,7 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
                inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
                        saddr, sport, daddr, dport,     // matches incoming for server sockets
                        skb->dev->ifindex);
                inet_lookup(_OPT_NET_ARG &tcp_hashinfo,
                        saddr, sport, daddr, dport,     // matches incoming for server sockets
                        skb->dev->ifindex);
+       }
 
 #undef _OPT_NET_ARG
        /* no match, nothing to be done */
 
 #undef _OPT_NET_ARG
        /* no match, nothing to be done */
@@ -534,9 +560,15 @@ linux_lookup(const int proto, const __be32 saddr, const __be16 sport,
                        sk->sk_socket && sk->sk_socket->file) {
                ugp->fw_uid = sk->sk_socket->file->_CURR_UID;
                uid = ugp->fw_uid;
                        sk->sk_socket && sk->sk_socket->file) {
                ugp->fw_uid = sk->sk_socket->file->_CURR_UID;
                uid = ugp->fw_uid;
+               ugp->fw_groups[0] = sk->sk_socket->file->_CURR_GID;
+#ifdef CONFIG_VSERVER
+               ugp->fw_groups[1] = sk->sk_xid;
+               ugp->fw_groups[2] = sk->sk_nid;
+#endif
                ret = 1;
        }
                ret = 1;
        }
-       sock_put(sk);
+       if (1 && !skb->sk) /* the reference came from the lookup */
+               sock_put(sk);
 #undef _CURR_UID
 #undef _CURR_GID
 
 #undef _CURR_UID
 #undef _CURR_GID
 
index c47b117..b15d84a 100644 (file)
@@ -25,6 +25,7 @@
 
 /*
  * $Id$
 
 /*
  * $Id$
+ *
  * Header for kernel variables and functions that are not available in
  * userland.
  */
  * Header for kernel variables and functions that are not available in
  * userland.
  */
diff --git a/glue.h b/glue.h
index ff7ef07..86b229a 100644 (file)
--- a/glue.h
+++ b/glue.h
@@ -23,7 +23,6 @@
  * SUCH DAMAGE.
  */
 /*
  * SUCH DAMAGE.
  */
 /*
- *
  * $Id$
  *
  * glue code to adapt the FreeBSD version to linux and windows,
  * $Id$
  *
  * glue code to adapt the FreeBSD version to linux and windows,
@@ -213,7 +212,6 @@ struct clockinfo {
 void
 qsort_r(void *a, size_t n, size_t es, void *thunk,
        int cmp_t(void *, const void *, const void *));
 void
 qsort_r(void *a, size_t n, size_t es, void *thunk,
        int cmp_t(void *, const void *, const void *));
-#define heapsort(_a, _b, _c, _d)       qsort(_a, _b, _c, _d)
 
 #define setprogname(x) /* not present in linux */
 
 
 #define setprogname(x) /* not present in linux */
 
index a8a4f47..bcaed9c 100644 (file)
@@ -6,12 +6,10 @@
 # enable extra debugging information
 # Do not set with = or := so we can inherit from the caller
 $(warning Building userland ipfw for $(VER))
 # enable extra debugging information
 # Do not set with = or := so we can inherit from the caller
 $(warning Building userland ipfw for $(VER))
-EXTRA_CFLAGS += 
 EXTRA_CFLAGS += -O1
 EXTRA_CFLAGS += -O1
+# comment this on planetlab
+# EXTRA_CFLAGS += -Wall -Werror
 EXTRA_CFLAGS += -include ../glue.h
 EXTRA_CFLAGS += -include ../glue.h
-
-LDFLAGS=
-
 EXTRA_CFLAGS += -I ./include
 
 ifneq ($(VER),openwrt)
 EXTRA_CFLAGS += -I ./include
 
 ifneq ($(VER),openwrt)
@@ -25,8 +23,12 @@ endif
 endif # !openwrt
 
 CFLAGS += $(EXTRA_CFLAGS)
 endif # !openwrt
 
 CFLAGS += $(EXTRA_CFLAGS)
+# Location of OS headers and libraries. After our stuff.
+USRDIR?= /usr
+CFLAGS += -I$(USRDIR)/include
+LDFLAGS += -L$(USRDIR)/lib
 
 
-OBJS = ipfw2.o dummynet.o main.o ipv6.o altq.o
+OBJS = ipfw2.o dummynet.o main.o ipv6.o altq.o qsort_r.o
 ifneq ($(HAVE_NAT),)
     OBJS += nat.o
     EXTRA_CFLAGS += -DHAVE_NAT
 ifneq ($(HAVE_NAT),)
     OBJS += nat.o
     EXTRA_CFLAGS += -DHAVE_NAT
index 1f90c75..f7866d7 100755 (executable)
@@ -1,4 +1,6 @@
 #!/bin/bash
 #!/bin/bash
+#
+# A test script to add rules
 
 PRG=./ipfw
 
 
 PRG=./ipfw
 
index fd8fc4d..e2c5ff1 100644 (file)
@@ -74,8 +74,12 @@ static struct _s_x dummynet_params[] = {
        { NULL, 0 }     /* terminator */
 };
 
        { NULL, 0 }     /* terminator */
 };
 
+/*
+ * XXX to be updated to the new version,
+ * without the global struct command_opts variable
+ */
 static int
 static int
-sort_q(const void *pa, const void *pb)
+sort_q(void * to_be_done, const void *pa, const void *pb)
 {
        int rev = (co.do_sort < 0);
        int field = rev ? -co.do_sort : co.do_sort;
 {
        int rev = (co.do_sort < 0);
        int field = rev ? -co.do_sort : co.do_sort;
@@ -118,7 +122,7 @@ list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
                return;
 
        if (co.do_sort != 0)
                return;
 
        if (co.do_sort != 0)
-               heapsort(q, fs->rq_elements, sizeof *q, sort_q);
+               qsort_r(q, fs->rq_elements, sizeof *q, NULL, sort_q);
 
        /* Print IPv4 flows */
        index_printed = 0;
 
        /* Print IPv4 flows */
        index_printed = 0;
@@ -477,7 +481,7 @@ is_valid_number(const char *s)
  * and return the numeric bandwidth value.
  * set clocking interface or bandwidth value
  */
  * and return the numeric bandwidth value.
  * set clocking interface or bandwidth value
  */
-void
+static void
 read_bandwidth(char *arg, int *bandwidth, char *if_name, int namelen)
 {
        if (*bandwidth != -1)
 read_bandwidth(char *arg, int *bandwidth, char *if_name, int namelen)
 {
        if (*bandwidth != -1)
@@ -521,7 +525,7 @@ struct point {
        double delay;
 };
 
        double delay;
 };
 
-int
+static int
 compare_points(const void *vp1, const void *vp2)
 {
        const struct point *p1 = vp1;
 compare_points(const void *vp1, const void *vp2)
 {
        const struct point *p1 = vp1;
index ed12d9c..8d6ed87 100644 (file)
@@ -358,7 +358,8 @@ do_cmd(int optname, void *optval, uintptr_t optlen)
        if (s < 0)
                err(EX_UNAVAILABLE, "socket");
 
        if (s < 0)
                err(EX_UNAVAILABLE, "socket");
 
-       if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET ||
+       if (optname == IP_FW_GET || optname == IP_FW_DYN_GET ||
+           optname == IP_DUMMYNET_GET ||
            optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST ||
            optname == IP_FW_TABLE_GETSIZE || 
            optname == IP_FW_NAT_GET_CONFIG || 
            optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST ||
            optname == IP_FW_TABLE_GETSIZE || 
            optname == IP_FW_NAT_GET_CONFIG || 
@@ -1719,12 +1720,14 @@ void
 ipfw_list(int ac, char *av[], int show_counters)
 {
        struct ip_fw *r;
 ipfw_list(int ac, char *av[], int show_counters)
 {
        struct ip_fw *r;
-       ipfw_dyn_rule *dynrules, *d;
+       ipfw_dyn_rule *dynrules = NULL;
+       ipfw_dyn_rule *d;
 
 #define NEXT(r)        ((struct ip_fw *)((char *)r + RULESIZE(r)))
        char *lim;
        void *data = NULL;
 
 #define NEXT(r)        ((struct ip_fw *)((char *)r + RULESIZE(r)))
        char *lim;
        void *data = NULL;
-       int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
+       int bcwidth, n, nbytes, pcwidth, width, nstat;
+       int ndyn = 0;
        int exitval = EX_OK;
        int lac;
        char **lav;
        int exitval = EX_OK;
        int lac;
        char **lav;
@@ -1732,8 +1735,13 @@ ipfw_list(int ac, char *av[], int show_counters)
        char *endptr;
        int seen = 0;
        uint8_t set;
        char *endptr;
        int seen = 0;
        uint8_t set;
+       int ocmd = IP_FW_GET;
+
+       if (co.do_pipe)
+               ocmd = IP_DUMMYNET_GET;
+       else if (co.do_dynamic)
+               ocmd = IP_FW_DYN_GET;
 
 
-       const int ocmd = co.do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
        int nalloc = 1024;      /* start somewhere... */
 
        last = 0;
        int nalloc = 1024;      /* start somewhere... */
 
        last = 0;
@@ -1767,19 +1775,25 @@ ipfw_list(int ac, char *av[], int show_counters)
         * Count static rules. They have variable size so we
         * need to scan the list to count them.
         */
         * Count static rules. They have variable size so we
         * need to scan the list to count them.
         */
+       nstat = 0;
+       r = data;
+
+       if (!co.do_dynamic) {
        for (nstat = 1, r = data, lim = (char *)data + nbytes;
                    r->rulenum < IPFW_DEFAULT_RULE && (char *)r < lim;
                    ++nstat, r = NEXT(r) )
                ; /* nothing */
        for (nstat = 1, r = data, lim = (char *)data + nbytes;
                    r->rulenum < IPFW_DEFAULT_RULE && (char *)r < lim;
                    ++nstat, r = NEXT(r) )
                ; /* nothing */
+       }
 
        /*
         * Count dynamic rules. This is easier as they have
         * fixed size.
         */
 
        /*
         * Count dynamic rules. This is easier as they have
         * fixed size.
         */
-       r = NEXT(r);
-       dynrules = (ipfw_dyn_rule *)r ;
-       n = (char *)r - (char *)data;
-       ndyn = (nbytes - n) / sizeof *dynrules;
+       if (co.do_dynamic) {
+               dynrules = (ipfw_dyn_rule *)r ;
+               n = (char *)r - (char *)data;
+               ndyn = (nbytes - n) / sizeof *dynrules;
+       }
 
        /* if showing stats, figure out column widths ahead of time */
        bcwidth = pcwidth = 0;
 
        /* if showing stats, figure out column widths ahead of time */
        bcwidth = pcwidth = 0;
@@ -1802,6 +1816,7 @@ ipfw_list(int ac, char *av[], int show_counters)
                                bcwidth = width;
                }
        }
                                bcwidth = width;
                }
        }
+
        if (co.do_dynamic && ndyn) {
                for (n = 0, d = dynrules; n < ndyn; n++, d++) {
                        if (co.use_set) {
        if (co.do_dynamic && ndyn) {
                for (n = 0, d = dynrules; n < ndyn; n++, d++) {
                        if (co.use_set) {
@@ -1822,6 +1837,7 @@ ipfw_list(int ac, char *av[], int show_counters)
                                bcwidth = width;
                }
        }
                                bcwidth = width;
                }
        }
+
        /* if no rule numbers were specified, list all rules */
        if (ac == 0) {
                for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) {
        /* if no rule numbers were specified, list all rules */
        if (ac == 0) {
                for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) {
@@ -1847,6 +1863,7 @@ ipfw_list(int ac, char *av[], int show_counters)
 
        /* display specific rules requested on command line */
 
 
        /* display specific rules requested on command line */
 
+       if (!co.do_dynamic) {
        for (lac = ac, lav = av; lac != 0; lac--) {
                /* convert command line rule # */
                last = rnum = strtoul(*lav++, &endptr, 10);
        for (lac = ac, lav = av; lac != 0; lac--) {
                /* convert command line rule # */
                last = rnum = strtoul(*lav++, &endptr, 10);
@@ -1874,6 +1891,7 @@ ipfw_list(int ac, char *av[], int show_counters)
                        warnx("rule %lu does not exist", rnum);
                }
        }
                        warnx("rule %lu does not exist", rnum);
                }
        }
+       }
 
        if (co.do_dynamic && ndyn) {
                printf("## Dynamic rules:\n");
 
        if (co.do_dynamic && ndyn) {
                printf("## Dynamic rules:\n");
index efad8e7..e2afb0a 100755 (executable)
 #!/bin/sh
 #
 #!/bin/sh
 #
-# Marta Carbone
+# Marta Carbone, Luigi Rizzo
 # Copyright (C) 2009 Universita` di Pisa
 # $Id$
 #
 # Copyright (C) 2009 Universita` di Pisa
 # $Id$
 #
-# This script is the frontend to be used with
-# the vsys system.
-# It allows to configure dummynet pipes and queues.
-# In detail it:
-# - get user input
-# - send command to the vsys input pipe
-# - wait a bit
-# - get the reply from the output vsys pipe
-# - show the output to the user
-# 
-# A simple usage is:
-# ./netconfig -p 9898 <dummynet configuration parameters>
-# mandatory fields are the port to be configured
-# and dummynet configuration parameters
+# This script is the frontend to be used with the vsys system.
+# It simply passes information to the backend and gets back the reply
 
 PIPE_IN=/vsys/ipfw-be.in
 PIPE_OUT=/vsys/ipfw-be.out
 
 PIPE_IN=/vsys/ipfw-be.in
 PIPE_OUT=/vsys/ipfw-be.out
-LOGFILE=/tmp/netconfig.log
 
 
-SED=/bin/sed           # used to extract the profile name
-DEBUG=0                        # 0 disable debug messages
-prog=$0                        # this program
-
-# Print the first argument and exit
-abort()
-{
-       echo "$1"; exit 1
-}
-
-# if $DEBUG is enabled, print a debug message
-# $1 the message to print
-debug()
-{
-       [ "${DEBUG}" != "0" ] && echo "$1" >> ${LOGFILE}
-}
-
-# print the usage and exit
-help()
-{
-       cat << EOF
-Usage: $prog -p port [-U] [-t timeout[STRING]] ipfw_configuration_parameters \n
-       $prog ipfw show \n
-       $prog pipe show \n
-
-  -h show help \n
-  -p specify the port to configure \n
-  -d delete specified rules and pipes \n
-  -t specify the timeout. STRING can be "1minute" or "4hours" (default 1 hour) \n
-
-   ipfw configuration parameters (mandatory) \n
-          extra-delay <filename> bw <value> delay <value> proto... plr... \n
-
-   ipfw show show the ipfw ruleset
-   ipfw pipe show the configured pipes
-EOF
-       exit 0
-}
-
-# parse input line and fill missing fields
-parse_input()
-{
-       # counters used to check if at least
-       # two ipfw configuration parameters are present
-       local OPT_ARGS=2        # optional (timeout)
-       local MAND_ARGS=2       # mandatory (port)
-
-       [ -z "$1" ] && help;
-
-       while getopts ":hdp:t:" opt; do
-               case $opt in
-               h | \?) help;;
-               p) PORT=$OPTARG;;
-               d) DELETE=1;;
-               t) TIMEOUT=$OPTARG;;
-               esac
-       done
-
-       # check for mandatory arguments
-       [ -z ${PORT} ] && abort "a port value is mandatory";
-
-       # the default value for the timeout is 1H
-       if [ -z ${TIMEOUT} ]; then
-               TIMEOUT="1hour"
-               OPT_ARGS=$((${OPT_ARGS}-2))
-       fi
-
-       # check for deletion flag
-       if [ -z ${DELETE} ]; then
-               DELETE=0
-       else
-               # if d is present configuration is not required
-               MAND_ARGS=$((${MAND_ARGS}-2))
-       fi
-
-       # compute residue argument, we need at least 2 
-       # mandatory arguments (for ipfw), exit on error
-       # debug "Passed args $# Mandatory ${MAND_ARGS} Optional ${OPT_ARGS} Extra $(($#-${MAND_ARGS}-${OPT_ARGS}))"
-       if [ $(($#-${MAND_ARGS}-${OPT_ARGS})) -lt 2 ]; then
-               help
-       fi
-}
-
-# the backend expects lines in the format:
-# ipfw
-# pipe
-# port timeout configuration_string
-# main starts here
-
-       # allow ipfw show and ipfw pipe show commands
-       if [ x$1 = x"ipfw" ]; then
-               echo "received" $1
-               echo "ipfw" >> ${PIPE_IN}
-               cat ${PIPE_OUT}
-               exit 0;
-       else if [ x$1 = x"pipe" ]; then
-               echo "pipe" >> ${PIPE_IN}
-               cat ${PIPE_OUT}
-               exit 0;
-       fi
-       fi
-
-       # parse the input
-       parse_input $*
-       shift $((${OPTIND}-1));
-
-       # print debug
-       debug "PORT ${PORT}"
-       debug "DELETE ${DELETE}"
-       debug "TIMEOUT ${TIMEOUT}"
-       debug "PIPE_CONFIGURATION $*"
-
-       # format CMD as expected by the backend script
-       CMD="${PORT} ${TIMEOUT} ${DELETE} $*";
-
-       # send the command
-       debug "Sending: ${CMD}"
-       echo ${CMD} >> ${PIPE_IN}
-
-       cat ${PIPE_OUT}
+sudo sh -c "echo $* >> ${PIPE_IN}"
+sudo sh -c "cat ${PIPE_OUT}"