-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512
Ok, "allow-state"/"deny-state" was very limited idea. Here is more universal mechanism: new "keep-state-only" (aliased as "record-only") option, which works exactly as "keep-state" BUT cancel match of rule after state creation. It allows to write stateful + nat firewall as easy as: nat 1 config if outIface 1000 skipto 2000 in skipto 3000 out deny all from any to any // Safeguard 2000 skipto 4000 recv inIface skipto 6000 recv outIface deny all from any to any // Safeguard 3000 skipto 5000 xmit inIface skipto 7000 xmit outIface deny all from any to any // Safeguard 4000 // For sake of simplicity! // Real firewall will have some checks about local network here allow all from any to any deny all from any to any // Safeguard 5000 // For sake of simplicity! // Real firewall will have some checks about local network here allow all from any to any deny all from any to any // Safeguard 6000 deny all not dst-ip $EXT_IP nat 1 all from any to any // All enabled with "keep-state-only" at block 7000 before NAT check-state all from any to any // Here could be accept rules for our servers or servers in DMZ // Disable everything else deny all from any to any 7000 // Here goes rules which could DISABLE outbound external traffic // Create state for "check-state" at block 6000 and fallthrough allow keep-state-only allow src-ip $EXT_IP // Save NAT some work nat 1 all from any to any allow all from any to any deny all from any to any // Safeguard And variants with multiple NATs and "nat global" becomes as easy as this, too! No stupid "skipto", no "keep-state" at "incoming from local network" parts of firewall, nothing! P.S. I HATE this "all any to any" part! - -- // Lev Serebryakov -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (MingW32) iQJ8BAEBCgBmBQJU0POaXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25zLm9w ZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXRGOTZEMUNBMEI1RjQzMThCNjc0QjMzMEFF QUIwM0M1OEJGREM0NzhGAAoJEOqwPFi/3EePR+gP/1Oxi+h7pi0UlnqfrKyfHJRS FUbrMNeR9NATnTwxIK1UxNT1kF3m7wiwnFlgwW7rwLtTviFB1wK/pfd38l2h4t/w qUbtyK4PFMCq8I6wAJIB0qUl3C/mN1rwc+LSJJyFM07R52snoQs6FvkIYkCz0fOy Cak1f/P+scc21IRhFvYJXMMDO/1Y1nkxZk/HdHbn1GELpTXuHugvL1T9hHl98sqO HKlHnvtqAVlyZn9Sv3uC9nsyjFA2sdOCtb67UGnPDV3CIs4Jwj5CSst5jbz13qFG aXF8ZSm0coPJMUjH1PSogZM9Xiq23yZ47V0mesBxQsHL24548jM/wKcsR3buDjP7 NJ2rqo2OBCzTu6VCK2oIY5j9A6vq1mu8+/eBs5jF4C2k0xHiw53Okou7zOCA0gJ+ z+VGZvD3la/+tFjacty7Ra7LLNA8kNCnRa0QML7LOJ1/99a4l3Z/uGFxy5zYnk7d p27Y85CAhTJQjkYZSGAiFD5SE4XxRqtSJ9OL89w7vLxoHqW0rqwi+DVrr9uvXQZS 8Z5G5iQARG4ygXuKsl6MlwChCXa3ucbOs41lorrug94cuVCwGg859zBZY3dpQsKz XIhtVQS21wPLxXywzIc678ar4uKVWNiaRWg+k57O7375gAszvqujRuTEcfHRf/T+ gHJJZt8Tc+en4bw8XItY =wOAJ -----END PGP SIGNATURE-----
Index: sbin/ipfw/ipfw.8 =================================================================== --- sbin/ipfw/ipfw.8 (revision 278151) +++ sbin/ipfw/ipfw.8 (working copy) @@ -166,7 +166,8 @@ depending on how the kernel is configured. .Pp If the ruleset includes one or more rules with the -.Cm keep-state +.Cm keep-state , +.Cm keep-state-only or .Cm limit option, @@ -180,7 +181,8 @@ Dynamic rules, which have a limited lifetime, are checked at the first occurrence of a .Cm check-state , -.Cm keep-state +.Cm keep-state , +.Cm keep-state-only or .Cm limit rule, and are typically used to open the firewall on-demand to @@ -582,7 +584,8 @@ packet delivery. .Pp Note: this condition is checked before any other condition, including -ones such as keep-state or check-state which might have side effects. +ones such as keep-state, keep-stat-only or check-state which might have +side effects. .It Cm log Op Cm logamount Ar number Packets matching a rule with the .Cm log @@ -748,7 +751,8 @@ If no .Cm check-state rule is found, the dynamic ruleset is checked at the first -.Cm keep-state +.Cm keep-state , +.Cm keep-state-only , or .Cm limit rule. @@ -1583,6 +1587,14 @@ .Xr sysctl 8 variables), and the lifetime is refreshed every time a matching packet is found. +.It Cm keep-state-only | record-only +Upon a match, the firewall will create a dynamic rule as if +.Cm keep-state +was specified, but after that match is cancelled and the search +continues with the next rule. +On dynamic rule match action, specified in this rule, +performed as if rule contains +.Cm keep-state . .It Cm layer2 Matches only layer2 packets, i.e., those passed to .Nm Index: sbin/ipfw/ipfw2.c =================================================================== --- sbin/ipfw/ipfw2.c (revision 278151) +++ sbin/ipfw/ipfw2.c (working copy) @@ -292,6 +292,8 @@ { "in", TOK_IN }, { "limit", TOK_LIMIT }, { "keep-state", TOK_KEEPSTATE }, + { "record-state", TOK_STATE_ONLY }, + { "keep-state-only", TOK_STATE_ONLY }, { "bridged", TOK_LAYER2 }, { "layer2", TOK_LAYER2 }, { "out", TOK_OUT }, @@ -1993,6 +1995,10 @@ bprintf(bp, " keep-state"); break; + case O_STATE_ONLY: + bprintf(bp, " keep-state-only"); + break; + case O_LIMIT: { struct _s_x *p = limit_masks; ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; @@ -4335,14 +4341,16 @@ break; case TOK_KEEPSTATE: + case TOK_STATE_ONLY: if (open_par) - errx(EX_USAGE, "keep-state cannot be part " + errx(EX_USAGE, "keep-state or keep-state-only cannot be part " "of an or block"); if (have_state) errx(EX_USAGE, "only one of keep-state " "and limit is allowed"); have_state = cmd; - fill_cmd(cmd, O_KEEP_STATE, 0, 0); + fill_cmd(cmd, i == TOK_KEEPSTATE ? + O_KEEP_STATE : O_STATE_ONLY, 0, 0); break; case TOK_LIMIT: { @@ -4585,7 +4593,7 @@ dst = next_cmd(dst, &rblen); } - /* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */ + /* copy all commands but O_LOG, O_KEEP_STATE, O_STATE_ONLY, O_LIMIT, O_ALTQ, O_TAG */ for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { i = F_LEN(src); CHECK_RBUFLEN(i); @@ -4593,6 +4601,7 @@ switch (src->opcode) { case O_LOG: case O_KEEP_STATE: + case O_STATE_ONLY: case O_LIMIT: case O_ALTQ: case O_TAG: Index: sbin/ipfw/ipfw2.h =================================================================== --- sbin/ipfw/ipfw2.h (revision 278151) +++ sbin/ipfw/ipfw2.h (working copy) @@ -227,6 +227,7 @@ TOK_LOCK, TOK_UNLOCK, TOK_VLIST, + TOK_STATE_ONLY, }; /* Index: sys/netinet/ip_fw.h =================================================================== --- sys/netinet/ip_fw.h (revision 278151) +++ sys/netinet/ip_fw.h (working copy) @@ -252,6 +252,8 @@ O_DSCP, /* 2 u32 = DSCP mask */ O_SETDSCP, /* arg1=DSCP value */ O_IP_FLOW_LOOKUP, /* arg1=table number, u32=value */ + + O_STATE_ONLY, /* none */ O_LAST_OPCODE /* not an opcode! */ }; Index: sys/netpfil/ipfw/ip_fw2.c =================================================================== --- sys/netpfil/ipfw/ip_fw2.c (revision 278151) +++ sys/netpfil/ipfw/ip_fw2.c (working copy) @@ -2107,9 +2107,9 @@ * O_TAG, O_LOG and O_ALTQ action parameters: * perform some action and set match = 1; * - * O_LIMIT and O_KEEP_STATE: these opcodes are - * not real 'actions', and are stored right - * before the 'action' part of the rule. + * O_LIMIT, O_KEEP_STATE and O_STATE_ONLY: these + * opcodes are not real 'actions', and are stored + * right before the 'action' part of the rule. * These opcodes try to install an entry in the * state tables; if successful, we continue with * the next opcode (match=1; break;), otherwise @@ -2126,9 +2126,20 @@ * further instances of these opcodes become NOPs. * The jump to the next rule is done by setting * l=0, cmdlen=0. + * + * O_STATE_ONLY: this opcode is not real 'action' + * too, and is stored right before the 'action' + * part of the rule, right after O_KEEP_STATE + * opcode. It causes match failure so real + * 'action' could be executed only if rule + * is checked via dynamic rule from state + * table, as in such case execution starts + * from true 'action' opcode directly. + * */ case O_LIMIT: case O_KEEP_STATE: + case O_STATE_ONLY: if (ipfw_install_state(chain, f, (ipfw_insn_limit *)cmd, args, tablearg)) { /* error or limit violation */ @@ -2136,7 +2147,11 @@ l = 0; /* exit inner loop */ done = 1; /* exit outer loop */ } - match = 1; + if (cmd->opcode == O_STATE_ONLY) { + l = 0; /* exit inner loop */ + match = 0; + } else + match = 1; break; case O_PROBE_STATE: @@ -2188,6 +2203,7 @@ break; case O_ACCEPT: + retval = 0; /* accept */ l = 0; /* exit inner loop */ done = 1; /* exit outer loop */ @@ -2537,7 +2553,7 @@ done = 1; /* exit outer loop */ break; } - + default: panic("-- unknown opcode %d\n", cmd->opcode); } /* end of switch() on opcodes */ Index: sys/netpfil/ipfw/ip_fw_dynamic.c =================================================================== --- sys/netpfil/ipfw/ip_fw_dynamic.c (revision 278151) +++ sys/netpfil/ipfw/ip_fw_dynamic.c (working copy) @@ -708,6 +708,7 @@ switch (cmd->o.opcode) { case O_KEEP_STATE: /* bidir rule */ + case O_STATE_ONLY: q = add_dyn_rule(&args->f_id, i, O_KEEP_STATE, rule); break; @@ -1357,6 +1358,7 @@ switch (cmd->opcode) { case O_LIMIT: case O_KEEP_STATE: + case O_STATE_ONLY: case O_PROBE_STATE: case O_CHECK_STATE: return (1); Index: sys/netpfil/ipfw/ip_fw_sockopt.c =================================================================== --- sys/netpfil/ipfw/ip_fw_sockopt.c (revision 278151) +++ sys/netpfil/ipfw/ip_fw_sockopt.c (working copy) @@ -1433,6 +1433,7 @@ switch (cmd->opcode) { case O_PROBE_STATE: case O_KEEP_STATE: + case O_STATE_ONLY: case O_PROTO: case O_IP_SRC_ME: case O_IP_DST_ME:
ipfw-state-only.diff.sig
Description: Binary data
_______________________________________________ freebsd-ipfw@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-ipfw To unsubscribe, send any mail to "freebsd-ipfw-unsubscr...@freebsd.org"