Update the work on ipfw tables, reduce diffs.
[ipfw.git] / dummynet / ip_fw2.c
index 19d4d94..50e8701 100644 (file)
@@ -44,10 +44,11 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #endif
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
-#include "opt_mac.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/condvar.h>
+#include <sys/eventhandler.h>
 #include <sys/malloc.h>
 #include <sys/mbuf.h>
 #include <sys/kernel.h>
@@ -56,6 +57,7 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #include <sys/module.h>
 #include <sys/priv.h>
 #include <sys/proc.h>
+#include <sys/rwlock.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 #include <sys/sysctl.h>
@@ -68,6 +70,11 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #include <net/pf_mtag.h>
 #include <net/vnet.h>
 
+#ifdef linux
+#define INP_LOCK_ASSERT                /* define before missing.h otherwise ? */
+#include "missing.h"
+#endif
+
 #define        IPFW_INTERNAL   /* Access to protected data structures in ip_fw.h. */
 
 #include <netinet/in.h>
@@ -92,6 +99,7 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #include <netinet/icmp6.h>
 #ifdef INET6
 #include <netinet6/scope6_var.h>
+#include <netinet6/ip6_var.h>
 #endif
 
 #include <machine/in_cksum.h>  /* XXX for in_cksum */
@@ -100,14 +108,6 @@ __FBSDID("$FreeBSD: src/sys/netinet/ip_fw2.c,v 1.175.2.13 2008/10/30 16:29:04 bz
 #include <security/mac/mac_framework.h>
 #endif
 
-#ifdef linux
-//#include <linux/netdevice.h>    /* XXX dev_net() is used in linux 2.6.30.5 */
-#define INP_LOCK_ASSERT                /* define before missing.h otherwise ? */
-#include "missing.h"
-#define _IPV6_H                /* prevent ipv6 inclusion from hashtables and udp.h */
-#include <net/sock.h>  /* linux - struct sock and sock_put() */
-#endif
-
 static VNET_DEFINE(int, ipfw_vnet_ready) = 0;
 #define        V_ipfw_vnet_ready       VNET(ipfw_vnet_ready)
 /*
@@ -218,6 +218,9 @@ SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs,
 
 #endif /* SYSCTL_NODE */
 
+#ifndef IPFW_NEWTABLES_MAX
+#define IPFW_NEWTABLES_MAX     256
+#endif
 /*
  * Description of dynamic rules.
  *
@@ -1912,7 +1915,7 @@ lookup_next_rule(struct ip_fw *me, u_int32_t tablearg)
        struct ip_fw *rule = NULL;
        ipfw_insn *cmd;
        u_int16_t       rulenum;
-
+printf("%s called\n", __FUNCTION__);
        /* look for action, in case it is a skipto */
        cmd = ACTION_PTR(me);
        if (cmd->opcode == O_LOG)
@@ -1939,6 +1942,37 @@ lookup_next_rule(struct ip_fw *me, u_int32_t tablearg)
        return rule;
 }
 
+#ifdef IPFW_HAVE_SKIPTO_TABLE
+struct ip_fw *lookup_skipto_table(struct ip_fw_chain *chain, uint16_t num);
+
+struct ip_fw *
+lookup_skipto_table(struct ip_fw_chain *chain, uint16_t num)
+{
+       struct ip_fw *f;
+
+       printf("--%s called\n", __FUNCTION__);
+       if (1)
+               return NULL;
+       if (chain->skipto_pointers[num].id == chain->id) {
+               printf("-- %s pointer ok, return it\n", __FUNCTION__);
+               return chain->skipto_pointers[num].rule;
+       }
+       printf("-- %s search pointer\n", __FUNCTION__);
+
+       for (f = chain->rules; f ; f = f->next) {
+               if (f->rulenum == num) {
+                       chain->skipto_pointers[num].id = chain->id;
+                       chain->skipto_pointers[num].rule = f;
+                       printf("-- %s found, set and return\n", __FUNCTION__);
+                       return f;
+               }
+       }
+       printf("-- %s NOT found return NULL\n", __FUNCTION__);
+
+       return NULL;
+}
+#endif /* IPFW_HAVE_SKIPTO_TABLE */
+
 #ifdef radix
 static int
 add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
@@ -2029,6 +2063,9 @@ extern int del_table_entry(struct ip_fw_chain *ch, uint16_t tbl,
 extern int flush_table(struct ip_fw_chain *ch, uint16_t tbl);
 extern int count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
 extern int dump_table(struct ip_fw_chain *ch, ipfw_table *tbl);
+extern int lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
+    uint32_t *val);
+extern int init_tables(struct ip_fw_chain *ch);
 #endif
 
 static void
@@ -2038,14 +2075,14 @@ flush_tables(struct ip_fw_chain *ch)
 
        IPFW_WLOCK_ASSERT(ch);
 
-       for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++)
+       for (tbl = IPFW_TABLES_MAX -1; tbl < IPFW_NEWTABLES_MAX; tbl++)
                flush_table(ch, tbl);
 }
 
