summaryrefslogtreecommitdiffstats
path: root/lib/libalias
diff options
context:
space:
mode:
authorluigi <luigi@FreeBSD.org>2002-06-27 23:02:18 +0000
committerluigi <luigi@FreeBSD.org>2002-06-27 23:02:18 +0000
commita9ab854862b9e8f268eb8bbbac00742895dbb2c3 (patch)
tree53922ec5b28d758363c3c72bc71078ef26229c57 /lib/libalias
parent63fdb8e6ba59d01bbbb957a13d305d04a276e889 (diff)
downloadFreeBSD-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 'lib/libalias')
-rw-r--r--lib/libalias/alias_db.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/lib/libalias/alias_db.c b/lib/libalias/alias_db.c
index 52384b3..f5b0405 100644
--- a/lib/libalias/alias_db.c
+++ b/lib/libalias/alias_db.c
@@ -2641,6 +2641,82 @@ PacketAliasCheckNewLink(void)
#include <string.h>
#include <err.h>
+#define NEW_IPFW 1 /* use new ipfw code */
+#ifdef NEW_IPFW
+/*
+ * A function to fill simple commands of size 1.
+ * Existing flags are preserved.
+ */
+static void
+fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, u_int16_t arg)
+{
+ cmd->opcode = opcode;
+ cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1;
+ cmd->arg1 = arg;
+}
+
+/*
+ * helper function, updates the pointer to cmd with the length
+ * of the current command, and also cleans up the first word of
+ * the new command in case it has been clobbered before.
+ */
+static ipfw_insn *
+next_cmd(ipfw_insn *cmd)
+{
+ cmd += F_LEN(cmd);
+ bzero(cmd, sizeof(*cmd));
+ return cmd;
+}
+
+static void
+fill_ip(ipfw_insn_ip *cmd, enum ipfw_opcodes opcode, u_int32_t addr)
+{
+ cmd->o.opcode = opcode;
+ cmd->o.len = F_INSN_SIZE(ipfw_insn_u32);
+ cmd->addr.s_addr = addr;
+}
+
+static void
+fill_one_port(ipfw_insn_u16 *cmd, enum ipfw_opcodes opcode, u_int16_t port)
+{
+ cmd->o.opcode = opcode;
+ cmd->o.len = F_INSN_SIZE(ipfw_insn_u16);
+ cmd->ports[0] = cmd->ports[1] = port;
+}
+
+static int
+fill_rule(void *buf, int bufsize, int rulenum,
+ enum ipfw_opcodes action, int proto,
+ struct in_addr sa, u_int16_t sp, struct in_addr da, u_int32_t dp)
+{
+ struct ip_fw *rule = (struct ip_fw *)buf;
+ ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
+
+ bzero(buf, bufsize);
+ rule->rulenum = rulenum;
+
+ fill_cmd(cmd, O_PROTO, 0, proto);
+ cmd = next_cmd(cmd);
+
+ fill_ip((ipfw_insn_ip *)cmd, O_IP_SRC, sa.s_addr);
+ cmd = next_cmd(cmd);
+
+ fill_one_port((ipfw_insn_u16 *)cmd, O_IP_SRCPORT, sp);
+ cmd = next_cmd(cmd);
+
+ fill_ip((ipfw_insn_ip *)cmd, O_IP_DST, da.s_addr);
+ cmd = next_cmd(cmd);
+
+ fill_one_port((ipfw_insn_u16 *)cmd, O_IP_DSTPORT, dp);
+ cmd = next_cmd(cmd);
+
+ fill_cmd(cmd, O_ACCEPT, 0, 0);
+ cmd = next_cmd(cmd);
+
+ return ((void *)cmd - buf);
+}
+#endif /* NEW_IPFW */
+
static void ClearAllFWHoles(void);
static int fireWallBaseNum; /* The first firewall entry free for our use */
@@ -2724,6 +2800,35 @@ PunchFWHole(struct alias_link *link) {
/* Start next search at next position */
fireWallActiveNum = fwhole+1;
+#ifdef NEW_IPFW
+ if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) {
+ /*
+ * generate two rules of the form
+ *
+ * add fwhole accept tcp from OAddr OPort to DAddr DPort
+ * add fwhole accept tcp from DAddr DPort to OAddr OPort
+ */
+ u_int32_t rulebuf[255];
+ int i;
+
+ i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
+ O_ACCEPT, IPPROTO_TCP,
+ GetOriginalAddress(link), ntohs(GetOriginalPort(link)),
+ GetDestAddress(link), ntohs(GetDestPort(link)) );
+ r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
+ if (r)
+ err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
+
+ i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
+ O_ACCEPT, IPPROTO_TCP,
+ GetDestAddress(link), ntohs(GetDestPort(link)),
+ GetOriginalAddress(link), ntohs(GetOriginalPort(link)) );
+ r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
+ if (r)
+ err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
+ }
+#else /* !NEW_IPFW old code to generate ipfw rule */
+
/* Build generic part of the two rules */
rule.fw_number = fwhole;
IP_FW_SETNSRCP(&rule, 1); /* Number of source ports. */
@@ -2759,6 +2864,7 @@ PunchFWHole(struct alias_link *link) {
err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
#endif
}
+#endif /* !NEW_IPFW */
/* Indicate hole applied */
link->data.tcp->fwhole = fwhole;
fw_setfield(fireWallField, fwhole);
@@ -2770,6 +2876,10 @@ static void
ClearFWHole(struct alias_link *link) {
if (link->link_type == LINK_TCP) {
int fwhole = link->data.tcp->fwhole; /* Where is the firewall hole? */
+#ifdef NEW_IPFW
+ while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &fwhole, sizeof fwhole))
+ ;
+#else /* !NEW_IPFW */
struct ip_fw rule;
if (fwhole < 0)
@@ -2779,7 +2889,9 @@ ClearFWHole(struct alias_link *link) {
rule.fw_number = fwhole;
while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
;
+#endif /* !NEW_IPFW */
fw_clrfield(fireWallField, fwhole);
+
link->data.tcp->fwhole = -1;
}
}
@@ -2795,9 +2907,15 @@ ClearAllFWHoles(void) {
memset(&rule, 0, sizeof rule);
for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
+#ifdef NEW_IPFW
+ int r = i;
+ while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r))
+ ;
+#else /* !NEW_IPFW */
rule.fw_number = i;
while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
;
+#endif /* NEW_IPFW */
}
memset(fireWallField, 0, fireWallNumNums);
}
OpenPOWER on IntegriCloud