Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151558389
D1776.id3634.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D1776.id3634.diff
View Options
Index: sbin/ipfw/ipfw.8
===================================================================
--- sbin/ipfw/ipfw.8
+++ sbin/ipfw/ipfw.8
@@ -166,9 +166,11 @@
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 record-state ,
+.Cm limit
or
-.Cm limit
+.Cm set-limit
option,
the firewall will have a
.Em stateful
@@ -185,6 +187,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 matched by rule) but
+.Cm record-state
+and
+.Cm set-limit
+have not implicit
+.Cm check-state .
See the
.Sx STATEFUL FIREWALL
and
@@ -582,7 +596,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
@@ -1583,6 +1602,34 @@
.Xr sysctl 8
variables), and the lifetime is refreshed every time a matching
packet is found.
+.It Cm record-state
+Upon a match, the firewall will create a dynamic rule as if
+.Cm keep-state
+was specified.
+This option doesn't act as
+.Cm check-state
+in contrast to
+.Cm keep-state .
+.It Cm set-limit Bro Cm src-addr | src-port | dst-addr | dst-port Brc Ar N
+Works exactly like
+.Cm limit
+but rule with this option doesn't have implicit
+.Cm check-state
+attached to it.
+.It Cm skip-immediate-action | skip-action
+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 dynamic rule, created on match, will work
+as intended.
+Rule with both
+.Cm record-state
+and
+.Cm skip-immediate-action
+creates dynamic rule and continues with next rule, but
+when dynamic rule is matched, action is executed as usual.
.It Cm layer2
Matches only layer2 packets, i.e., those passed to
.Nm
@@ -2164,16 +2211,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
+.Cm keep-state ,
+.Cm record-state ,
+.Cm limit
or
-.Cm limit
+.Cm set-limit
rule, causing the creation of a
.Em dynamic
rule which will match all and only packets with
Index: sbin/ipfw/ipfw2.h
===================================================================
--- sbin/ipfw/ipfw2.h
+++ sbin/ipfw/ipfw2.h
@@ -115,7 +115,9 @@
TOK_JAIL,
TOK_IN,
TOK_LIMIT,
+ TOK_SETLIMIT,
TOK_KEEPSTATE,
+ TOK_RECORDSTATE,
TOK_LAYER2,
TOK_OUT,
TOK_DIVERTED,
@@ -227,6 +229,7 @@
TOK_LOCK,
TOK_UNLOCK,
TOK_VLIST,
+ TOK_SKIPACTION,
};
/*
Index: sbin/ipfw/ipfw2.c
===================================================================
--- sbin/ipfw/ipfw2.c
+++ sbin/ipfw/ipfw2.c
@@ -291,7 +291,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 },
@@ -354,6 +356,8 @@
{ "src-ip6", TOK_SRCIP6},
{ "lookup", TOK_LOOKUP},
{ "flow", TOK_FLOW},
+ { "skip-action", TOK_SKIPACTION },
+ { "skip-immediate-action", TOK_SKIPACTION },
{ "//", TOK_COMMENT },
{ "not", TOK_NOT }, /* pseudo option */
@@ -1384,6 +1388,7 @@
ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */
int or_block = 0; /* we are in an or block */
uint32_t uval;
+ int have_probe_state = 0;
if ((fo->set_mask & (1 << rule->set)) == 0) {
/* disabled mask */
@@ -1653,6 +1658,7 @@
break; /* done already */
case O_PROBE_STATE:
+ have_probe_state = 1;
break; /* no need to print anything here */
case O_IP_SRC:
@@ -1990,7 +1996,10 @@
break;
case O_KEEP_STATE:
- bprintf(bp, " keep-state");
+ if (have_probe_state)
+ bprintf(bp, " keep-state");
+ else
+ bprintf(bp, " record-state");
break;
case O_LIMIT: {
@@ -1999,7 +2008,11 @@
uint8_t x = c->limit_mask;
char const *comma = " ";
- bprintf(bp, " limit");
+ if (have_probe_state)
+ bprintf(bp, " limit");
+ else
+ bprintf(bp, " set-limit");
+
for (; p->x != 0 ; p++)
if ((x & p->x) == p->x) {
x &= ~p->x;
@@ -2035,6 +2048,10 @@
0, O_TAGGED);
break;
+ case O_SKIP_ACTION:
+ bprintf(bp, " skip-immediate-action");
+ break;
+
default:
bprintf(bp, " [opcode %d len %d]",
cmd->opcode, cmd->len);
@@ -3485,8 +3502,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;
@@ -4335,27 +4354,31 @@
break;
case TOK_KEEPSTATE:
+ case TOK_RECORDSTATE:
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");
have_state = cmd;
+ have_rstate = i == TOK_RECORDSTATE;
fill_cmd(cmd, O_KEEP_STATE, 0, 0);
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;
@@ -4539,6 +4562,7 @@
av++;
}
break;
+
case TOK_FLOW:
NEED1("missing table name");
if (strncmp(*av, "table(", 6) != 0)
@@ -4548,6 +4572,14 @@
av++;
break;
+ case TOK_SKIPACTION:
+ if (have_skipcmd)
+ errx(EX_USAGE, "only one skip-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);
}
@@ -4558,6 +4590,11 @@
}
done:
+
+ if (!have_state && have_skipcmd)
+ warnx("Rule contains \"skip-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
@@ -4580,12 +4617,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, 0);
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);
@@ -4596,6 +4636,7 @@
case O_LIMIT:
case O_ALTQ:
case O_TAG:
+ case O_SKIP_ACTION:
break;
default:
bcopy(src, dst, i * sizeof(uint32_t));
@@ -4612,7 +4653,18 @@
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
*/
rule->act_ofs = dst - rule->cmd;
@@ -4963,7 +5015,3 @@
free(olh);
}
-
-
-
-
Index: sys/netinet/ip_fw.h
===================================================================
--- sys/netinet/ip_fw.h
+++ sys/netinet/ip_fw.h
@@ -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_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
@@ -2109,7 +2109,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
@@ -2126,11 +2128,22 @@
* 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 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:
- if (ipfw_install_state(chain, f,
- (ipfw_insn_limit *)cmd, args, tablearg)) {
+ if (ipfw_install_or_update_state(chain, f,
+ (ipfw_insn_limit *)cmd, args, tablearg,
+ proto == IPPROTO_TCP ? TCP(ulp) : NULL)) {
/* error or limit violation */
retval = IP_FW_DENY;
l = 0; /* exit inner loop */
@@ -2187,6 +2200,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 */
@@ -2537,7 +2555,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
+++ sys/netpfil/ipfw/ip_fw_dynamic.c
@@ -669,13 +669,15 @@
/**
* Install dynamic state for rule type cmd->o.opcode
+ * If rule exists, update it state.
*
* Returns 1 (failure) if state is not installed because of errors or because
* session limitations are enforced.
*/
int
-ipfw_install_state(struct ip_fw_chain *chain, struct ip_fw *rule,
- ipfw_insn_limit *cmd, struct ip_fw_args *args, uint32_t tablearg)
+ipfw_install_or_update_state(struct ip_fw_chain *chain, struct ip_fw *rule,
+ ipfw_insn_limit *cmd, struct ip_fw_args *args, uint32_t tablearg,
+ struct tcphdr *tcp)
{
ipfw_dyn_rule *q;
int i;
@@ -686,9 +688,9 @@
IPFW_BUCK_LOCK(i);
- q = lookup_dyn_rule_locked(&args->f_id, i, NULL, NULL);
+ q = lookup_dyn_rule_locked(&args->f_id, i, NULL, tcp);
- if (q != NULL) { /* should never occur */
+ if (q != NULL) { /* could occur in case of "record-state" */
DEB(
if (last_log != time_uptime) {
last_log = time_uptime;
Index: sys/netpfil/ipfw/ip_fw_private.h
===================================================================
--- sys/netpfil/ipfw/ip_fw_private.h
+++ sys/netpfil/ipfw/ip_fw_private.h
@@ -183,8 +183,9 @@
struct tcphdr;
struct mbuf *ipfw_send_pkt(struct mbuf *, struct ipfw_flow_id *,
u_int32_t, u_int32_t, int);
-int ipfw_install_state(struct ip_fw_chain *chain, struct ip_fw *rule,
- ipfw_insn_limit *cmd, struct ip_fw_args *args, uint32_t tablearg);
+int ipfw_install_or_update_state(struct ip_fw_chain *chain, struct ip_fw *rule,
+ ipfw_insn_limit *cmd, struct ip_fw_args *args, uint32_t tablearg,
+ struct tcphdr *tcp);
ipfw_dyn_rule *ipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt,
int *match_direction, struct tcphdr *tcp);
void ipfw_remove_dyn_children(struct ip_fw *rule);
Index: sys/netpfil/ipfw/ip_fw_sockopt.c
===================================================================
--- sys/netpfil/ipfw/ip_fw_sockopt.c
+++ sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -1460,6 +1460,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
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 10, 4:46 AM (10 h, 28 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31200123
Default Alt Text
D1776.id3634.diff (12 KB)
Attached To
Mode
D1776: New options for ipfw - record-state, set-limit and skip-immediate-action - for simpler rulesets
Attached
Detach File
Event Timeline
Log In to Comment