+#ifdef radix
 static int
 init_tables(struct ip_fw_chain *ch)
 { 
-#ifdef radix
        int i;
        uint16_t j;
 
@@ -2057,7 +2094,6 @@ init_tables(struct ip_fw_chain *ch)
                        return (ENOMEM);
                }
        }
-#endif
        return (0);
 }
 
@@ -2065,7 +2101,6 @@ static int
 lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
     uint32_t *val)
 {
-#ifdef radix
        struct radix_node_head *rnh;
        struct table_entry *ent;
        struct sockaddr_in sa;
@@ -2080,9 +2115,9 @@ lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
                *val = ent->value;
                return (1);
        }
-#endif
        return (0);
 }
+#endif
 
 #ifdef radix
 static int
@@ -2909,6 +2944,37 @@ do {                                                                     \
                                            dst_ip.s_addr : src_ip.s_addr;
                                    uint32_t v = 0;
 
+                                   if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
+                                       v = ((ipfw_insn_u32 *)cmd)->d[1];
+                                       if (v == 0)
+                                           a = dst_ip.s_addr;
+                                       else if (v == 1)
+                                           a = src_ip.s_addr;
+                                       else if (offset != 0)
+                                           break;
+                                       else if (proto != IPPROTO_TCP &&
+                                               proto != IPPROTO_UDP)
+                                           break;
+                                       else if (v == 2)
+                                           a = dst_port;
+                                       else if (v == 3)
+                                           a = src_port;
+                                       else if (v >= 4 && v <= 6) {
+                                           check_uidgid(
+                                                   (ipfw_insn_u32 *)cmd,
+                                                   proto, oif,
+                                                   dst_ip, dst_port,
+                                                   src_ip, src_port, &fw_ugid_cache,
+                                                   &ugid_lookup, (struct inpcb *)args->m);
+                                           if (v ==4 /* O_UID */)
+                                               a = fw_ugid_cache.fw_uid;
+                                           else if (v == 5 /* O_GID */)
+                                               a = fw_ugid_cache.fw_groups[0];
+                                           else if (v == 6 /* O_JAIL */)
+                                               a = fw_ugid_cache.fw_groups[1];
+                                       } else
+                                           break;
+                                   }
                                    match = lookup_table(chain, cmd->arg1, a,
                                        &v);
                                    if (!match)
@@ -3489,6 +3555,29 @@ do {                                                                     \
                                        break;
                                }
                                /* handle skipto */
+#ifdef IPFW_HAVE_SKIPTO_TABLE
+                               /* NOTE: lookup_skipto_table can return NULL
+                                *       if the rule isn't found, so the
+                                *       standard lookup function must be
+                                *       called XXX
+                                */
+                               if (cmd->arg1 == IP_FW_TABLEARG) {
+                                       f = lookup_skipto_table(chain,
+                                                                tablearg);
+                                       if (f == NULL)
+                                               f = lookup_next_rule(f, tablearg);
+                               }
+                                else {
+                                       f = lookup_skipto_table(chain,
+                                                                cmd->arg1);
+                                       if (f == NULL) {
+                                               if (f->next_rule == NULL)
+                                                       lookup_next_rule(f, 0);
+                                               f = f->next_rule;
+                                       }
+                                }
+
+#else
                                if (cmd->arg1 == IP_FW_TABLEARG) {
                                        f = lookup_next_rule(f, tablearg);
                                } else {
@@ -3496,6 +3585,7 @@ do {                                                                      \
                                                lookup_next_rule(f, 0);
                                        f = f->next_rule;
                                }
+#endif
                                /*
                                 * Skip disabled rules, and
                                 * re-enter the inner loop
@@ -4262,10 +4352,11 @@ check_ipfw_struct(struct ip_fw *rule, int size)
                case O_IP_DST_LOOKUP:
                        if (cmd->arg1 >= IPFW_TABLES_MAX) {
                                printf("ipfw: invalid table number %d\n",
-                                   cmd->arg1);
+                                       cmd->arg1);
                                return (EINVAL);
                        }
                        if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
+                           cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
                            cmdlen != F_INSN_SIZE(ipfw_insn_u32))
                                goto bad_size;
                        break;
@@ -4821,7 +4912,7 @@ ipfw_ctl(struct sockopt *sopt)
  * NULL pointer, but this way we do not need to check for the special
  * case, plus here he have info on the default behaviour).
  */
-struct ip_fw *ip_fw_default_rule;
+//struct ip_fw *ip_fw_default_rule;
 
 /*
  * This procedure is only used to handle keepalives. It is invoked
@@ -5041,6 +5132,12 @@ vnet_ipfw_init(const void *unused)
        if (error) {
                panic("init_tables"); /* XXX Marko fix this ! */
        }
+
+#ifdef IPFW_HAVE_SKIPTO_TABLE
+//     for (error = 0; error < 64*1024; error++)
+//             V_layer3_chain.skipto_pointers[error].id = -1;
+#endif /* IPFW_HAVE_SKIPTO_TABLE */
+
 #ifdef IPFIREWALL_NAT
        LIST_INIT(&V_layer3_chain.nat);
 #endif