Page MenuHomeFreeBSD

D1776.id42881.diff
No OneTemporary

D1776.id42881.diff

Index: sbin/ipfw/ipfw.8
===================================================================
--- sbin/ipfw/ipfw.8
+++ sbin/ipfw/ipfw.8
@@ -212,9 +212,11 @@
depending on how the kernel is configured.
.Pp
If the ruleset includes one or more rules with the
-.Cm keep-state
-or
+.Cm keep-state ,
+.Cm record-state ,
.Cm limit
+or
+.Cm set-limit
option,
the firewall will have a
.Em stateful
@@ -231,6 +233,18 @@
.Cm limit
rule, and are typically used to open the firewall on-demand to
legitimate traffic only.
+Please, note, that
+.Cm keep-state
+amd
+.Cm limit
+imply implicit
+.Cm check-state
+for all packets (not only these matched by the rule) but
+.Cm record-state
+and
+.Cm set-limit
+have no implicit
+.Cm check-state .
See the
.Sx STATEFUL FIREWALL
and
@@ -628,7 +642,12 @@
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
+.Cm keep-state
+or
+.Cm check-state
+which might have
+side effects.
.It Cm log Op Cm logamount Ar number
Packets matching a rule with the
.Cm log
@@ -1462,6 +1481,21 @@
.It Cm bridged
Alias for
.Cm layer2 .
+.It Cm defer-immediate-action | defer-action
+A rule with this option will not perform normal action
+upon a match. This option is intended to be used with
+.Cm record-state
+or
+.Cm keep-state
+as the dynamic rule, created but ignored on match, will work
+as intended.
+Rules with both
+.Cm record-state
+and
+.Cm defer-immediate-action
+create a dynamic rule and continue with the next rule without actually
+performing the action part of this rule. When the rule is later activated
+via the state table, the action is performed as usual.
.It Cm diverted
Matches only packets generated by a divert socket.
.It Cm diverted-loopback
@@ -1780,6 +1814,14 @@
option is used, in which case symbolic resolution will be attempted).
.It Cm proto Ar protocol
Matches packets with the corresponding IP protocol.
+.It Cm record-state
+Upon a match, the firewall will create a dynamic rule as if
+.Cm keep-state
+was specified.
+However, this option doesn't imply an implicit
+.Cm check-state
+in contrast to
+.Cm keep-state .
.It Cm recv | xmit | via Brq Ar ifX | Ar if Ns Cm * | Ar table Ns Po Ar name Ns Oo , Ns Ar value Oc Pc | Ar ipno | Ar any
Matches packets received, transmitted or going through,
respectively, the interface specified by exact name
@@ -1828,6 +1870,12 @@
originating from the local host have no receive interface,
while packets destined for the local host have no transmit
interface.
+.It Cm set-limit Bro Cm src-addr | src-port | dst-addr | dst-port Brc Ar N
+Works like
+.Cm limit
+but does not have an implicit
+.Cm check-state
+attached to it.
.It Cm setup
Matches TCP packets that have the SYN bit set but no ACK bit.
This is the short form of
@@ -2284,16 +2332,18 @@
match a given pattern are detected.
Support for stateful
operation comes through the
-.Cm check-state , keep-state
+.Cm check-state , keep-state , record-state , limit
and
-.Cm limit
+.Cm set-limit
options of
.Nm rules .
.Pp
Dynamic rules are created when a packet matches a
-.Cm keep-state
-or
+.Cm keep-state ,
+.Cm record-state ,
.Cm limit
+or
+.Cm set-limit
rule, causing the creation of a
.Em dynamic
rule which will match all and only packets with
@@ -3665,6 +3715,15 @@
ruleset to minimize the amount of work scanning the ruleset.
Your mileage may vary.
.Pp
+For more complex scenarios with dynamic rules
+.Cm record-state
+and
+.Cm defer-action
+can be used to precisely control creation and checking of dynamic rules.
+Example of usage of these options are provided in
+.Sx NETWORK ADDRESS TRANSLATION (NAT)
+Section.
+.Pp
To limit the number of connections a user can open
you can use the following type of rules:
.Pp
@@ -3931,6 +3990,40 @@
.Dl " 10.0.0.100"
.Dl "ipfw nat 5 config redirect_port tcp"
.Dl " 192.168.0.1:80,192.168.0.10:22,192.168.0.20:25 500"
+.Pp
+Sometimes you may want to mix NAT and dynamic rules. It could be achived with
+.Cm record-state
+and
+.Cm defer-action
+options. Problem is, you need to create dynamic rule before NAT and check it
+after NAT actions (or vice versa) to have consistent addresses and ports.
+Rule with
+.Cm keep-state
+option will trigger activation of existing dynamic state, and action of such
+rule will be performed as soon as rule is matched. In case of NAT and
+.Cm allow
+rule packet need to be passed to NAT, not allowed as soon is possible.
+.Pp
+There is example of set of rules to achive this. Bear in mind that this
+is exmaple only and it is not very usefult by itself.
+.Pp
+On way out, after all checks place this rules:
+.Pp
+.Dl "ipfw add allow record-state skip-action"
+.Dl "ipfw add nat 1"
+.Pp
+And on way in there should be something like this:
+.Pp
+.Dl "ipfw add nat 1"
+.Dl "ipfw add check-state"
+.Pp
+Please note, that first rule on way out doesn't allow packet and doesn't
+execute existing dynamic rules. All it does, create new dynamic rule with
+.Cm allow
+action, if it is not created yet. Later, this dynamic rule is used on way
+in by
+.Cm check-state
+rule.
.Sh SEE ALSO
.Xr cpp 1 ,
.Xr m4 1 ,
Index: sbin/ipfw/ipfw2.h
===================================================================
--- sbin/ipfw/ipfw2.h
+++ sbin/ipfw/ipfw2.h
@@ -124,7 +124,9 @@
TOK_JAIL,
TOK_IN,
TOK_LIMIT,
+ TOK_SETLIMIT,
TOK_KEEPSTATE,
+ TOK_RECORDSTATE,
TOK_LAYER2,
TOK_OUT,
TOK_DIVERTED,
@@ -294,6 +296,8 @@
TOK_PREFIXLEN,
TOK_TCPSETMSS,
+
+ TOK_SKIPACTION,
};
/*
Index: sbin/ipfw/ipfw2.c
===================================================================
--- sbin/ipfw/ipfw2.c
+++ sbin/ipfw/ipfw2.c
@@ -304,7 +304,9 @@
{ "jail", TOK_JAIL },
{ "in", TOK_IN },
{ "limit", TOK_LIMIT },
+ { "set-limit", TOK_SETLIMIT },
{ "keep-state", TOK_KEEPSTATE },
+ { "record-state", TOK_RECORDSTATE },
{ "bridged", TOK_LAYER2 },
{ "layer2", TOK_LAYER2 },
{ "out", TOK_OUT },
@@ -367,6 +369,8 @@
{ "src-ip6", TOK_SRCIP6},
{ "lookup", TOK_LOOKUP},
{ "flow", TOK_FLOW},
+ { "defer-action", TOK_SKIPACTION },
+ { "defer-immediate-action", TOK_SKIPACTION },
{ "//", TOK_COMMENT },
{ "not", TOK_NOT }, /* pseudo option */
@@ -1370,9 +1374,10 @@
const ipfw_insn *eaction;
uint8_t *printed;
int flags;
-#define HAVE_PROTO 0x0001
-#define HAVE_SRCIP 0x0002
-#define HAVE_DSTIP 0x0004
+#define HAVE_PROTO 0x0001
+#define HAVE_SRCIP 0x0002
+#define HAVE_DSTIP 0x0004
+#define HAVE_PROBE_STATE 0x0008
int proto;
int or_block;
};
@@ -1414,13 +1419,12 @@
}
static void
-print_limit(struct buf_pr *bp, const ipfw_insn_limit *limit)
+print_limit_mask(struct buf_pr *bp, const ipfw_insn_limit *limit)
{
struct _s_x *p = limit_masks;
char const *comma = " ";
uint8_t x;
- bprintf(bp, " limit");
for (x = limit->limit_mask; p->x != 0; p++) {
if ((x & p->x) == p->x) {
x &= ~p->x;
@@ -1454,6 +1458,7 @@
bprintf(bp, "prob %f ", d);
break;
case O_PROBE_STATE: /* no need to print anything here */
+ state->flags |= HAVE_PROBE_STATE;
break;
case O_IP_SRC:
case O_IP_SRC_LOOKUP:
@@ -1660,13 +1665,20 @@
bprintf(bp, " // %s", (char *)(cmd + 1));
break;
case O_KEEP_STATE:
- bprintf(bp, " keep-state");
+ if (state->flags & HAVE_PROBE_STATE)
+ bprintf(bp, " keep-state");
+ else
+ bprintf(bp, " record-state");
bprintf(bp, " :%s",
object_search_ctlv(fo->tstate, cmd->arg1,
IPFW_TLV_STATE_NAME));
break;
case O_LIMIT:
- print_limit(bp, insntod(cmd, limit));
+ if (state->flags & HAVE_PROBE_STATE)
+ bprintf(bp, " limit");
+ else
+ bprintf(bp, " set-limit");
+ print_limit_mask(bp, insntod(cmd, limit));
bprintf(bp, " :%s",
object_search_ctlv(fo->tstate, cmd->arg1,
IPFW_TLV_STATE_NAME));
@@ -1690,6 +1702,9 @@
print_newports(bp, insntod(cmd, u16),
0, O_TAGGED);
break;
+ case O_SKIP_ACTION:
+ bprintf(bp, " defer-immediate-action");
+ break;
default:
bprintf(bp, " [opcode %d len %d]", cmd->opcode,
cmd->len);
@@ -3705,8 +3720,10 @@
/*
* various flags used to record that we entered some fields.
*/
- ipfw_insn *have_state = NULL; /* check-state or keep-state */
+ ipfw_insn *have_state = NULL; /* any state-related option */
+ int have_rstate = 0;
ipfw_insn *have_log = NULL, *have_altq = NULL, *have_tag = NULL;
+ ipfw_insn *have_skipcmd = NULL;
size_t len;
int i;
@@ -4647,15 +4664,16 @@
av++;
break;
- case TOK_KEEPSTATE: {
+ case TOK_KEEPSTATE:
+ case TOK_RECORDSTATE: {
uint16_t uidx;
if (open_par)
- errx(EX_USAGE, "keep-state cannot be part "
+ errx(EX_USAGE, "keep-state or record-state cannot be part "
"of an or block");
if (have_state)
- errx(EX_USAGE, "only one of keep-state "
- "and limit is allowed");
+ errx(EX_USAGE, "only one of keep-state, record-state, "
+ " limit and set-limit is allowed");
if (*av != NULL && *av[0] == ':') {
if (state_check_name(*av + 1) != 0)
errx(EX_DATAERR,
@@ -4667,21 +4685,24 @@
uidx = pack_object(tstate, default_state_name,
IPFW_TLV_STATE_NAME);
have_state = cmd;
+ have_rstate = i == TOK_RECORDSTATE;
fill_cmd(cmd, O_KEEP_STATE, 0, uidx);
break;
}
- case TOK_LIMIT: {
+ case TOK_LIMIT:
+ case TOK_SETLIMIT: {
ipfw_insn_limit *c = (ipfw_insn_limit *)cmd;
int val;
if (open_par)
errx(EX_USAGE,
- "limit cannot be part of an or block");
+ "limit or set-limit cannot be part of an or block");
if (have_state)
- errx(EX_USAGE, "only one of keep-state and "
- "limit is allowed");
+ errx(EX_USAGE, "only one of keep-state, record-state, "
+ " limit and set-limit is allowed");
have_state = cmd;
+ have_rstate = i == TOK_SETLIMIT;
cmd->len = F_INSN_SIZE(ipfw_insn_limit);
CHECK_CMDLEN;
@@ -4884,6 +4905,14 @@
av++;
break;
+ case TOK_SKIPACTION:
+ if (have_skipcmd)
+ errx(EX_USAGE, "only one defer-action "
+ "is allowed");
+ have_skipcmd = cmd;
+ fill_cmd(cmd, O_SKIP_ACTION, 0, 0);
+ break;
+
default:
errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
}
@@ -4894,6 +4923,11 @@
}
done:
+
+ if (!have_state && have_skipcmd)
+ warnx("Rule contains \"defer-immediate-action\" "
+ "and doesn't contain any state-related options.");
+
/*
* Now copy stuff into the rule.
* If we have a keep-state option, the first instruction
@@ -4916,12 +4950,15 @@
/*
* generate O_PROBE_STATE if necessary
*/
- if (have_state && have_state->opcode != O_CHECK_STATE) {
+ if (have_state && have_state->opcode != O_CHECK_STATE && !have_rstate) {
fill_cmd(dst, O_PROBE_STATE, 0, have_state->arg1);
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_LIMIT, O_ALTQ, O_TAG,
+ * O_SKIP_ACTION
+ */
for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
i = F_LEN(src);
CHECK_RBUFLEN(i);
@@ -4932,6 +4969,7 @@
case O_LIMIT:
case O_ALTQ:
case O_TAG:
+ case O_SKIP_ACTION:
break;
default:
bcopy(src, dst, i * sizeof(uint32_t));
@@ -4948,6 +4986,17 @@
bcopy(have_state, dst, i * sizeof(uint32_t));
dst += i;
}
+
+ /*
+ * put back the have_skipcmd command as very last opcode
+ */
+ if (have_skipcmd) {
+ i = F_LEN(have_skipcmd);
+ CHECK_RBUFLEN(i);
+ bcopy(have_skipcmd, dst, i * sizeof(uint32_t));
+ dst += i;
+ }
+
/*
* start action section
*/
Index: sys/netinet/ip_fw.h
===================================================================
--- sys/netinet/ip_fw.h
+++ sys/netinet/ip_fw.h
@@ -285,6 +285,8 @@
O_EXTERNAL_INSTANCE, /* arg1=id of eaction handler instance */
O_EXTERNAL_DATA, /* variable length data */
+ O_SKIP_ACTION, /* none */
+
O_LAST_OPCODE /* not an opcode! */
};
Index: sys/netpfil/ipfw/ip_fw2.c
===================================================================
--- sys/netpfil/ipfw/ip_fw2.c
+++ sys/netpfil/ipfw/ip_fw2.c
@@ -2584,7 +2584,9 @@
*
* O_LIMIT and O_KEEP_STATE: these opcodes are
* not real 'actions', and are stored right
- * before the 'action' part of the rule.
+ * before the 'action' part of the rule (one
+ * exception is O_SKIP_ACTION which could be
+ * between these opcodes and 'action' one).
* These opcodes try to install an entry in the
* state tables; if successful, we continue with
* the next opcode (match=1; break;), otherwise
@@ -2601,6 +2603,16 @@
* further instances of these opcodes become NOPs.
* The jump to the next rule is done by setting
* l=0, cmdlen=0.
+ *
+ * O_SKIP_ACTION: this opcode is not a real 'action'
+ * either, and is stored right before the 'action'
+ * part of the rule, right after the O_KEEP_STATE
+ * opcode. It causes match failure so the real
+ * 'action' could be executed only if the rule
+ * is checked via dynamic rule from the state
+ * table, as in such case execution starts
+ * from the true 'action' opcode directly.
+ *
*/
case O_LIMIT:
case O_KEEP_STATE:
@@ -2653,6 +2665,11 @@
match = 1;
break;
+ case O_SKIP_ACTION:
+ match = 0; /* skip to the next rule */
+ l = 0; /* exit inner loop */
+ break;
+
case O_ACCEPT:
retval = 0; /* accept */
l = 0; /* exit inner loop */
Index: sys/netpfil/ipfw/ip_fw_sockopt.c
===================================================================
--- sys/netpfil/ipfw/ip_fw_sockopt.c
+++ sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -1750,6 +1750,7 @@
#endif
case O_IP4:
case O_TAG:
+ case O_SKIP_ACTION:
if (cmdlen != F_INSN_SIZE(ipfw_insn))
goto bad_size;
break;

File Metadata

Mime Type
text/plain
Expires
Wed, Sep 25, 1:09 AM (1 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
12717271
Default Alt Text
D1776.id42881.diff (13 KB)

Event Timeline