Create a new directory with PlanetLab stuff and changed specfiles accordingly.
--- /dev/null
+# Makefile to build the package in openwrt.
+# goes into package/ipfw2/Makefile
+#
+# Edit IPFW_DIR to point to the directory with the sources for ipfw
+
+IPFW_DIR := $(TOPDIR)/../ipfw_mod
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=kmod-ipfw2
+PKG_RELEASE:=1
+
+# MV is undefined
+MV ?= mv
+
+include $(INCLUDE_DIR)/package.mk
+
+# Description for the package.
+# The names KernelPackage/ipfw2 must match the arguments to the
+# call $(eval $(call KernelPackage,ipfw2)) used to build it
+
+
+define KernelPackage/ipfw2
+ SUBMENU:=Other modules
+ TITLE:= IPFW and dummynet
+ # FILES is what makes up the module, both kernel and userland
+ # It must be in the KernelPackage section
+ FILES := $(PKG_BUILD_DIR)/dummynet/ipfw_mod.o $(PKG_BUILD_DIR)/ipfw/ipfw
+ # AUTOLOAD:=$(call AutoLoad,80,ipfw_mod)
+endef
+
+define KernelPackage/ipfw2/description
+ This package contains the ipfw and dummynet module
+endef
+
+# Standard entries for the openwrt builds: Build/Prepare and Build/Compile
+# Remember that commands must start with a tab
+
+# 'prepare' instructions for both kernel and userland
+# We copy the entire subtree, then build include_e/ which
+# contains empty headers used by the kernel sources.
+define Build/Prepare
+ # $(warning Preparing ipfw sources)
+ mkdir -p $(PKG_BUILD_DIR)
+ $(CP) -Rp $(IPFW_DIR)/* $(PKG_BUILD_DIR)/
+ (cd $(PKG_BUILD_DIR)/dummynet && $(MAKE) include_e )
+endef
+
+define Build/Compile
+ # compile the kernel part for openwrt
+ $(MAKE) -C "$(LINUX_DIR)" \
+ CROSS_COMPILE="$(TARGET_CROSS)" \
+ ARCH="$(LINUX_KARCH)" \
+ SUBDIRS="$(PKG_BUILD_DIR)/dummynet" \
+ VER=openwrt modules
+ # compile the userland part for openwrt
+ $(MAKE) -C $(PKG_BUILD_DIR)/ipfw \
+ $(TARGET_CONFIGURE_OPTS) \
+ CFLAGS="$(TARGET_CFLAGS) -I./include -include ../glue.h" \
+ VER=openwrt all
+endef
+
+define Package/ipfw2-userland
+ SECTION:=utils
+ CATEGORY:=Utilities
+ TITLE := /sbin/ipfw
+ DESCRIPTION := This is the control program for ipfw and dummynet
+endef
+
+define Package/ipfw2-userland/install
+ $(INSTALL_DIR) $(1) /sbin
+endef
+
+# XXX not entirely clear why the install entry for userland works,
+# given that /sbin/ipfw is in KernelPackage/ipfw2
+
+$(eval $(call Package,ipfw2-userland))
+$(eval $(call KernelPackage,ipfw2))
--- /dev/null
+#
+# $Id: NOTES 2844 2009-06-22 10:59:35Z luigi $
+#
+
+---------------------------------------------------------------------
+--- DEVELOPER NOTES ------------------------------------------------
+
+Both the client and the kernel code use almost unmodified sources
+from FreeBSD (just a very small number of sections #ifdef'ed out
+for features not relevant or not implemented).
+
+In both cases we provide two set of headers:
+ - one set is made of empty files, automatically generated, to replace
+ FreeBSD headers not available or conflicting on the ported platforms.
+ - one set is made of custom files, sometimes copied verbatim
+ from FreeBSD, sometimes containing only the minimal set of
+ macros/ struct/ prototypes required by the port.
+
+Additionally, we have a small set of .c files providing functions not
+available in the port platforms, and hooks for the sockopt/packet
+data.
+
+
+TODO (LINUX), 20090622:
++ use an appropriate identifier instead of LINUX24
++ find the discharging module hook, in order to force a queue flush
++ use the output interface as a clock for the pipe
++ better matching on interface names (case insensitive etc ?)
++ match by interface address
++ verify path
++ send keepalives
++ tables support
++ uid/gid match (through the socket ?)
++ pullup or data in external buffers
++ O_TAG
++ O_DIVERT
++ O_TEE
++ O_SETFIB
++ kmem_cache_alloc
+
+TODO (WINDOWS) 20090622
++ all of the above, once it works
+# svn
+https://svn.sourceforge.net/svnroot/wipfw
+
+TODO (OpenWRT) 20090622
++ add a module compilation for 2.6
+
+TODO (FreeBSD, general)
++ New features related to the forthcoming IPv6 are missing, as the IPv6
+support for lookup tables that currently support IPv4 addresses only.
+One of the goal of this project is to add the tables feature to the
+IPv6 protocol.
+
++ The current code implements rules listing requests as a single
+request returning both static and dynamic rules as a whole block. This
+operation requires a lock to be held for the time needed to get the
+full list of rules, regardless of the requested rules. I propose to
+break up the rule request in two parts, for static and dynamic rules, in
+order to avoid to lock the whole struct for a subset of rules required.
+
++ At last, due to improvement and contribution to the code, the tool
+significantly grown over the time with new functionalities and features,
+leaving the general view aside. An example of this will be the use of
+dispatching table instead some very long switch case, making the resulting
+code more readable and hopefully a faster execution.
+
++ XXX can't find the ipfw_* indirection...
+
+DETAILED PORTING INFO
+
+--- ipfw (userland) on linux ---
+
+The port is relatively trivial. Communication with the kernel occurs
+through a raw socket using [gs]etsockopt(), and all is needed is the
+availability of ip_fw.h and ip_dummynet.h headers to describe the
+relevant data structures.
+
+--- kernel ipfw on linux ---
+
+Sources are mostly unmodified, except for commenting out
+unsupported features (tables, in-kernel nat...).
+The port requires a rather large number of empty headers.
+Other porting issues are in ipfw2_mod.c
+
+--- build as an Openwrt package
+
+------ WINDOWS PORT ------
+
+A port to windows is still in progress.
+This directory contain a port of ipfw and dummynet to Windows.
+
+--- BACKGROUND:
+
+We started from the wipfw port available at [WIPFW] , but
+most of the port is done from scratch using the most recent
+version of ipfw+dummynet from HEAD/RELENG_7 as of March 2009
+
+# WIPFW: wipfw.sourceforge.net
+#binary:
+http://downloads.sourceforge.net/wipfw/wipfw-0.3.2b.zip?use_mirror=mesh
+http://downloads.sourceforge.net/wipfw/wipfw-0.2.8-source.zip
+
+--- DEVELOPMENT TOOLS:
+
+At least initially, to build the code you need a pc with
+windows installed and the [WINDDK] from the microsoft site.
+Other tools like the new WDK should work as well.
+
+The 'standard' way used by WDK/WINDDK is to run a 'build'
+script which in turn calls nmake and then the microsoft
+compiler [CL] and linker [LINK]. See the documentation for
+command line switches for these tools, they are similar but
+not the same as the equivalent gcc switches. In particular,
+a / is often used to replace - though both forms are accepted.
+
+The steps to do in order to launch the build environment follows:
+
+ + download winddk from microsoft.com
+ + install
+ + run the Free Build Enviroment from:
+
+ Start -> All Program -> WINDDK ->
+ [NT|XP|2000] -> Free Build Environment
+
+ + change dir to .src and type `build' in command line
+
+For our purposes, however, it is much more convenient to use
+cygwin [CYGWIN] and invoke CL and LINK using gmake
+
+A debugging tools is:
+ http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx
+it simply display the kernel-mode debug output.
+Use the DbgPrint() function, that is something similar to printk().
+Can be lauched with dbgview.exe.
+
+After a succesfully compilation and link, you can launch the program
+in user space simply executing the binary file, while for the kernel
+space you need to do the following steps:
+
+cp ipfw.sys /cygdrive/c/WINDOWS/system32/drivers/
+ipfw install_drv System32\DRIVERS\ip_fw.sys
+net start ip_fw
+
+
+=======
+--- ARCHITECTURE ---
+
+The main part of the userland program mostly work as the
+unix equivalent, the only issue is to provide empty
+header files to replace those not available in Windows,
+and include the winsock2 headers to access some network
+related functions and headers.
+
+Communication with the kernel module does not use a raw IP socket
+as in the unix version. Instead, we inherit the same method
+used in ipfw -- a replacement for socket() creates a handle
+to access the control structure, and setsockopt/getsockopt
+replacements are also used to communicate with the kernel
+side. This is implemented in win32.c
+
+In order to load the module and activate it, we also use
+the same technique suggested in wipfw -- the main() is
+extended (with a wrapper) so that it can handle additional
+commands to install/control/deinstall the service and
+call the appropriate actions. See svcmain.c for details.
+
+--- PORTING ISSUES:
+
+Most of the unix hierarchy of headers is not available so we
+have to replicate them.
+
+gcc attributes are also not present.
+
+C99 types are not present, remapped in <sys/cdefs.h>
+
+--- USEFUL LINKS:
+
+[WIPFW]
+ http://wipfw.sourceforge.net/
+
+[WINDDK]
+ http://www.microsoft.com/whdc/devtools/ddk/default.mspx
+
+[CL]
+ http://msdn.microsoft.com/en-us/library/610ecb4h.aspx
+ command line syntax
+
+[CYGWIN]
+ http://www.cygwin.com/setup.exe
#
-# $Id: README 4363 2009-12-08 16:06:54Z marta $
+# $Id: README 4396 2009-12-09 21:52:46Z luigi $
#
This directory contains a port of ipfw and dummynet to Linux and OpenWrt
-(a Windows version is in the works but not ready yet).
+(including PlanetLab). A Windows version is in the works but not ready yet.
Building the code produces:
a kernel module, ipfw_mod.ko
and headers written from scratch.
Unless specified otherwise, all the code here is under a BSD license.
-=== To compile for a 2.6 kernel, simply run
+=================== BUILD INSTRUCTIONS ==========================
- make
+***** Linux 2.6.x ******
- Make sure that kernel headers (or sources) are installed on your
- system, and that the link "/lib/modules/`uname -r`/build" points
- to the header/source tree matching your kernel.
+ make KERNELPATH=/path/to/linux USRDIR=/path/to/usr
- You can override the default kernel tree with
-
- make KERNELPATH=your_kernel_source_tree
+ where the two variables are optional an point to the linux kernel
+ sources and the /usr directory. Defaults are USRDIR=/usr and
+ KERNELPATH=/lib/modules/`uname -r`/build --- XXX check ?
NOTE: make sure CONFIG_NETFILTER is enabled in the kernel
configuration file. You can enable it by doing
[*] Network packet filtering framework (Netfilter)
-=== To compile for a 2.4 kernel:
+***** Linux 2.4.x *****
+
+ Almost as above, with an additional VER=2.4
make VER=2.4 KERNELPATH=...
You need to follow the same instruction for the 2.6 kernel, enabling
- the kernel options:
+ netfilter in the kernel options:
Networking options --->
[*] Network packet filtering (replaces ipchains)
-=== To build an Openwrt package
+***** Openwrt package *****
(Tested with kamikaze_8.09.1 and Linux 2.4)
/lib/modules/2.4.35.4/ipfw show # launch the userspace tool
rmmod ipfw_mod.o # remove the module
+***** PLANETLAB BUILD *****
+
-----------------------------------------------------------------------------
--- /dev/null
+OpenWrt on ASUSWL-520GC (admin, admin)
+
+Notes:
+ The firmware installed is the version: 2.0.1.1, the ip address
+ is 192.168.1.1, the web gui can be used by admin, admin.
+ After reflashing the board, the old firmware should be available
+ in the cdrom shipped with the router.
+
+OpenWRT compatility:
+1. The 2.4 kernel version has some troubles accessing the flash
+ and this will actually make the board hang after a while.
+
+2. The 2.6 kernel does not have the same issue, except for the
+ open source b43 wireless driver, that make the board reboot
+ as soon as it is loaded.
+
+For this reason, when configuring the kernel option from the toolchain
+menu, the wireless target profile to choose should be `No WiFi'
+
+Flash the board:
+1. The compiled binary images are under the main tree, ./bin the file
+ to be used is openwrt-brcm47xx-squashfs.trx.
+2. Start the router in diag mode and goes with tftp, as follows:
+ tftp 192.168.1.1
+ tftp> bin
+ tftp> put openwrt-brcm47xx-squashfs.trx
+ Sent 1904640 bytes in 5.4 seconds
+ tftp>
+3. Wait for 10 minutes, the reboot
obj-m := ipfw_mod.o
# generic cflags used on all systems
+ipfw-cflags += -Dradix
ipfw-cflags += -DIPFIREWALL_DEFAULT_TO_ACCEPT -DTRACE
# _BSD_SOURCE enables __FAVOR_BSD (udp/tcp bsd structs instead of posix)
ipfw-cflags += -D_BSD_SOURCE
# Original ipfw and dummynet sources + FreeBSD stuff,
IPFW_SRCS = ip_fw2.c ip_dummynet.c ip_fw_pfil.c in_cksum.c
-
+IPFW_SRCS += radix.c
# Module glue and functions missing in linux
IPFW_SRCS += ipfw2_mod.c bsd_compat.c hashtable.c new_glue.c
$(LD) $(LDFLAGS) -m elf_i386 -r -o $@ $^
clean:
-rm -f *.o *.ko Module.symvers *.mod.c
+ -rm -rf include_e
distclean: clean
-rm -f .*cmd modules.order opt_*
-rm -rf .tmp_versions include_e
- -rm -rf .ip_dummynet.o.d
+ -rm -rf .*.o.d
# support to create empty dirs and files in include_e/
# EDIRS is the list of directories, EFILES is the list of files.
EDIRS= altq arpa machine net netinet netinet6 sys
-EFILES += opt_inet6.h opt_ipfw.h opt_ipsec.h opt_mac.h
+EFILES += opt_inet6.h opt_ipfw.h opt_ipsec.h
EFILES += opt_mbuf_stress_test.h opt_param.h
EFILES += altq/if_altq.h
EFILES += arpa/inet.h
EFILES += machine/in_cksum.h
-EFILES += net/ethernet.h net/netisr.h net/pf_mtag.h net/radix.h
+EFILES += net/ethernet.h net/netisr.h net/pf_mtag.h
EFILES += net/vnet.h
EFILES += netinet/ether.h netinet/icmp6.h netinet/if_ether.h
EFILES += netinet6/ip6_var.h
-EFILES += sys/_lock.h sys/_mutex.h sys/jail.h
+EFILES += sys/_lock.h sys/_rwlock.h sys/_mutex.h sys/jail.h
+EFILES += sys/condvar.h sys/eventhandler.h
EFILES += sys/limits.h sys/lock.h sys/mutex.h sys/priv.h
EFILES += sys/proc.h sys/rwlock.h sys/socket.h sys/socketvar.h
EFILES += sys/sysctl.h sys/time.h sys/ucred.h
i = h->hash(obj, h->table_size);
for (o = h->table_ptr[i]; o; o = o->next) {
if (h->cmp(o->obj, obj) == 0)
- return obj;
+ return o->obj;
}
return NULL;
}
--- /dev/null
+/*-
+ * Copyright (c) 1988, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)radix.h 8.2 (Berkeley) 10/31/94
+ * $FreeBSD: head/sys/net/radix.h 185747 2008-12-07 21:15:43Z kmacy $
+ */
+
+#ifndef _RADIX_H_
+#define _RADIX_H_
+
+#ifdef _KERNEL
+#include <sys/_lock.h>
+#include <sys/_mutex.h>
+#include <sys/_rwlock.h>
+#endif
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_RTABLE);
+#endif
+
+/*
+ * Radix search tree node layout.
+ */
+
+struct radix_node {
+ struct radix_mask *rn_mklist; /* list of masks contained in subtree */
+ struct radix_node *rn_parent; /* parent */
+ short rn_bit; /* bit offset; -1-index(netmask) */
+ char rn_bmask; /* node: mask for bit test*/
+ u_char rn_flags; /* enumerated next */
+#define RNF_NORMAL 1 /* leaf contains normal route */
+#define RNF_ROOT 2 /* leaf is root leaf for tree */
+#define RNF_ACTIVE 4 /* This node is alive (for rtfree) */
+ union {
+ struct { /* leaf only data: */
+ caddr_t rn_Key; /* object of search */
+ caddr_t rn_Mask; /* netmask, if present */
+ struct radix_node *rn_Dupedkey;
+ } rn_leaf;
+ struct { /* node only data: */
+ int rn_Off; /* where to start compare */
+ struct radix_node *rn_L;/* progeny */
+ struct radix_node *rn_R;/* progeny */
+ } rn_node;
+ } rn_u;
+#ifdef RN_DEBUG
+ int rn_info;
+ struct radix_node *rn_twin;
+ struct radix_node *rn_ybro;
+#endif
+};
+
+#define rn_dupedkey rn_u.rn_leaf.rn_Dupedkey
+#define rn_key rn_u.rn_leaf.rn_Key
+#define rn_mask rn_u.rn_leaf.rn_Mask
+#define rn_offset rn_u.rn_node.rn_Off
+#define rn_left rn_u.rn_node.rn_L
+#define rn_right rn_u.rn_node.rn_R
+
+/*
+ * Annotations to tree concerning potential routes applying to subtrees.
+ */
+
+struct radix_mask {
+ short rm_bit; /* bit offset; -1-index(netmask) */
+ char rm_unused; /* cf. rn_bmask */
+ u_char rm_flags; /* cf. rn_flags */
+ struct radix_mask *rm_mklist; /* more masks to try */
+ union {
+ caddr_t rmu_mask; /* the mask */
+ struct radix_node *rmu_leaf; /* for normal routes */
+ } rm_rmu;
+ int rm_refs; /* # of references to this struct */
+};
+
+#define rm_mask rm_rmu.rmu_mask
+#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */
+
+typedef int walktree_f_t(struct radix_node *, void *);
+
+struct radix_node_head {
+ struct radix_node *rnh_treetop;
+ int rnh_addrsize; /* permit, but not require fixed keys */
+ int rnh_pktsize; /* permit, but not require fixed keys */
+ struct radix_node *(*rnh_addaddr) /* add based on sockaddr */
+ (void *v, void *mask,
+ struct radix_node_head *head, struct radix_node nodes[]);
+ struct radix_node *(*rnh_addpkt) /* add based on packet hdr */
+ (void *v, void *mask,
+ struct radix_node_head *head, struct radix_node nodes[]);
+ struct radix_node *(*rnh_deladdr) /* remove based on sockaddr */
+ (void *v, void *mask, struct radix_node_head *head);
+ struct radix_node *(*rnh_delpkt) /* remove based on packet hdr */
+ (void *v, void *mask, struct radix_node_head *head);
+ struct radix_node *(*rnh_matchaddr) /* locate based on sockaddr */
+ (void *v, struct radix_node_head *head);
+ struct radix_node *(*rnh_lookup) /* locate based on sockaddr */
+ (void *v, void *mask, struct radix_node_head *head);
+ struct radix_node *(*rnh_matchpkt) /* locate based on packet hdr */
+ (void *v, struct radix_node_head *head);
+ int (*rnh_walktree) /* traverse tree */
+ (struct radix_node_head *head, walktree_f_t *f, void *w);
+ int (*rnh_walktree_from) /* traverse tree below a */
+ (struct radix_node_head *head, void *a, void *m,
+ walktree_f_t *f, void *w);
+ void (*rnh_close) /* do something when the last ref drops */
+ (struct radix_node *rn, struct radix_node_head *head);
+ struct radix_node rnh_nodes[3]; /* empty tree for common case */
+ int rnh_multipath; /* multipath capable ? */
+#ifdef _KERNEL
+#if defined( __linux__ ) || defined( _WIN32 )
+ spinlock_t rnh_lock;
+#else
+ struct rwlock rnh_lock; /* locks entire radix tree */
+#endif /* !__linux__ */
+#endif
+};
+
+#ifndef _KERNEL
+#define R_Malloc(p, t, n) (p = (t) malloc((unsigned int)(n)))
+#define R_Zalloc(p, t, n) (p = (t) calloc(1,(unsigned int)(n)))
+#define Free(p) free((char *)p);
+#else
+#define R_Malloc(p, t, n) (p = (t) malloc((unsigned long)(n), M_RTABLE, M_NOWAIT))
+#define R_Zalloc(p, t, n) (p = (t) malloc((unsigned long)(n), M_RTABLE, M_NOWAIT | M_ZERO))
+#define Free(p) free((caddr_t)p, M_RTABLE);
+
+#define RADIX_NODE_HEAD_LOCK_INIT(rnh) \
+ rw_init_flags(&(rnh)->rnh_lock, "radix node head", 0)
+#define RADIX_NODE_HEAD_LOCK(rnh) rw_wlock(&(rnh)->rnh_lock)
+#define RADIX_NODE_HEAD_UNLOCK(rnh) rw_wunlock(&(rnh)->rnh_lock)
+#define RADIX_NODE_HEAD_RLOCK(rnh) rw_rlock(&(rnh)->rnh_lock)
+#define RADIX_NODE_HEAD_RUNLOCK(rnh) rw_runlock(&(rnh)->rnh_lock)
+#define RADIX_NODE_HEAD_LOCK_TRY_UPGRADE(rnh) rw_try_upgrade(&(rnh)->rnh_lock)
+
+
+#define RADIX_NODE_HEAD_DESTROY(rnh) rw_destroy(&(rnh)->rnh_lock)
+#define RADIX_NODE_HEAD_LOCK_ASSERT(rnh) rw_assert(&(rnh)->rnh_lock, RA_LOCKED)
+#define RADIX_NODE_HEAD_WLOCK_ASSERT(rnh) rw_assert(&(rnh)->rnh_lock, RA_WLOCKED)
+#endif /* _KERNEL */
+
+void rn_init(void);
+int rn_inithead(void **, int);
+int rn_refines(void *, void *);
+struct radix_node
+ *rn_addmask(void *, int, int),
+ *rn_addroute (void *, void *, struct radix_node_head *,
+ struct radix_node [2]),
+ *rn_delete(void *, void *, struct radix_node_head *),
+ *rn_lookup (void *v_arg, void *m_arg,
+ struct radix_node_head *head),
+ *rn_match(void *, struct radix_node_head *);
+
+#endif /* _RADIX_H_ */
SLIST_HEAD(dn_pipe_head, dn_pipe);
#ifdef _KERNEL
-typedef int ip_dn_ctl_t(struct sockopt *); /* raw_ip.c */
typedef void ip_dn_ruledel_t(void *); /* ip_fw.c */
-typedef int ip_dn_io_t(struct mbuf **m, int dir, struct ip_fw_args *fwa);
-extern ip_dn_ctl_t *ip_dn_ctl_ptr;
extern ip_dn_ruledel_t *ip_dn_ruledel_ptr;
-extern ip_dn_io_t *ip_dn_io_ptr;
/*
* Return the IPFW rule associated with the dummynet tag; if any.
int ipfw_chk(struct ip_fw_args *);
-int ipfw_init(void);
-void ipfw_destroy(void);
-
-typedef int ip_fw_ctl_t(struct sockopt *);
-extern ip_fw_ctl_t *ip_fw_ctl_ptr;
-extern int fw_one_pass;
-extern int fw_enable;
-#ifdef INET6
-extern int fw6_enable;
+int ipfw_hook(void);
+int ipfw6_hook(void);
+int ipfw_unhook(void);
+int ipfw6_unhook(void);
+#ifdef NOTYET
+void ipfw_nat_destroy(void);
#endif
-/* For kernel ipfw_ether and ipfw_bridge. */
-typedef int ip_fw_chk_t(struct ip_fw_args *args);
-extern ip_fw_chk_t *ip_fw_chk_ptr;
+#define IPFW_HAVE_SKIPTO_TABLE
-#ifdef IPFW_INTERNAL
+struct _rulepointer {
+ struct ip_fw *rule;
+ uint32_t id;
+};
+
+VNET_DECLARE(int, fw_one_pass);
+VNET_DECLARE(int, fw_enable);
+#define V_fw_one_pass VNET(fw_one_pass)
+#define V_fw_enable VNET(fw_enable)
+
+#ifdef INET6
+VNET_DECLARE(int, fw6_enable);
+#define V_fw6_enable VNET(fw6_enable)
+#endif
struct ip_fw_chain {
struct ip_fw *rules; /* list of rules */
struct rwlock rwmtx;
#endif /* !__linux__ */
uint32_t id; /* ruleset id */
+ struct _rulepointer skipto_pointers[64*1024];
+ struct new_hash_table *global_tables[128];
};
+
+#ifdef IPFW_INTERNAL
+
#define IPFW_LOCK_INIT(_chain) \
rw_init(&(_chain)->rwmtx, "IPFW static rules")
#define IPFW_LOCK_DESTROY(_chain) rw_destroy(&(_chain)->rwmtx)
typedef int ipfw_nat_cfg_t(struct sockopt *);
#endif
+VNET_DECLARE(struct ip_fw_chain, layer3_chain);
+#define V_layer3_chain VNET(layer3_chain)
+
#endif /* _KERNEL */
#endif /* _IPFW2_H */
#ifdef _KERNEL
/* bzero not present on linux, but this should go in glue.h */
-#define bzero(s, n) memset(s, 0, n)
+// #define bzero(s, n) memset(s, 0, n)
/*
* We implement a very simplified UMA allocator where the backend
* include files marked with XXX are probably not needed
*/
+#include "missing.h"
+
#include <sys/limits.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/module.h>
-#include <sys/mutex.h>
#include <sys/priv.h>
#include <sys/proc.h>
+#include <sys/rwlock.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/time.h>
#include <netinet/ip6.h> /* for ip6_input, ip6_output prototypes */
#include <netinet6/ip6_var.h>
-#include "missing.h"
-
/*
* We keep a private variable for the simulation time, but we could
* probably use an existing one ("softticks" in sys/kern/kern_timeout.c)
static void dummynet_flush(void);
static void dummynet_send(struct mbuf *);
void dummynet_drain(void);
-static ip_dn_io_t dummynet_io;
static void dn_rule_delete(void *);
+static int dummynet_io(struct mbuf **, int , struct ip_fw_args *);
/*
* Heap management functions.
u_int t = div64(curr_time - q->q_time,
fs->lookup_step);
- q->avg = (t >= 0 && t < fs->lookup_depth) ?
+ q->avg = (t < fs->lookup_depth) ?
SCALE_MUL(q->avg, fs->w_q_lookup[t]) : 0;
}
}
#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>
#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>
#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>
#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 */
#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)
/*
#endif /* SYSCTL_NODE */
+#ifndef IPFW_NEWTABLES_MAX
+#define IPFW_NEWTABLES_MAX 256
+#endif
/*
* Description of dynamic rules.
*
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)
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,
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
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;
return (ENOMEM);
}
}
-#endif
return (0);
}
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;
*val = ent->value;
return (1);
}
-#endif
return (0);
}
+#endif
#ifdef radix
static int
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)
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 {
lookup_next_rule(f, 0);
f = f->next_rule;
}
+#endif
/*
* Skip disabled rules, and
* re-enter the inner loop
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;
* 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
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
#include <net/pfil.h>
#include <net/vnet.h>
+#include "missing.h"
+
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <machine/in_cksum.h>
-#include "missing.h"
-
-int fw_enable = 1;
+VNET_DEFINE(int, fw_enable) = 1;
#ifdef INET6
-int fw6_enable = 1;
+VNET_DEFINE(int, fw6_enable) = 1;
#endif
int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
args.m = *m0;
args.inp = inp;
ipfw = ipfw_chk(&args);
- *m0 = args.m; /* args.m can be modified by ipfw_chk */
+ *m0 = args.m;
tee = 0;
KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
goto drop;
break; /* not reached */
- /* here packets come after the ipfw classification */
case IP_FW_DUMMYNET:
if (ip_dn_io_ptr == NULL)
goto drop;
args.oif = ifp;
args.inp = inp;
ipfw = ipfw_chk(&args);
- *m0 = args.m; /* args.m can be modified by ipfw_chk */
+ *m0 = args.m;
tee = 0;
KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
return 1;
}
-static int
+int
ipfw_hook(void)
{
struct pfil_head *pfh_inet;
return 0;
}
-static int
+int
ipfw_unhook(void)
{
struct pfil_head *pfh_inet;
}
#ifdef INET6
-static int
+int
ipfw6_hook(void)
{
struct pfil_head *pfh_inet6;
return 0;
}
-static int
+int
ipfw6_unhook(void)
{
struct pfil_head *pfh_inet6;
#include <sys/mbuf.h> /* sizeof struct mbuf */
#include <sys/param.h> /* NGROUPS */
+#include "missing.h"
+
#ifdef __linux__
#include <linux/module.h>
#include <linux/kernel.h>
/*
* Here we allocate some global variables used in the firewall.
*/
-ip_dn_ctl_t *ip_dn_ctl_ptr;
+//ip_dn_ctl_t *ip_dn_ctl_ptr;
+int (*ip_dn_ctl_ptr)(struct sockopt *);
+
ip_fw_ctl_t *ip_fw_ctl_ptr;
-ip_dn_io_t *ip_dn_io_ptr;
+int (*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa);
ip_fw_chk_t *ip_fw_chk_ptr;
void (*bridge_dn_p)(struct mbuf *, struct ifnet *);
/*
* Kernel locking support.
- * FreeBSD uses mtx in dummynet.c, and rwlocks in ipfw.c
+ * FreeBSD uses mtx in dummynet.c and struct rwlock ip_fw2.c
*
* In linux we use spinlock_bh to implement both.
+ * For 'struct rwlock' we need an #ifdef to change it to spinlock_t
*/
#ifndef DEFINE_SPINLOCK /* this is for linux 2.4 */
/* end of locking support */
+/* in netinet/in.h */
+#define in_nullhost(x) ((x).s_addr == INADDR_ANY)
+
+/* bzero not present on linux, but this should go in glue.h */
+#define bzero(s, n) memset(s, 0, n)
+#define bcmp(p1, p2, n) memcmp(p1, p2, n)
+
/* ethernet stuff */
#define ETHERTYPE_IP 0x0800 /* IP protocol */
#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */
u_int32_t qid; /* queue id */
};
-/* radix related */
-
+#if 0 // ndef radix
+/* radix stuff in radix.h and radix.c */
struct radix_node {
caddr_t rn_key; /* object of search */
caddr_t rn_mask; /* netmask, if present */
};
+#endif /* !radix */
/* missing kernel functions */
char *inet_ntoa(struct in_addr ina);
struct sk_buff *skb, int dir, struct ip_fw_ugid *ugp);
/* vnet wrappers, in vnet.h and ip_var.h */
+int ipfw_init(void);
+void ipfw_destroy(void);
+struct ip_fw_args;
+extern int (*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa);
+
#define curvnet NULL
#define CURVNET_SET(_v)
#define CURVNET_RESTORE()
#define VNET_PTR(n) (&(n))
#define VNET(n) (n)
-VNET_DECLARE(struct ip_fw_chain, layer3_chain);
+extern int (*ip_dn_ctl_ptr)(struct sockopt *);
+typedef int ip_fw_ctl_t(struct sockopt *);
+extern ip_fw_ctl_t *ip_fw_ctl_ptr;
+
+/* For kernel ipfw_ether and ipfw_bridge. */
+struct ip_fw_args;
+typedef int ip_fw_chk_t(struct ip_fw_args *args);
+extern ip_fw_chk_t *ip_fw_chk_ptr;
-#define V_fw_enable VNET(fw_enable)
-#define V_fw_one_pass VNET(fw_one_pass)
#define V_ip_fw_chk_ptr VNET(ip_fw_chk_ptr)
#define V_ip_fw_ctl_ptr VNET(ip_fw_ctl_ptr)
-#define V_layer3_chain VNET(layer3_chain)
#define V_tcbinfo VNET(tcbinfo)
#define V_udbinfo VNET(udbinfo)
#include "missing.h"
-//#include <sys/param.h>
-//#include <sys/systm.h>
-//#include <sys/malloc.h>
-// #include <sys/mbuf.h>
-//#include <sys/kernel.h>
-//#include <sys/lock.h>
-//#include <sys/jail.h>
-//#include <sys/module.h>
-//#include <sys/priv.h>
-//#include <sys/proc.h>
-//#include <sys/socket.h>
-//#include <sys/socketvar.h>
-//#include <sys/sysctl.h>
-//#include <sys/syslog.h>
-//#include <sys/ucred.h>
-//#include <net/ethernet.h> /* for ETHERTYPE_IP */
-//#include <net/if.h>
-//#include <net/radix.h>
-//#include <net/route.h>
-//#include <net/pf_mtag.h>
#define IPFW_INTERNAL
#include <netinet/ip_fw.h>
MALLOC_DEFINE(M_IPFW_HTBL, "ipfw_tbl", "IpFw tables");
-static struct new_hash_table *global_tables[128];
int add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
uint8_t mlen, uint32_t value);
int new_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr);
int del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
uint8_t mlen);
-int new_flush_table(uint16_t tbl);
+int new_flush_table(struct ip_fw_chain *ch, uint16_t tbl);
int flush_table(struct ip_fw_chain *ch, uint16_t tbl);
int lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
uint32_t *val);
-int new_count_table_entry(uint32_t tbl, uint32_t *cnt);
+int new_count_table_entry(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
int count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
-int new_dump_table_entry(ipfw_table *tbl);
+int new_dump_table_entry(struct ip_fw_chain *ch, ipfw_table *tbl);
int dump_table(struct ip_fw_chain *ch, ipfw_table *tbl);
int init_tables(struct ip_fw_chain *ch);
printf("%s called\n", __FUNCTION__);
if (i < 0 || i > size-1) /* wrong table number */
return 1;
- if (global_tables[i] == NULL) {
+ if (ch->global_tables[i] == NULL) {
printf("Creating table n %d\n", tbl);
- global_tables[i] = new_table_init(size, obj_size,
+ ch->global_tables[i] = new_table_init(size, obj_size,
simple_hash32, cmp_func32, M_IPFW_HTBL);
}
obj.mask = mlen;
/* Insert the object in the table */
- ret = new_table_insert_obj(global_tables[i], &obj);
+ ret = new_table_insert_obj(ch->global_tables[i], &obj);
return ret;
}
printf("%s called\n", __FUNCTION__);
- ret = new_table_delete_obj(global_tables[nr], &addr);
+ ret = new_table_delete_obj(ch->global_tables[nr], &addr);
return ret;
}
}
int
-new_flush_table(uint16_t tbl)
+new_flush_table(struct ip_fw_chain *ch, uint16_t tbl)
{
printf("%s called\n", __FUNCTION__);
- new_table_destroy(global_tables[tbl - IPFW_TABLES_MAX]);
+ new_table_destroy(ch->global_tables[tbl - IPFW_TABLES_MAX]);
return 0;
}
{
printf("%s called\n", __FUNCTION__);
if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX)
- return new_flush_table(tbl);
+ return new_flush_table(ch, tbl);
return (EINVAL);
}
printf("%s called\n", __FUNCTION__);
if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) {
struct new_hash_table *h;
- struct t_o *obj;
+ const struct t_o *obj;
- h = global_tables[tbl - IPFW_NEWTABLES_MAX];
+ h = ch->global_tables[tbl - IPFW_TABLES_MAX];
printf("Search %d in table number %d\n", addr, tbl);
- obj = (struct t_o *)new_table_extract_obj(h, (void *)&addr);
+ obj = new_table_extract_obj(h, (void *)&addr);
if (obj == NULL)
- return 0;
+ return 0; /* no match */
*val = obj->value;
-
- return 1;
+ printf("obj->addr=%d,obj->value=%d\n",obj->addr, obj->value);
+ return 1; /* match */
}
-
- return 1;
+ return 0;
}
int
-new_count_table_entry(uint32_t tbl, uint32_t *cnt)
+new_count_table_entry(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt)
{
printf("%s called\n", __FUNCTION__);
- *cnt = new_table_get_element(global_tables[tbl - IPFW_TABLES_MAX]);
+ *cnt = new_table_get_element(ch->global_tables[tbl - IPFW_TABLES_MAX]);
return 0;
}
{
printf("%s called\n", __FUNCTION__);
if (tbl >= IPFW_TABLES_MAX && tbl < IPFW_NEWTABLES_MAX) {
- new_count_table_entry(tbl, cnt);
+ new_count_table_entry(ch, tbl, cnt);
return (0);
}
return (EINVAL);
}
int
-new_dump_table_entry(ipfw_table *tbl)
+new_dump_table_entry(struct ip_fw_chain *ch, ipfw_table *tbl)
{
/* fill the tbl with all entryes */
ipfw_table_entry *ent;
int i;
int n_el;
int nr = tbl->tbl - IPFW_TABLES_MAX;
- struct new_hash_table *t = global_tables[nr];
+ struct new_hash_table *t = ch->global_tables[nr];
printf("%s called\n", __FUNCTION__);
{
printf("%s called\n", __FUNCTION__);
if (tbl->tbl >= IPFW_TABLES_MAX && tbl->tbl < IPFW_NEWTABLES_MAX) {
- new_dump_table_entry(tbl);
+ new_dump_table_entry(ch, tbl);
return (0);
}
return (EINVAL);
printf("%s called\n", __FUNCTION__);
/* Initialize new tables XXXMPD */
for (i = 0; i < IPFW_NEWTABLES_MAX - IPFW_TABLES_MAX; i++) {
- memset(&global_tables[i], sizeof(struct new_hash_table*), 0);
+ memset(&ch->global_tables[i], sizeof(struct new_hash_table*), 0);
}
return (0);
--- /dev/null
+/*-
+ * Copyright (c) 1988, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)radix.c 8.5 (Berkeley) 5/19/95
+ * $FreeBSD: head/sys/net/radix.c 186176 2008-12-16 11:01:36Z kmacy $
+ */
+
+#include "missing.h"
+/*
+ * Routines to build and maintain radix trees for routing lookups.
+ */
+#ifndef _RADIX_H_
+#include <sys/param.h>
+#ifdef _KERNEL
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+// #include <sys/domain.h>
+#else
+#include <stdlib.h>
+#endif
+#include <sys/syslog.h>
+#include <net/radix.h>
+#endif
+
+// #include "opt_mpath.h"
+
+#ifdef RADIX_MPATH
+#include <net/radix_mpath.h>
+#endif
+
+
+static int rn_walktree_from(struct radix_node_head *h, void *a, void *m,
+ walktree_f_t *f, void *w);
+static int rn_walktree(struct radix_node_head *, walktree_f_t *, void *);
+static struct radix_node
+ *rn_insert(void *, struct radix_node_head *, int *,
+ struct radix_node [2]),
+ *rn_newpair(void *, int, struct radix_node[2]),
+ *rn_search(void *, struct radix_node *),
+ *rn_search_m(void *, struct radix_node *, void *);
+
+static int max_keylen;
+static struct radix_mask *rn_mkfreelist;
+static struct radix_node_head *mask_rnhead;
+/*
+ * Work area -- the following point to 3 buffers of size max_keylen,
+ * allocated in this order in a block of memory malloc'ed by rn_init.
+ */
+static char *rn_zeros, *rn_ones, *addmask_key;
+
+#define MKGet(m) { \
+ if (rn_mkfreelist) { \
+ m = rn_mkfreelist; \
+ rn_mkfreelist = (m)->rm_mklist; \
+ } else \
+ R_Malloc(m, struct radix_mask *, sizeof (struct radix_mask)); }
+
+#define MKFree(m) { (m)->rm_mklist = rn_mkfreelist; rn_mkfreelist = (m);}
+
+#define rn_masktop (mask_rnhead->rnh_treetop)
+
+static int rn_lexobetter(void *m_arg, void *n_arg);
+static struct radix_mask *
+ rn_new_radix_mask(struct radix_node *tt,
+ struct radix_mask *next);
+static int rn_satisfies_leaf(char *trial, struct radix_node *leaf,
+ int skip);
+
+/*
+ * The data structure for the keys is a radix tree with one way
+ * branching removed. The index rn_bit at an internal node n represents a bit
+ * position to be tested. The tree is arranged so that all descendants
+ * of a node n have keys whose bits all agree up to position rn_bit - 1.
+ * (We say the index of n is rn_bit.)
+ *
+ * There is at least one descendant which has a one bit at position rn_bit,
+ * and at least one with a zero there.
+ *
+ * A route is determined by a pair of key and mask. We require that the
+ * bit-wise logical and of the key and mask to be the key.
+ * We define the index of a route to associated with the mask to be
+ * the first bit number in the mask where 0 occurs (with bit number 0
+ * representing the highest order bit).
+ *
+ * We say a mask is normal if every bit is 0, past the index of the mask.
+ * If a node n has a descendant (k, m) with index(m) == index(n) == rn_bit,
+ * and m is a normal mask, then the route applies to every descendant of n.
+ * If the index(m) < rn_bit, this implies the trailing last few bits of k
+ * before bit b are all 0, (and hence consequently true of every descendant
+ * of n), so the route applies to all descendants of the node as well.
+ *
+ * Similar logic shows that a non-normal mask m such that
+ * index(m) <= index(n) could potentially apply to many children of n.
+ * Thus, for each non-host route, we attach its mask to a list at an internal
+ * node as high in the tree as we can go.
+ *
+ * The present version of the code makes use of normal routes in short-
+ * circuiting an explict mask and compare operation when testing whether
+ * a key satisfies a normal route, and also in remembering the unique leaf
+ * that governs a subtree.
+ */
+
+/*
+ * Most of the functions in this code assume that the key/mask arguments
+ * are sockaddr-like structures, where the first byte is an u_char
+ * indicating the size of the entire structure.
+ *
+ * To make the assumption more explicit, we use the LEN() macro to access
+ * this field. It is safe to pass an expression with side effects
+ * to LEN() as the argument is evaluated only once.
+ */
+#define LEN(x) (*(const u_char *)(x))
+
+/*
+ * XXX THIS NEEDS TO BE FIXED
+ * In the code, pointers to keys and masks are passed as either
+ * 'void *' (because callers use to pass pointers of various kinds), or
+ * 'caddr_t' (which is fine for pointer arithmetics, but not very
+ * clean when you dereference it to access data). Furthermore, caddr_t
+ * is really 'char *', while the natural type to operate on keys and
+ * masks would be 'u_char'. This mismatch require a lot of casts and
+ * intermediate variables to adapt types that clutter the code.
+ */
+
+/*
+ * Search a node in the tree matching the key.
+ */
+static struct radix_node *
+rn_search(v_arg, head)
+ void *v_arg;
+ struct radix_node *head;
+{
+ register struct radix_node *x;
+ register caddr_t v;
+
+ for (x = head, v = v_arg; x->rn_bit >= 0;) {
+ if (x->rn_bmask & v[x->rn_offset])
+ x = x->rn_right;
+ else
+ x = x->rn_left;
+ }
+ return (x);
+}
+
+/*
+ * Same as above, but with an additional mask.
+ * XXX note this function is used only once.
+ */
+static struct radix_node *
+rn_search_m(v_arg, head, m_arg)
+ struct radix_node *head;
+ void *v_arg, *m_arg;
+{
+ register struct radix_node *x;
+ register caddr_t v = v_arg, m = m_arg;
+
+ for (x = head; x->rn_bit >= 0;) {
+ if ((x->rn_bmask & m[x->rn_offset]) &&
+ (x->rn_bmask & v[x->rn_offset]))
+ x = x->rn_right;
+ else
+ x = x->rn_left;
+ }
+ return x;
+}
+
+int
+rn_refines(m_arg, n_arg)
+ void *m_arg, *n_arg;
+{
+ register caddr_t m = m_arg, n = n_arg;
+ register caddr_t lim, lim2 = lim = n + LEN(n);
+ int longer = LEN(n++) - (int)LEN(m++);
+ int masks_are_equal = 1;
+
+ if (longer > 0)
+ lim -= longer;
+ while (n < lim) {
+ if (*n & ~(*m))
+ return 0;
+ if (*n++ != *m++)
+ masks_are_equal = 0;
+ }
+ while (n < lim2)
+ if (*n++)
+ return 0;
+ if (masks_are_equal && (longer < 0))
+ for (lim2 = m - longer; m < lim2; )
+ if (*m++)
+ return 1;
+ return (!masks_are_equal);
+}
+
+struct radix_node *
+rn_lookup(v_arg, m_arg, head)
+ void *v_arg, *m_arg;
+ struct radix_node_head *head;
+{
+ register struct radix_node *x;
+ caddr_t netmask = 0;
+
+ if (m_arg) {
+ x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_offset);
+ if (x == 0)
+ return (0);
+ netmask = x->rn_key;
+ }
+ x = rn_match(v_arg, head);
+ if (x && netmask) {
+ while (x && x->rn_mask != netmask)
+ x = x->rn_dupedkey;
+ }
+ return x;
+}
+
+static int
+rn_satisfies_leaf(trial, leaf, skip)
+ char *trial;
+ register struct radix_node *leaf;
+ int skip;
+{
+ register char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask;
+ char *cplim;
+ int length = min(LEN(cp), LEN(cp2));
+
+ if (cp3 == 0)
+ cp3 = rn_ones;
+ else
+ length = min(length, (int)(*(u_char *)cp3));
+ cplim = cp + length; cp3 += skip; cp2 += skip;
+ for (cp += skip; cp < cplim; cp++, cp2++, cp3++)
+ if ((*cp ^ *cp2) & *cp3)
+ return 0;
+ return 1;
+}
+
+struct radix_node *
+rn_match(v_arg, head)
+ void *v_arg;
+ struct radix_node_head *head;
+{
+ caddr_t v = v_arg;
+ register struct radix_node *t = head->rnh_treetop, *x;
+ register caddr_t cp = v, cp2;
+ caddr_t cplim;
+ struct radix_node *saved_t, *top = t;
+ int off = t->rn_offset, vlen = LEN(cp), matched_off;
+ register int test, b, rn_bit;
+
+ /*
+ * Open code rn_search(v, top) to avoid overhead of extra
+ * subroutine call.
+ */
+ for (; t->rn_bit >= 0; ) {
+ if (t->rn_bmask & cp[t->rn_offset])
+ t = t->rn_right;
+ else
+ t = t->rn_left;
+ }
+ /*
+ * See if we match exactly as a host destination
+ * or at least learn how many bits match, for normal mask finesse.
+ *
+ * It doesn't hurt us to limit how many bytes to check
+ * to the length of the mask, since if it matches we had a genuine
+ * match and the leaf we have is the most specific one anyway;
+ * if it didn't match with a shorter length it would fail
+ * with a long one. This wins big for class B&C netmasks which
+ * are probably the most common case...
+ */
+ if (t->rn_mask)
+ vlen = *(u_char *)t->rn_mask;
+ cp += off; cp2 = t->rn_key + off; cplim = v + vlen;
+ for (; cp < cplim; cp++, cp2++)
+ if (*cp != *cp2)
+ goto on1;
+ /*
+ * This extra grot is in case we are explicitly asked
+ * to look up the default. Ugh!
+ *
+ * Never return the root node itself, it seems to cause a
+ * lot of confusion.
+ */
+ if (t->rn_flags & RNF_ROOT)
+ t = t->rn_dupedkey;
+ return t;
+on1:
+ test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */
+ for (b = 7; (test >>= 1) > 0;)
+ b--;
+ matched_off = cp - v;
+ b += matched_off << 3;
+ rn_bit = -1 - b;
+ /*
+ * If there is a host route in a duped-key chain, it will be first.
+ */
+ if ((saved_t = t)->rn_mask == 0)
+ t = t->rn_dupedkey;
+ for (; t; t = t->rn_dupedkey)
+ /*
+ * Even if we don't match exactly as a host,
+ * we may match if the leaf we wound up at is
+ * a route to a net.
+ */
+ if (t->rn_flags & RNF_NORMAL) {
+ if (rn_bit <= t->rn_bit)
+ return t;
+ } else if (rn_satisfies_leaf(v, t, matched_off))
+ return t;
+ t = saved_t;
+ /* start searching up the tree */
+ do {
+ register struct radix_mask *m;
+ t = t->rn_parent;
+ m = t->rn_mklist;
+ /*
+ * If non-contiguous masks ever become important
+ * we can restore the masking and open coding of
+ * the search and satisfaction test and put the
+ * calculation of "off" back before the "do".
+ */
+ while (m) {
+ if (m->rm_flags & RNF_NORMAL) {
+ if (rn_bit <= m->rm_bit)
+ return (m->rm_leaf);
+ } else {
+ off = min(t->rn_offset, matched_off);
+ x = rn_search_m(v, t, m->rm_mask);
+ while (x && x->rn_mask != m->rm_mask)
+ x = x->rn_dupedkey;
+ if (x && rn_satisfies_leaf(v, x, off))
+ return x;
+ }
+ m = m->rm_mklist;
+ }
+ } while (t != top);
+ return 0;
+}
+
+#ifdef RN_DEBUG
+int rn_nodenum;
+struct radix_node *rn_clist;
+int rn_saveinfo;
+int rn_debug = 1;
+#endif
+
+/*
+ * Whenever we add a new leaf to the tree, we also add a parent node,
+ * so we allocate them as an array of two elements: the first one must be
+ * the leaf (see RNTORT() in route.c), the second one is the parent.
+ * This routine initializes the relevant fields of the nodes, so that
+ * the leaf is the left child of the parent node, and both nodes have
+ * (almost) all all fields filled as appropriate.
+ * (XXX some fields are left unset, see the '#if 0' section).
+ * The function returns a pointer to the parent node.
+ */
+
+static struct radix_node *
+rn_newpair(v, b, nodes)
+ void *v;
+ int b;
+ struct radix_node nodes[2];
+{
+ register struct radix_node *tt = nodes, *t = tt + 1;
+ t->rn_bit = b;
+ t->rn_bmask = 0x80 >> (b & 7);
+ t->rn_left = tt;
+ t->rn_offset = b >> 3;
+
+#if 0 /* XXX perhaps we should fill these fields as well. */
+ t->rn_parent = t->rn_right = NULL;
+
+ tt->rn_mask = NULL;
+ tt->rn_dupedkey = NULL;
+ tt->rn_bmask = 0;
+#endif
+ tt->rn_bit = -1;
+ tt->rn_key = (caddr_t)v;
+ tt->rn_parent = t;
+ tt->rn_flags = t->rn_flags = RNF_ACTIVE;
+ tt->rn_mklist = t->rn_mklist = 0;
+#ifdef RN_DEBUG
+ tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
+ tt->rn_twin = t;
+ tt->rn_ybro = rn_clist;
+ rn_clist = tt;
+#endif
+ return t;
+}
+
+static struct radix_node *
+rn_insert(v_arg, head, dupentry, nodes)
+ void *v_arg;
+ struct radix_node_head *head;
+ int *dupentry;
+ struct radix_node nodes[2];
+{
+ caddr_t v = v_arg;
+ struct radix_node *top = head->rnh_treetop;
+ int head_off = top->rn_offset, vlen = (int)LEN(v);
+ register struct radix_node *t = rn_search(v_arg, top);
+ register caddr_t cp = v + head_off;
+ register int b;
+ struct radix_node *tt;
+ /*
+ * Find first bit at which v and t->rn_key differ
+ */
+ {
+ register caddr_t cp2 = t->rn_key + head_off;
+ register int cmp_res;
+ caddr_t cplim = v + vlen;
+
+ while (cp < cplim)
+ if (*cp2++ != *cp++)
+ goto on1;
+ *dupentry = 1;
+ return t;
+on1:
+ *dupentry = 0;
+ cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
+ for (b = (cp - v) << 3; cmp_res; b--)
+ cmp_res >>= 1;
+ }
+ {
+ register struct radix_node *p, *x = top;
+ cp = v;
+ do {
+ p = x;
+ if (cp[x->rn_offset] & x->rn_bmask)
+ x = x->rn_right;
+ else
+ x = x->rn_left;
+ } while (b > (unsigned) x->rn_bit);
+ /* x->rn_bit < b && x->rn_bit >= 0 */
+#ifdef RN_DEBUG
+ if (rn_debug)
+ log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p);
+#endif
+ t = rn_newpair(v_arg, b, nodes);
+ tt = t->rn_left;
+ if ((cp[p->rn_offset] & p->rn_bmask) == 0)
+ p->rn_left = t;
+ else
+ p->rn_right = t;
+ x->rn_parent = t;
+ t->rn_parent = p; /* frees x, p as temp vars below */
+ if ((cp[t->rn_offset] & t->rn_bmask) == 0) {
+ t->rn_right = x;
+ } else {
+ t->rn_right = tt;
+ t->rn_left = x;
+ }
+#ifdef RN_DEBUG
+ if (rn_debug)
+ log(LOG_DEBUG, "rn_insert: Coming Out:\n"), traverse(p);
+#endif
+ }
+ return (tt);
+}
+
+struct radix_node *
+rn_addmask(n_arg, search, skip)
+ int search, skip;
+ void *n_arg;
+{
+ caddr_t netmask = (caddr_t)n_arg;
+ register struct radix_node *x;
+ register caddr_t cp, cplim;
+ register int b = 0, mlen, j;
+ int maskduplicated, m0, isnormal;
+ struct radix_node *saved_x;
+ static int last_zeroed = 0;
+
+ if ((mlen = LEN(netmask)) > max_keylen)
+ mlen = max_keylen;
+ if (skip == 0)
+ skip = 1;
+ if (mlen <= skip)
+ return (mask_rnhead->rnh_nodes);
+ if (skip > 1)
+ bcopy(rn_ones + 1, addmask_key + 1, skip - 1);
+ if ((m0 = mlen) > skip)
+ bcopy(netmask + skip, addmask_key + skip, mlen - skip);
+ /*
+ * Trim trailing zeroes.
+ */
+ for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;)
+ cp--;
+ mlen = cp - addmask_key;
+ if (mlen <= skip) {
+ if (m0 >= last_zeroed)
+ last_zeroed = mlen;
+ return (mask_rnhead->rnh_nodes);
+ }
+ if (m0 < last_zeroed)
+ bzero(addmask_key + m0, last_zeroed - m0);
+ *addmask_key = last_zeroed = mlen;
+ x = rn_search(addmask_key, rn_masktop);
+ if (bcmp(addmask_key, x->rn_key, mlen) != 0)
+ x = 0;
+ if (x || search)
+ return (x);
+ R_Zalloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x));
+ if ((saved_x = x) == 0)
+ return (0);
+ netmask = cp = (caddr_t)(x + 2);
+ bcopy(addmask_key, cp, mlen);
+ x = rn_insert(cp, mask_rnhead, &maskduplicated, x);
+ if (maskduplicated) {
+ log(LOG_ERR, "rn_addmask: mask impossibly already in tree");
+ Free(saved_x);
+ return (x);
+ }
+ /*
+ * Calculate index of mask, and check for normalcy.
+ * First find the first byte with a 0 bit, then if there are
+ * more bits left (remember we already trimmed the trailing 0's),
+ * the pattern must be one of those in normal_chars[], or we have
+ * a non-contiguous mask.
+ */
+ cplim = netmask + mlen;
+ isnormal = 1;
+ for (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;)
+ cp++;
+ if (cp != cplim) {
+ static char normal_chars[] = {
+ 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
+
+ for (j = 0x80; (j & *cp) != 0; j >>= 1)
+ b++;
+ if (*cp != normal_chars[b] || cp != (cplim - 1))
+ isnormal = 0;
+ }
+ b += (cp - netmask) << 3;
+ x->rn_bit = -1 - b;
+ if (isnormal)
+ x->rn_flags |= RNF_NORMAL;
+ return (x);
+}
+
+static int /* XXX: arbitrary ordering for non-contiguous masks */
+rn_lexobetter(m_arg, n_arg)
+ void *m_arg, *n_arg;
+{
+ register u_char *mp = m_arg, *np = n_arg, *lim;
+
+ if (LEN(mp) > LEN(np))
+ return 1; /* not really, but need to check longer one first */
+ if (LEN(mp) == LEN(np))
+ for (lim = mp + LEN(mp); mp < lim;)
+ if (*mp++ > *np++)
+ return 1;
+ return 0;
+}
+
+static struct radix_mask *
+rn_new_radix_mask(tt, next)
+ register struct radix_node *tt;
+ register struct radix_mask *next;
+{
+ register struct radix_mask *m;
+
+ MKGet(m);
+ if (m == 0) {
+ log(LOG_ERR, "Mask for route not entered\n");
+ return (0);
+ }
+ bzero(m, sizeof *m);
+ m->rm_bit = tt->rn_bit;
+ m->rm_flags = tt->rn_flags;
+ if (tt->rn_flags & RNF_NORMAL)
+ m->rm_leaf = tt;
+ else
+ m->rm_mask = tt->rn_mask;
+ m->rm_mklist = next;
+ tt->rn_mklist = m;
+ return m;
+}
+
+struct radix_node *
+rn_addroute(v_arg, n_arg, head, treenodes)
+ void *v_arg, *n_arg;
+ struct radix_node_head *head;
+ struct radix_node treenodes[2];
+{
+ caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
+ register struct radix_node *t, *x = 0, *tt;
+ struct radix_node *saved_tt, *top = head->rnh_treetop;
+ short b = 0, b_leaf = 0;
+ int keyduplicated;
+ caddr_t mmask;
+ struct radix_mask *m, **mp;
+
+ /*
+ * In dealing with non-contiguous masks, there may be
+ * many different routes which have the same mask.
+ * We will find it useful to have a unique pointer to
+ * the mask to speed avoiding duplicate references at
+ * nodes and possibly save time in calculating indices.
+ */
+ if (netmask) {
+ if ((x = rn_addmask(netmask, 0, top->rn_offset)) == 0)
+ return (0);
+ b_leaf = x->rn_bit;
+ b = -1 - x->rn_bit;
+ netmask = x->rn_key;
+ }
+ /*
+ * Deal with duplicated keys: attach node to previous instance
+ */
+ saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
+ if (keyduplicated) {
+ for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) {
+#ifdef RADIX_MPATH
+ /* permit multipath, if enabled for the family */
+ if (rn_mpath_capable(head) && netmask == tt->rn_mask) {
+ /*
+ * go down to the end of multipaths, so that
+ * new entry goes into the end of rn_dupedkey
+ * chain.
+ */
+ do {
+ t = tt;
+ tt = tt->rn_dupedkey;
+ } while (tt && t->rn_mask == tt->rn_mask);
+ break;
+ }
+#endif
+ if (tt->rn_mask == netmask)
+ return (0);
+ if (netmask == 0 ||
+ (tt->rn_mask &&
+ ((b_leaf < tt->rn_bit) /* index(netmask) > node */
+ || rn_refines(netmask, tt->rn_mask)
+ || rn_lexobetter(netmask, tt->rn_mask))))
+ break;
+ }
+ /*
+ * If the mask is not duplicated, we wouldn't
+ * find it among possible duplicate key entries
+ * anyway, so the above test doesn't hurt.
+ *
+ * We sort the masks for a duplicated key the same way as
+ * in a masklist -- most specific to least specific.
+ * This may require the unfortunate nuisance of relocating
+ * the head of the list.
+ *
+ * We also reverse, or doubly link the list through the
+ * parent pointer.
+ */
+ if (tt == saved_tt) {
+ struct radix_node *xx = x;
+ /* link in at head of list */
+ (tt = treenodes)->rn_dupedkey = t;
+ tt->rn_flags = t->rn_flags;
+ tt->rn_parent = x = t->rn_parent;
+ t->rn_parent = tt; /* parent */
+ if (x->rn_left == t)
+ x->rn_left = tt;
+ else
+ x->rn_right = tt;
+ saved_tt = tt; x = xx;
+ } else {
+ (tt = treenodes)->rn_dupedkey = t->rn_dupedkey;
+ t->rn_dupedkey = tt;
+ tt->rn_parent = t; /* parent */
+ if (tt->rn_dupedkey) /* parent */
+ tt->rn_dupedkey->rn_parent = tt; /* parent */
+ }
+#ifdef RN_DEBUG
+ t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
+ tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
+#endif
+ tt->rn_key = (caddr_t) v;
+ tt->rn_bit = -1;
+ tt->rn_flags = RNF_ACTIVE;
+ }
+ /*
+ * Put mask in tree.
+ */
+ if (netmask) {
+ tt->rn_mask = netmask;
+ tt->rn_bit = x->rn_bit;
+ tt->rn_flags |= x->rn_flags & RNF_NORMAL;
+ }
+ t = saved_tt->rn_parent;
+ if (keyduplicated)
+ goto on2;
+ b_leaf = -1 - t->rn_bit;
+ if (t->rn_right == saved_tt)
+ x = t->rn_left;
+ else
+ x = t->rn_right;
+ /* Promote general routes from below */
+ if (x->rn_bit < 0) {
+ for (mp = &t->rn_mklist; x; x = x->rn_dupedkey)
+ if (x->rn_mask && (x->rn_bit >= b_leaf) && x->rn_mklist == 0) {
+ *mp = m = rn_new_radix_mask(x, 0);
+ if (m)
+ mp = &m->rm_mklist;
+ }
+ } else if (x->rn_mklist) {
+ /*
+ * Skip over masks whose index is > that of new node
+ */
+ for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
+ if (m->rm_bit >= b_leaf)
+ break;
+ t->rn_mklist = m; *mp = 0;
+ }
+on2:
+ /* Add new route to highest possible ancestor's list */
+ if ((netmask == 0) || (b > t->rn_bit ))
+ return tt; /* can't lift at all */
+ b_leaf = tt->rn_bit;
+ do {
+ x = t;
+ t = t->rn_parent;
+ } while (b <= t->rn_bit && x != top);
+ /*
+ * Search through routes associated with node to
+ * insert new route according to index.
+ * Need same criteria as when sorting dupedkeys to avoid
+ * double loop on deletion.
+ */
+ for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) {
+ if (m->rm_bit < b_leaf)
+ continue;
+ if (m->rm_bit > b_leaf)
+ break;
+ if (m->rm_flags & RNF_NORMAL) {
+ mmask = m->rm_leaf->rn_mask;
+ if (tt->rn_flags & RNF_NORMAL) {
+ log(LOG_ERR,
+ "Non-unique normal route, mask not entered\n");
+ return tt;
+ }
+ } else
+ mmask = m->rm_mask;
+ if (mmask == netmask) {
+ m->rm_refs++;
+ tt->rn_mklist = m;
+ return tt;
+ }
+ if (rn_refines(netmask, mmask)
+ || rn_lexobetter(netmask, mmask))
+ break;
+ }
+ *mp = rn_new_radix_mask(tt, *mp);
+ return tt;
+}
+
+struct radix_node *
+rn_delete(v_arg, netmask_arg, head)
+ void *v_arg, *netmask_arg;
+ struct radix_node_head *head;
+{
+ register struct radix_node *t, *p, *x, *tt;
+ struct radix_mask *m, *saved_m, **mp;
+ struct radix_node *dupedkey, *saved_tt, *top;
+ caddr_t v, netmask;
+ int b, head_off, vlen;
+
+ v = v_arg;
+ netmask = netmask_arg;
+ x = head->rnh_treetop;
+ tt = rn_search(v, x);
+ head_off = x->rn_offset;
+ vlen = LEN(v);
+ saved_tt = tt;
+ top = x;
+ if (tt == 0 ||
+ bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))
+ return (0);
+ /*
+ * Delete our route from mask lists.
+ */
+ if (netmask) {
+ if ((x = rn_addmask(netmask, 1, head_off)) == 0)
+ return (0);
+ netmask = x->rn_key;
+ while (tt->rn_mask != netmask)
+ if ((tt = tt->rn_dupedkey) == 0)
+ return (0);
+ }
+ if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0)
+ goto on1;
+ if (tt->rn_flags & RNF_NORMAL) {
+ if (m->rm_leaf != tt || m->rm_refs > 0) {
+ log(LOG_ERR, "rn_delete: inconsistent annotation\n");
+ return 0; /* dangling ref could cause disaster */
+ }
+ } else {
+ if (m->rm_mask != tt->rn_mask) {
+ log(LOG_ERR, "rn_delete: inconsistent annotation\n");
+ goto on1;
+ }
+ if (--m->rm_refs >= 0)
+ goto on1;
+ }
+ b = -1 - tt->rn_bit;
+ t = saved_tt->rn_parent;
+ if (b > t->rn_bit)
+ goto on1; /* Wasn't lifted at all */
+ do {
+ x = t;
+ t = t->rn_parent;
+ } while (b <= t->rn_bit && x != top);
+ for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
+ if (m == saved_m) {
+ *mp = m->rm_mklist;
+ MKFree(m);
+ break;
+ }
+ if (m == 0) {
+ log(LOG_ERR, "rn_delete: couldn't find our annotation\n");
+ if (tt->rn_flags & RNF_NORMAL)
+ return (0); /* Dangling ref to us */
+ }
+on1:
+ /*
+ * Eliminate us from tree
+ */
+ if (tt->rn_flags & RNF_ROOT)
+ return (0);
+#ifdef RN_DEBUG
+ /* Get us out of the creation list */
+ for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {}
+ if (t) t->rn_ybro = tt->rn_ybro;
+#endif
+ t = tt->rn_parent;
+ dupedkey = saved_tt->rn_dupedkey;
+ if (dupedkey) {
+ /*
+ * Here, tt is the deletion target and
+ * saved_tt is the head of the dupekey chain.
+ */
+ if (tt == saved_tt) {
+ /* remove from head of chain */
+ x = dupedkey; x->rn_parent = t;
+ if (t->rn_left == tt)
+ t->rn_left = x;
+ else
+ t->rn_right = x;
+ } else {
+ /* find node in front of tt on the chain */
+ for (x = p = saved_tt; p && p->rn_dupedkey != tt;)
+ p = p->rn_dupedkey;
+ if (p) {
+ p->rn_dupedkey = tt->rn_dupedkey;
+ if (tt->rn_dupedkey) /* parent */
+ tt->rn_dupedkey->rn_parent = p;
+ /* parent */
+ } else log(LOG_ERR, "rn_delete: couldn't find us\n");
+ }
+ t = tt + 1;
+ if (t->rn_flags & RNF_ACTIVE) {
+#ifndef RN_DEBUG
+ *++x = *t;
+ p = t->rn_parent;
+#else
+ b = t->rn_info;
+ *++x = *t;
+ t->rn_info = b;
+ p = t->rn_parent;
+#endif
+ if (p->rn_left == t)
+ p->rn_left = x;
+ else
+ p->rn_right = x;
+ x->rn_left->rn_parent = x;
+ x->rn_right->rn_parent = x;
+ }
+ goto out;
+ }
+ if (t->rn_left == tt)
+ x = t->rn_right;
+ else
+ x = t->rn_left;
+ p = t->rn_parent;
+ if (p->rn_right == t)
+ p->rn_right = x;
+ else
+ p->rn_left = x;
+ x->rn_parent = p;
+ /*
+ * Demote routes attached to us.
+ */
+ if (t->rn_mklist) {
+ if (x->rn_bit >= 0) {
+ for (mp = &x->rn_mklist; (m = *mp);)
+ mp = &m->rm_mklist;
+ *mp = t->rn_mklist;
+ } else {
+ /* If there are any key,mask pairs in a sibling
+ duped-key chain, some subset will appear sorted
+ in the same order attached to our mklist */
+ for (m = t->rn_mklist; m && x; x = x->rn_dupedkey)
+ if (m == x->rn_mklist) {
+ struct radix_mask *mm = m->rm_mklist;
+ x->rn_mklist = 0;
+ if (--(m->rm_refs) < 0)
+ MKFree(m);
+ m = mm;
+ }
+ if (m)
+ log(LOG_ERR,
+ "rn_delete: Orphaned Mask %p at %p\n",
+ (void *)m, (void *)x);
+ }
+ }
+ /*
+ * We may be holding an active internal node in the tree.
+ */
+ x = tt + 1;
+ if (t != x) {
+#ifndef RN_DEBUG
+ *t = *x;
+#else
+ b = t->rn_info;
+ *t = *x;
+ t->rn_info = b;
+#endif
+ t->rn_left->rn_parent = t;
+ t->rn_right->rn_parent = t;
+ p = x->rn_parent;
+ if (p->rn_left == x)
+ p->rn_left = t;
+ else
+ p->rn_right = t;
+ }
+out:
+ tt->rn_flags &= ~RNF_ACTIVE;
+ tt[1].rn_flags &= ~RNF_ACTIVE;
+ return (tt);
+}
+
+/*
+ * This is the same as rn_walktree() except for the parameters and the
+ * exit.
+ */
+static int
+rn_walktree_from(h, a, m, f, w)
+ struct radix_node_head *h;
+ void *a, *m;
+ walktree_f_t *f;
+ void *w;
+{
+ int error;
+ struct radix_node *base, *next;
+ u_char *xa = (u_char *)a;
+ u_char *xm = (u_char *)m;
+ register struct radix_node *rn, *last = 0 /* shut up gcc */;
+ int stopping = 0;
+ int lastb;
+
+ /*
+ * rn_search_m is sort-of-open-coded here. We cannot use the
+ * function because we need to keep track of the last node seen.
+ */
+ /* printf("about to search\n"); */
+ for (rn = h->rnh_treetop; rn->rn_bit >= 0; ) {
+ last = rn;
+ /* printf("rn_bit %d, rn_bmask %x, xm[rn_offset] %x\n",
+ rn->rn_bit, rn->rn_bmask, xm[rn->rn_offset]); */
+ if (!(rn->rn_bmask & xm[rn->rn_offset])) {
+ break;
+ }
+ if (rn->rn_bmask & xa[rn->rn_offset]) {
+ rn = rn->rn_right;
+ } else {
+ rn = rn->rn_left;
+ }
+ }
+ /* printf("done searching\n"); */
+
+ /*
+ * Two cases: either we stepped off the end of our mask,
+ * in which case last == rn, or we reached a leaf, in which
+ * case we want to start from the last node we looked at.
+ * Either way, last is the node we want to start from.
+ */
+ rn = last;
+ lastb = rn->rn_bit;
+
+ /* printf("rn %p, lastb %d\n", rn, lastb);*/
+
+ /*
+ * This gets complicated because we may delete the node
+ * while applying the function f to it, so we need to calculate
+ * the successor node in advance.
+ */
+ while (rn->rn_bit >= 0)
+ rn = rn->rn_left;
+
+ while (!stopping) {
+ /* printf("node %p (%d)\n", rn, rn->rn_bit); */
+ base = rn;
+ /* If at right child go back up, otherwise, go right */
+ while (rn->rn_parent->rn_right == rn
+ && !(rn->rn_flags & RNF_ROOT)) {
+ rn = rn->rn_parent;
+
+ /* if went up beyond last, stop */
+ if (rn->rn_bit <= lastb) {
+ stopping = 1;
+ /* printf("up too far\n"); */
+ /*
+ * XXX we should jump to the 'Process leaves'
+ * part, because the values of 'rn' and 'next'
+ * we compute will not be used. Not a big deal
+ * because this loop will terminate, but it is
+ * inefficient and hard to understand!
+ */
+ }
+ }
+
+ /*
+ * At the top of the tree, no need to traverse the right
+ * half, prevent the traversal of the entire tree in the
+ * case of default route.
+ */
+ if (rn->rn_parent->rn_flags & RNF_ROOT)
+ stopping = 1;
+
+ /* Find the next *leaf* since next node might vanish, too */
+ for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
+ rn = rn->rn_left;
+ next = rn;
+ /* Process leaves */
+ while ((rn = base) != 0) {
+ base = rn->rn_dupedkey;
+ /* printf("leaf %p\n", rn); */
+ if (!(rn->rn_flags & RNF_ROOT)
+ && (error = (*f)(rn, w)))
+ return (error);
+ }
+ rn = next;
+
+ if (rn->rn_flags & RNF_ROOT) {
+ /* printf("root, stopping"); */
+ stopping = 1;
+ }
+
+ }
+ return 0;
+}
+
+static int
+rn_walktree(h, f, w)
+ struct radix_node_head *h;
+ walktree_f_t *f;
+ void *w;
+{
+ int error;
+ struct radix_node *base, *next;
+ register struct radix_node *rn = h->rnh_treetop;
+ /*
+ * This gets complicated because we may delete the node
+ * while applying the function f to it, so we need to calculate
+ * the successor node in advance.
+ */
+
+ /* First time through node, go left */
+ while (rn->rn_bit >= 0)
+ rn = rn->rn_left;
+ for (;;) {
+ base = rn;
+ /* If at right child go back up, otherwise, go right */
+ while (rn->rn_parent->rn_right == rn
+ && (rn->rn_flags & RNF_ROOT) == 0)
+ rn = rn->rn_parent;
+ /* Find the next *leaf* since next node might vanish, too */
+ for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
+ rn = rn->rn_left;
+ next = rn;
+ /* Process leaves */
+ while ((rn = base)) {
+ base = rn->rn_dupedkey;
+ if (!(rn->rn_flags & RNF_ROOT)
+ && (error = (*f)(rn, w)))
+ return (error);
+ }
+ rn = next;
+ if (rn->rn_flags & RNF_ROOT)
+ return (0);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Allocate and initialize an empty tree. This has 3 nodes, which are
+ * part of the radix_node_head (in the order <left,root,right>) and are
+ * marked RNF_ROOT so they cannot be freed.
+ * The leaves have all-zero and all-one keys, with significant
+ * bits starting at 'off'.
+ * Return 1 on success, 0 on error.
+ */
+int
+rn_inithead(head, off)
+ void **head;
+ int off;
+{
+ register struct radix_node_head *rnh;
+ register struct radix_node *t, *tt, *ttt;
+ if (*head)
+ return (1);
+ R_Zalloc(rnh, struct radix_node_head *, sizeof (*rnh));
+ if (rnh == 0)
+ return (0);
+#ifdef _KERNEL
+ RADIX_NODE_HEAD_LOCK_INIT(rnh);
+#endif
+ *head = rnh;
+ t = rn_newpair(rn_zeros, off, rnh->rnh_nodes);
+ ttt = rnh->rnh_nodes + 2;
+ t->rn_right = ttt;
+ t->rn_parent = t;
+ tt = t->rn_left; /* ... which in turn is rnh->rnh_nodes */
+ tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;
+ tt->rn_bit = -1 - off;
+ *ttt = *tt;
+ ttt->rn_key = rn_ones;
+ rnh->rnh_addaddr = rn_addroute;
+ rnh->rnh_deladdr = rn_delete;
+ rnh->rnh_matchaddr = rn_match;
+ rnh->rnh_lookup = rn_lookup;
+ rnh->rnh_walktree = rn_walktree;
+ rnh->rnh_walktree_from = rn_walktree_from;
+ rnh->rnh_treetop = t;
+ return (1);
+}
+
+void
+rn_init()
+{
+ char *cp, *cplim;
+#ifdef _KERNEL
+ struct domain *dom;
+
+ for (dom = domains; dom; dom = dom->dom_next)
+ if (dom->dom_maxrtkey > max_keylen)
+ max_keylen = dom->dom_maxrtkey;
+#endif
+ if (max_keylen == 0) {
+ log(LOG_ERR,
+ "rn_init: radix functions require max_keylen be set\n");
+ return;
+ }
+ R_Malloc(rn_zeros, char *, 3 * max_keylen);
+ if (rn_zeros == NULL)
+ panic("rn_init");
+ bzero(rn_zeros, 3 * max_keylen);
+ rn_ones = cp = rn_zeros + max_keylen;
+ addmask_key = cplim = rn_ones + max_keylen;
+ while (cp < cplim)
+ *cp++ = -1;
+ if (rn_inithead((void **)(void *)&mask_rnhead, 0) == 0)
+ panic("rn_init 2");
+}
* SUCH DAMAGE.
*/
/*
- * $Id: glue.h 4363 2009-12-08 16:06:54Z marta $
+ * $Id: glue.h 4413 2009-12-10 08:57:02Z luigi $
*
* glue code to adapt the FreeBSD version to linux and windows,
* userland and kernel.
#define INET_ADDRSTRLEN 16
+#ifdef linux
+/* linux does not have sin_len in sockaddr */
+#define sin_len __pad[0]
+#endif /* linux */
+
/*
* List of values used for set/getsockopt options.
* The base value on FreeBSD is defined as a macro,
URL: %(echo %{url} | cut -d ' ' -f 2)
%description
-the frontent part of the ipfw planetlab package
+the frontend part of the ipfw planetlab package
%prep
%setup
rm -rf $RPM_BUILD_ROOT
%install
-install -D -m 755 slice/netconfig $RPM_BUILD_ROOT/sbin/netconfig
-install -D -m 755 slice/ipfw.8.gz $RPM_BUILD_ROOT/%{_mandir}/man8/ipfw.8.gz
+install -D -m 755 planetlab/netconfig $RPM_BUILD_ROOT/sbin/netconfig
+install -D -m 755 planetlab/ipfw.8.gz $RPM_BUILD_ROOT/%{_mandir}/man8/ipfw.8.gz
%clean
rm -rf $RPM_BUILD_ROOT
%install
install -D -m 755 dummynet/ipfw_mod.ko $RPM_BUILD_ROOT/lib/modules/%{kernel_id}/net/netfilter/ipfw_mod.ko
install -D -m 755 ipfw/ipfw $RPM_BUILD_ROOT/sbin/ipfw
-install -D -m 755 ipfw-cleanup $RPM_BUILD_ROOT/usr/bin/ipfw-cleanup
-install -D -m 755 ipfw.cron $RPM_BUILD_ROOT/%{_sysconfdir}/cron.d/ipfw.cron
+install -D -m 755 planetlab/ipfw-cleanup $RPM_BUILD_ROOT/usr/bin/ipfw-cleanup
+install -D -m 755 planetlab/ipfw.cron $RPM_BUILD_ROOT/%{_sysconfdir}/cron.d/ipfw.cron
%clean
rm -rf $RPM_BUILD_ROOT
# Do not set with = or := so we can inherit from the caller
$(warning Building userland ipfw for $(VER))
EXTRA_CFLAGS += -O1
-# comment this on planetlab
-#EXTRA_CFLAGS += -Wall -Werror
+EXTRA_CFLAGS += -Wall -Werror
EXTRA_CFLAGS += -include ../glue.h
EXTRA_CFLAGS += -I ./include
clean distclean:
-rm -f $(OBJS) ipfw
+ -rm -rf include/netinet/
#include <ctype.h>
#include <err.h>
+#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
{ NULL, 0 } /* terminator */
};
-/*
- * XXX to be updated to the new version,
- * without the global struct command_opts variable
- */
static int
-sort_q(void * to_be_done, const void *pa, const void *pb)
+sort_q(void *arg, const void *pa, const void *pb)
{
int rev = (co.do_sort < 0);
int field = rev ? -co.do_sort : co.do_sort;
*
*/
-/* XXX move to an array definition ? */
#define ED_MAX_LINE_LEN 256+ED_MAX_NAME_LEN
#define ED_TOK_SAMPLES "samples"
#define ED_TOK_LOSS "loss-level"
{ NULL, 0 } /* terminator */
};
+/* index of 'lookup ... ' keys in the kernel */
+static int lookup_key[] = {
+ TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT,
+ TOK_UID, TOK_GID, TOK_JAIL,
+ TOK_PROTO, TOK_MACTYPE, 0, };
+
static struct _s_x rule_options[] = {
{ "tagged", TOK_TAGGED },
{ "uid", TOK_UID },
{ "dst-ip6", TOK_DSTIP6},
{ "src-ipv6", TOK_SRCIP6},
{ "src-ip6", TOK_SRCIP6},
+ { "lookup", TOK_LOOKUP},
{ "//", TOK_COMMENT },
{ "not", TOK_NOT }, /* pseudo option */
int len = F_LEN((ipfw_insn *)cmd);
uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
+ if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) {
+ uint32_t d = a[1];
+ const char *arg = "<invalid>";
+
+ if (d < sizeof(lookup_key)/sizeof(lookup_key[0]))
+ arg = match_value(rule_options, lookup_key[d]);
+ printf("%s lookup %s %d,%d", cmd->o.len & F_NOT ? " not": "",
+ arg, cmd->o.arg1, a[0]);
+ return;
+ }
printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
/*
* In the kernel we assume AF_INET and use only
- * sin_port and sin_addr.
+ * sin_port and sin_addr. Remember to set sin_len as
+ * the routing code seems to use it too.
*/
p->sa.sin_family = AF_INET;
+ //p->sa.sin_len = sizeof(struct sockaddr_in);
p->sa.sin_port = 0;
/*
* locate the address-port separator (':' or ',')
if (have_tag)
errx(EX_USAGE, "tag and untag cannot be "
"specified more than once");
- GET_UINT_ARG(tag, 1, IPFW_DEFAULT_RULE - 1, i,
+ GET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX, i,
rule_action_params);
have_tag = cmd;
fill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, tag);
if (c->limit_mask == 0)
errx(EX_USAGE, "limit: missing limit mask");
- GET_UINT_ARG(c->conn_limit, 1, IPFW_DEFAULT_RULE - 1,
+ GET_UINT_ARG(c->conn_limit, IPFW_ARG_MIN, IPFW_ARG_MAX,
TOK_LIMIT, rule_options);
ac--; av++;
else {
uint16_t tag;
- GET_UINT_ARG(tag, 1, IPFW_DEFAULT_RULE - 1,
+ GET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX,
TOK_TAGGED, rule_options);
fill_cmd(cmd, O_TAGGED, 0, tag);
}
ac--; av++;
break;
+ case TOK_LOOKUP: {
+ ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd;
+ char *p;
+ int j;
+
+ if (ac < 2)
+ errx(EX_USAGE, "format: lookup argument tablenum[,arg]");
+ cmd->opcode = O_IP_DST_LOOKUP;
+ cmd->len |= F_INSN_SIZE(ipfw_insn) + 2;
+ i = match_token(rule_options, *av);
+ for (j = 0; lookup_key[j] ; j++) {
+ if (i == lookup_key[j])
+ break;
+ }
+ if (lookup_key[j] == 0)
+ errx(EX_USAGE, "format: cannot lookup on %s", *av);
+ c->d[1] = j; // i converted to option
+ ac--; av++;
+ p = strchr(*av, ',');
+ if (p) {
+ *p++ = '\0';
+ c->d[0] = strtoul(p, NULL, 0);
+ } else {
+ c->d[0] = ~0;
+ }
+ cmd->arg1 = strtoul(*av, NULL, 0);
+ ac--; av++;
+ }
+ break;
+
default:
errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
}
TOK_FIB,
TOK_SETFIB,
+ TOK_LOOKUP,
};
/*
* the following macro returns an error message if we run out of