diff options
author | luigi <luigi@FreeBSD.org> | 2002-06-27 23:02:18 +0000 |
---|---|---|
committer | luigi <luigi@FreeBSD.org> | 2002-06-27 23:02:18 +0000 |
commit | a9ab854862b9e8f268eb8bbbac00742895dbb2c3 (patch) | |
tree | 53922ec5b28d758363c3c72bc71078ef26229c57 /sys/netinet/ip_dummynet.c | |
parent | 63fdb8e6ba59d01bbbb957a13d305d04a276e889 (diff) | |
download | FreeBSD-src-a9ab854862b9e8f268eb8bbbac00742895dbb2c3.zip FreeBSD-src-a9ab854862b9e8f268eb8bbbac00742895dbb2c3.tar.gz |
The new ipfw code.
This code makes use of variable-size kernel representation of rules
(exactly the same concept of BPF instructions, as used in the BSDI's
firewall), which makes firewall operation a lot faster, and the
code more readable and easier to extend and debug.
The interface with the rest of the system is unchanged, as witnessed
by this commit. The only extra kernel files that I am touching
are if_fw.h and ip_dummynet.c, which is quite tied to ipfw. In
userland I only had to touch those programs which manipulate the
internal representation of firewall rules).
The code is almost entirely new (and I believe I have written the
vast majority of those sections which were taken from the former
ip_fw.c), so rather than modifying the old ip_fw.c I decided to
create a new file, sys/netinet/ip_fw2.c . Same for the user
interface, which is in sbin/ipfw/ipfw2.c (it still compiles to
/sbin/ipfw). The old files are still there, and will be removed
in due time.
I have not renamed the header file because it would have required
touching a one-line change to a number of kernel files.
In terms of user interface, the new "ipfw" is supposed to accepts
the old syntax for ipfw rules (and produce the same output with
"ipfw show". Only a couple of the old options (out of some 30 of
them) has not been implemented, but they will be soon.
On the other hand, the new code has some very powerful extensions.
First, you can put "or" connectives between match fields (and soon
also between options), and write things like
ipfw add allow ip from { 1.2.3.4/27 or 5.6.7.8/30 } 10-23,25,1024-3000 to any
This should make rulesets slightly more compact (and lines longer!),
by condensing 2 or more of the old rules into single ones.
Also, as an example of how easy the rules can be extended, I have
implemented an 'address set' match pattern, where you can specify
an IP address in a format like this:
10.20.30.0/26{18,44,33,22,9}
which will match the set of hosts listed in braces belonging to the
subnet 10.20.30.0/26 . The match is done using a bitmap, so it is
essentially a constant time operation requiring a handful of CPU
instructions (and a very small amount of memmory -- for a full /24
subnet, the instruction only consumes 40 bytes).
Again, in this commit I have focused on functionality and tried
to minimize changes to the other parts of the system. Some performance
improvement can be achieved with minor changes to the interface of
ip_fw_chk_t. This will be done later when this code is settled.
The code is meant to compile unmodified on RELENG_4 (once the
PACKET_TAG_* changes have been merged), for this reason
you will see #ifdef __FreeBSD_version in a couple of places.
This should minimize errors when (hopefully soon) it will be time
to do the MFC.
Diffstat (limited to 'sys/netinet/ip_dummynet.c')
-rw-r--r-- | sys/netinet/ip_dummynet.c | 56 |
1 files changed, 26 insertions, 30 deletions
diff --git a/sys/netinet/ip_dummynet.c b/sys/netinet/ip_dummynet.c index 6006b65..7f8b241 100644 --- a/sys/netinet/ip_dummynet.c +++ b/sys/netinet/ip_dummynet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2001 Luigi Rizzo, Universita` di Pisa + * Copyright (c) 1998-2002 Luigi Rizzo, Universita` di Pisa * Portions Copyright (c) 2000 Akamba Corp. * All rights reserved * @@ -61,7 +61,6 @@ #include <sys/systm.h> #include <sys/malloc.h> #include <sys/mbuf.h> -#include <sys/queue.h> /* XXX */ #include <sys/kernel.h> #include <sys/module.h> #include <sys/proc.h> @@ -166,12 +165,6 @@ static void dn_rule_delete(void *); int if_tx_rdy(struct ifnet *ifp); -/* - * ip_fw_chain_head is used when deleting a pipe, because ipfw rules can - * hold references to the pipe. - */ -extern LIST_HEAD (ip_fw_head, ip_fw) ip_fw_chain_head; - static void rt_unref(struct rtentry *rt) { @@ -1023,9 +1016,13 @@ static __inline struct dn_flow_set * locate_flowset(int pipe_nr, struct ip_fw *rule) { - struct dn_flow_set *fs = NULL ; + ipfw_insn_pipe *cmd = (ipfw_insn_pipe *)(rule->cmd + rule->act_ofs); + struct dn_flow_set *fs = (struct dn_flow_set *)(cmd->pipe_ptr); - if ( (rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_QUEUE ) + if (fs != NULL) + return fs; + + if ( cmd->o.opcode == O_QUEUE ) for (fs=all_flow_sets; fs && fs->fs_nr != pipe_nr; fs=fs->next) ; else { @@ -1035,8 +1032,7 @@ locate_flowset(int pipe_nr, struct ip_fw *rule) if (p1 != NULL) fs = &(p1->fs) ; } - if (fs != NULL) - rule->pipe_ptr = fs ; /* record for the future */ + (struct dn_flow_set *)(cmd->pipe_ptr) = fs; /* record for the future */ return fs ; } @@ -1065,16 +1061,18 @@ dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa) u_int64_t len = m->m_pkthdr.len ; struct dn_flow_queue *q = NULL ; int s ; + int action = fwa->rule->cmd[fwa->rule->act_ofs].opcode; s = splimp(); pipe_nr &= 0xffff ; - if ( (fs = fwa->rule->pipe_ptr) == NULL ) { - fs = locate_flowset(pipe_nr, fwa->rule); - if (fs == NULL) - goto dropit ; /* this queue/pipe does not exist! */ - } + /* + * this is a dummynet rule, so we expect a O_PIPE or O_QUEUE rule + */ + fs = locate_flowset(pipe_nr, fwa->rule); + if (fs == NULL) + goto dropit ; /* this queue/pipe does not exist! */ pipe = fs->pipe ; if (pipe == NULL) { /* must be a queue, try find a matching pipe */ for (pipe = all_pipes; pipe && pipe->pipe_nr != fs->parent_nr; @@ -1152,7 +1150,7 @@ dummynet_io(struct mbuf *m, int pipe_nr, int dir, struct ip_fw_args *fwa) * to schedule it. This involves different actions for fixed-rate or * WF2Q queues. */ - if ( (fwa->rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_PIPE ) { + if ( action == O_PIPE ) { /* * Fixed-rate queue: just insert into the ready_heap. */ @@ -1302,15 +1300,13 @@ static void dummynet_flush() { struct dn_pipe *curr_p, *p ; - struct ip_fw *rule ; struct dn_flow_set *fs, *curr_fs; int s ; s = splimp() ; /* remove all references to pipes ...*/ - LIST_FOREACH(rule, &ip_fw_chain_head, next) - rule->pipe_ptr = NULL ; + flush_pipe_ptrs(NULL); /* prevent future matches... */ p = all_pipes ; all_pipes = NULL ; @@ -1375,8 +1371,8 @@ dn_rule_delete(void *r) fs = &(p->fs) ; dn_rule_delete_fs(fs, r); for (pkt = p->head ; pkt ; pkt = DN_NEXT(pkt) ) - if (pkt->rule == r) - pkt->rule = ip_fw_default_rule ; + if (pkt->hdr.mh_data == r) + pkt->hdr.mh_data = (void *)ip_fw_default_rule ; } } @@ -1663,7 +1659,6 @@ static int delete_pipe(struct dn_pipe *p) { int s ; - struct ip_fw *rule ; if (p->pipe_nr == 0 && p->fs.fs_nr == 0) return EINVAL ; @@ -1687,9 +1682,7 @@ delete_pipe(struct dn_pipe *p) else a->next = b->next ; /* remove references to this pipe from the ip_fw rules. */ - LIST_FOREACH(rule, &ip_fw_chain_head, next) - if (rule->pipe_ptr == &(b->fs)) - rule->pipe_ptr = NULL ; + flush_pipe_ptrs(&(b->fs)); /* remove all references to this pipe from flow_sets */ for (fs = all_flow_sets; fs; fs= fs->next ) @@ -1721,9 +1714,7 @@ delete_pipe(struct dn_pipe *p) else a->next = b->next ; /* remove references to this flow_set from the ip_fw rules. */ - LIST_FOREACH(rule, &ip_fw_chain_head, next) - if (rule->pipe_ptr == b) - rule->pipe_ptr = NULL ; + flush_pipe_ptrs(b); if (b->pipe != NULL) { /* Update total weight on parent pipe and cleanup parent heaps */ @@ -1847,9 +1838,14 @@ ip_dn_ctl(struct sockopt *sopt) /* Disallow sets in really-really secure mode. */ if (sopt->sopt_dir == SOPT_SET) { +#if __FreeBSD_version >= 500034 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); if (error) return (error); +#else + if (securelevel >= 3) + return (EPERM); +#endif } switch (sopt->sopt_name) { |