Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157837078
D40512.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
27 KB
Referenced Files
None
Subscribers
None
D40512.diff
View Options
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -448,7 +448,7 @@
struct tidx *tstate);
void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av, int cblen);
-void fill_unreach6_code(u_short *codep, char *str);
+uint16_t fill_unreach6_code(char *str);
void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av, int cblen);
int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -40,6 +40,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <stdbool.h>
#include <sysexits.h>
#include <time.h> /* ctime */
#include <timeconv.h> /* _long_to_time */
@@ -76,6 +77,122 @@
static int ipfw_socket = -1;
+struct linear_buffer {
+ char *base; /* Base allocated memory pointer */
+ uint32_t offset; /* Currently used offset */
+ uint32_t size; /* Total buffer size */
+ struct linear_buffer *next; /* Buffer chaining */
+};
+
+static inline struct linear_buffer *
+lb_init(uint32_t size)
+{
+ struct linear_buffer *lb = calloc(1, size);
+
+ if (lb != NULL) {
+ lb->base = (char *)(lb + 1);
+ lb->size = size - sizeof(*lb);
+ }
+
+ return (lb);
+}
+
+static inline void
+lb_free(struct linear_buffer *lb)
+{
+ free(lb);
+}
+
+static inline char *
+lb_allocz(struct linear_buffer *lb, int len)
+{
+ len = roundup2(len, sizeof(uint64_t));
+ if (lb->offset + len > lb->size)
+ return (NULL);
+ void *data = (void *)(lb->base + lb->offset);
+ lb->offset += len;
+ return (data);
+}
+
+static inline void
+lb_clear(struct linear_buffer *lb)
+{
+ memset(lb->base, 0, lb->offset);
+ lb->offset = 0;
+}
+
+
+struct ipfw_ctx {
+ struct linear_buffer *lb;
+};
+
+typedef struct ipfw_ctx ipfw_ctx_t;
+
+static bool
+lipfw_ctx_init(struct ipfw_ctx *ctx)
+{
+ memset(ctx, 0, sizeof(*ctx));
+
+ ctx->lb = lb_init(65536);
+ if (ctx->lb == NULL) {
+ return (false);
+ }
+
+ return (true);
+}
+
+static inline void *
+ipfw_allocz(struct ipfw_ctx *ctx, int len)
+{
+ void *data = lb_allocz(ctx->lb, len);
+
+ if (data == NULL) {
+ uint32_t size = ctx->lb->size * 2;
+
+ while (size < len + sizeof(struct linear_buffer))
+ size *= 2;
+
+ struct linear_buffer *lb = lb_init(size);
+
+ if (lb == NULL)
+ err(EX_UNAVAILABLE, "malloc(%d) failed", len);
+
+ lb->next = ctx->lb;
+ ctx->lb = lb;
+ data = lb_allocz(ctx->lb, len);
+ }
+
+ return (data);
+}
+
+static inline void
+lipfw_clear_lb(struct ipfw_ctx *ctx)
+{
+ struct linear_buffer *lb = ctx->lb;
+
+ lb_clear(lb);
+ lb = lb->next;
+ ctx->lb->next = NULL;
+ /* Remove all linear bufs except the largest one */
+ while (lb != NULL) {
+ struct linear_buffer *lb_next = lb->next;
+ lb_free(lb);
+ lb = lb_next;
+ }
+}
+
+static inline void
+lipfw_ctx_free(struct ipfw_ctx *ctx)
+{
+ lipfw_clear_lb(ctx);
+ lb_free(ctx->lb);
+}
+
+
+
+
+
+
#define CHECK_LENGTH(v, len) do { \
if ((v) < (len)) \
errx(EX_DATAERR, "Rule too long"); \
@@ -1203,8 +1320,8 @@
{ NULL, 0 }
};
-static void
-fill_reject_code(u_short *codep, char *str)
+static uint16_t
+fill_reject_code(char *str)
{
int val;
char *s;
@@ -1214,8 +1331,7 @@
val = match_token(icmpcodes, str);
if (val < 0)
errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str);
- *codep = val;
- return;
+ return (val);
}
static void
@@ -3110,6 +3226,7 @@
uint32_t size;
uint16_t counter;
uint8_t set;
+ ipfw_ctx_t *ctx;
};
int
@@ -3179,11 +3296,14 @@
}
if (tstate->count + 1 > tstate->size) {
- tstate->size += 4;
- tstate->idx = realloc(tstate->idx, tstate->size *
- sizeof(ipfw_obj_ntlv));
- if (tstate->idx == NULL)
- return (0);
+ int new_size = MAX(tstate->size * 2, 4);
+ void *idx;
+
+ idx = ipfw_allocz(tstate->ctx, new_size * sizeof(ipfw_obj_ntlv));
+ memcpy(idx, tstate->idx, tstate->size * sizeof(ipfw_obj_ntlv));
+
+ tstate->idx = idx;
+ tstate->size = new_size;
}
ntlv = &tstate->idx[i];
@@ -3937,6 +4057,98 @@
return ret;
}
+struct cmd_buffer {
+ char *data;
+ int off;
+ int size;
+ int count;
+};
+
+enum lipfw_ir_buffer {
+ LIPFW_IR_CMD,
+ LIPFW_IR_ACT,
+ LIPFW_IR_SACT,
+ LIPFW_IR_STA,
+ __LIPFW_IR_MAX,
+};
+
+struct ipfw_rule_ir {
+ ipfw_ctx_t *ctx;
+ ipfw_insn *state_insn;
+ struct cmd_buffer buffers[4];
+ uint32_t rule_num;
+ uint32_t set_id;
+ double match_prob;
+};
+
+static inline ipfw_insn *
+buf_reserve(struct ipfw_rule_ir *ir, struct cmd_buffer *buf, int len)
+{
+ if (__predict_false(buf->off + len > buf->size)) {
+ /* Realloc */
+ int new_size = MAX(buf->size * 2, 4);
+ char *data = ipfw_allocz(ir->ctx, new_size);
+
+ memcpy(data, buf->data, buf->off);
+ buf->data = data;
+ buf->size = new_size;
+ }
+
+ ipfw_insn *cmd = (ipfw_insn *)(void *)&buf->data[buf->off];
+ buf->off += len;
+ buf->count++;
+
+ return (cmd);
+}
+
+static struct ipfw_rule_ir *
+lipfw_rule_alloc(ipfw_ctx_t *ctx)
+{
+ struct ipfw_rule_ir *ir = ipfw_allocz(ctx, sizeof(*ir));
+
+ ir->ctx = ctx;
+ ir->match_prob = 1;
+
+ return (ir);
+}
+
+static ipfw_insn *
+buf_get(struct ipfw_rule_ir *ir, uint8_t btype)
+{
+ if (ir->buffers[btype].off == 0)
+ return (NULL);
+ return ((ipfw_insn *)ir->buffers[btype].data);
+}
+
+static bool
+buf_is_empty(const struct ipfw_rule_ir *ir, uint8_t btype)
+{
+ return (ir->buffers[btype].off != 0);
+}
+
+static ipfw_insn *
+lipfw_rule_add_cmd_raw(struct ipfw_rule_ir *ir, uint8_t btype, const ipfw_insn *cmd)
+{
+ ipfw_insn *new_cmd = buf_reserve(ir, &ir->buffers[btype], F_LEN(cmd) * 4);
+
+ memcpy(new_cmd, cmd, F_LEN(cmd) * 4);
+
+ return (new_cmd);
+}
+
+static ipfw_insn *
+lipfw_rule_add_cmd(struct ipfw_rule_ir *ir, uint8_t btype, uint8_t opcode,
+ uint8_t flags, uint16_t arg1)
+{
+ ipfw_insn *cmd = buf_reserve(ir, &ir->buffers[btype], sizeof(ipfw_insn));
+
+ cmd->opcode = opcode;
+ cmd->len = 1 | (flags & (F_NOT | F_OR));
+ cmd->arg1 = arg1;
+
+ return (cmd);
+}
+
static inline int
arg_or_targ_relaxed(const char *arg, const char *action)
{
@@ -3965,23 +4177,20 @@
return (arg1);
}
-static void
-fill_divert_port(ipfw_insn *cmd, char *arg, const char *action)
+static uint16_t
+fill_divert_port(char *arg, const char *action)
{
uint32_t arg1 = arg_or_targ_relaxed(arg, action);
- if (arg1 != (uint32_t)(-1)) {
- cmd->arg1 = arg1;
- return;
- }
+ if (arg1 != (uint32_t)(-1))
+ return (arg1);
struct servent *s;
setservent(1);
s = getservbyname(arg, "divert");
- if (s != NULL)
- cmd->arg1 = ntohs(s->s_port);
- else
+ if (s == NULL)
errx(EX_DATAERR, "illegal divert/tee port");
+ return (ntohs(s->s_port));
}
/*
@@ -3997,7 +4206,7 @@
*
*/
static void
-compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
+compile_rule(ipfw_ctx_t *ctx, char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate)
{
/*
* rules are added into the 'rulebuf' and then copied in
@@ -4005,10 +4214,10 @@
* Some things that need to go out of order (prob, action etc.)
* go into actbuf[].
*/
- static uint32_t actbuf[255], cmdbuf[255];
- int rblen, ablen, cblen;
+ static uint32_t cmdbuf[255];
+ int rblen, cblen;
- ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
+ ipfw_insn *src, *dst, *cmd, *prev=NULL;
ipfw_insn *first_cmd; /* first match pattern */
struct ip_fw_rule *rule;
@@ -4016,7 +4225,6 @@
/*
* various flags used to record that we entered some fields.
*/
- 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;
@@ -4031,28 +4239,29 @@
double match_prob = 1; /* match probability, default is always match */
- bzero(actbuf, sizeof(actbuf)); /* actions go here */
bzero(cmdbuf, sizeof(cmdbuf));
bzero(rbuf, *rbufsize);
rule = (struct ip_fw_rule *)rbuf;
cmd = (ipfw_insn *)cmdbuf;
- action = (ipfw_insn *)actbuf;
rblen = *rbufsize / sizeof(uint32_t);
rblen -= sizeof(struct ip_fw_rule) / sizeof(uint32_t);
- ablen = sizeof(actbuf) / sizeof(actbuf[0]);
cblen = sizeof(cmdbuf) / sizeof(cmdbuf[0]);
cblen -= F_INSN_SIZE(ipfw_insn_u32) + 1;
#define CHECK_RBUFLEN(len) { CHECK_LENGTH(rblen, len); rblen -= len; }
#define CHECK_ACTLEN CHECK_LENGTH(ablen, action->len)
+ struct ipfw_rule_ir *ir = lipfw_rule_alloc(ctx);
+ uint16_t arg1;
+
av++;
/* [rule N] -- Rule number optional */
if (av[0] && isdigit(**av)) {
rule->rulenum = atoi(*av);
+ ir->rule_num = atoi(*av);
av++;
}
@@ -4063,12 +4272,14 @@
errx(EX_DATAERR, "illegal set %s", av[1]);
rule->set = set;
tstate->set = set;
+ ir->set_id = set;
av += 2;
}
/* [prob D] -- match probability, optional */
if (av[0] && av[1] && _substrcmp(*av, "prob") == 0) {
match_prob = strtod(av[1], NULL);
+ ir->match_prob = match_prob;
if (match_prob <= 0 || match_prob > 1)
errx(EX_DATAERR, "illegal match prob. %s", av[1]);
@@ -4079,27 +4290,23 @@
NEED1("missing action");
i = match_token(rule_actions, *av);
av++;
- action->len = 1; /* default */
- CHECK_ACTLEN;
switch(i) {
case TOK_CHECKSTATE:
- have_state = action;
- action->opcode = O_CHECK_STATE;
- if (*av == NULL ||
- match_token(rule_options, *av) == TOK_COMMENT) {
- action->arg1 = pack_object(tstate,
- default_state_name, IPFW_TLV_STATE_NAME);
+ if (*av == NULL || match_token(rule_options, *av) == TOK_COMMENT) {
+ arg1 = pack_object(tstate, default_state_name,
+ IPFW_TLV_STATE_NAME);
+ lipfw_rule_add_cmd(ir, LIPFW_IR_STA, O_CHECK_STATE, 0, arg1);
break;
}
if (*av[0] == ':') {
- if (strcmp(*av + 1, "any") == 0)
- action->arg1 = 0;
- else if (state_check_name(*av + 1) == 0)
- action->arg1 = pack_object(tstate, *av + 1,
+ if (strcmp(*av + 1, "any") == 0) {
+ arg1 = 0;
+ } else if (state_check_name(*av + 1) == 0) {
+ arg1 = pack_object(tstate, *av + 1,
IPFW_TLV_STATE_NAME);
- else
- errx(EX_DATAERR, "Invalid state name %s",
- *av);
+ } else
+ errx(EX_DATAERR, "Invalid state name %s", *av);
+ lipfw_rule_add_cmd(ir, LIPFW_IR_STA, O_CHECK_STATE, 0, arg1);
av++;
break;
}
@@ -4107,116 +4314,119 @@
break;
case TOK_ABORT:
- action->opcode = O_REJECT;
- action->arg1 = ICMP_REJECT_ABORT;
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_REJECT, 0, ICMP_REJECT_ABORT);
break;
case TOK_ABORT6:
- action->opcode = O_UNREACH6;
- action->arg1 = ICMP6_UNREACH_ABORT;
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_UNREACH6, 0, ICMP6_UNREACH_ABORT);
break;
case TOK_ACCEPT:
- action->opcode = O_ACCEPT;
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_ACCEPT, 0, 0);
break;
case TOK_DENY:
- action->opcode = O_DENY;
- action->arg1 = 0;
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_DENY, 0, 0);
break;
case TOK_REJECT:
- action->opcode = O_REJECT;
- action->arg1 = ICMP_UNREACH_HOST;
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_REJECT, 0, ICMP_UNREACH_HOST);
break;
case TOK_RESET:
- action->opcode = O_REJECT;
- action->arg1 = ICMP_REJECT_RST;
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_REJECT, 0, ICMP_REJECT_RST);
break;
case TOK_RESET6:
- action->opcode = O_UNREACH6;
- action->arg1 = ICMP6_UNREACH_RST;
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_UNREACH6, 0, ICMP6_UNREACH_RST);
break;
case TOK_UNREACH:
- action->opcode = O_REJECT;
NEED1("missing reject code");
- fill_reject_code(&action->arg1, *av);
+ arg1 = fill_reject_code(*av);
av++;
- if (action->arg1 == ICMP_UNREACH_NEEDFRAG && isdigit(**av)) {
+ if (arg1 == ICMP_UNREACH_NEEDFRAG && isdigit(**av)) {
uint16_t mtu;
mtu = strtoul(*av, NULL, 10);
if (mtu < 68 || mtu >= IP_MAXPACKET)
errx(EX_DATAERR, "illegal argument for %s",
*(av - 1));
- action->len = F_INSN_SIZE(ipfw_insn_u16);
- ((ipfw_insn_u16 *)action)->ports[0] = mtu;
+
+ const ipfw_insn_u16 cmd_unreach = {
+ .o.opcode = O_REJECT,
+ .o.len = F_INSN_SIZE(ipfw_insn_u16),
+ .o.arg1 = arg1,
+ .ports = { mtu, },
+ };
+ lipfw_rule_add_cmd_raw(ir, LIPFW_IR_ACT, &cmd_unreach.o);
av++;
- }
+ } else
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_REJECT, 0, arg1);
break;
case TOK_UNREACH6:
- action->opcode = O_UNREACH6;
NEED1("missing unreach code");
- fill_unreach6_code(&action->arg1, *av);
+ arg1 = fill_unreach6_code(*av);
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_UNREACH6, 0, arg1);
av++;
break;
case TOK_COUNT:
- action->opcode = O_COUNT;
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_COUNT, 0, 0);
break;
case TOK_NAT:
- action->opcode = O_NAT;
- action->len = F_INSN_SIZE(ipfw_insn_nat);
- CHECK_ACTLEN;
if (*av != NULL && _substrcmp(*av, "global") == 0)
- action->arg1 = IP_FW_NAT44_GLOBAL;
+ arg1 = IP_FW_NAT44_GLOBAL;
else
- action->arg1 = arg_or_targ(av[0], *(av - 1));
+ arg1 = arg_or_targ(av[0], *(av - 1));
+ const ipfw_insn_nat cmd_nat = {
+ .o.opcode = O_NAT,
+ .o.len = F_INSN_SIZE(ipfw_insn_nat),
+ .o.arg1 = arg1,
+ };
+ lipfw_rule_add_cmd_raw(ir, LIPFW_IR_ACT, &cmd_nat.o);
av++;
break;
case TOK_QUEUE:
- action->opcode = O_QUEUE;
- action->arg1 = arg_or_targ(av[0], *(av - 1));
+ arg1 = arg_or_targ(av[0], *(av - 1));
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_QUEUE, 0, arg1);
av++;
break;
case TOK_PIPE:
- action->opcode = O_PIPE;
- action->arg1 = arg_or_targ(av[0], *(av - 1));
+ arg1 = arg_or_targ(av[0], *(av - 1));
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_PIPE, 0, arg1);
av++;
break;
case TOK_SKIPTO:
- action->opcode = O_SKIPTO;
- action->arg1 = arg_or_targ(av[0], *(av - 1));
+ arg1 = arg_or_targ(av[0], *(av - 1));
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_SKIPTO, 0, arg1);
av++;
break;
case TOK_NETGRAPH:
- action->opcode = O_NETGRAPH;
- action->arg1 = arg_or_targ(av[0], *(av - 1));
+ arg1 = arg_or_targ(av[0], *(av - 1));
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_NETGRAPH, 0, arg1);
av++;
break;
case TOK_NGTEE:
- action->opcode = O_NGTEE;
- action->arg1 = arg_or_targ(av[0], *(av - 1));
+ arg1 = arg_or_targ(av[0], *(av - 1));
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_NGTEE, 0, arg1);
av++;
break;
case TOK_DIVERT:
- action->opcode = O_DIVERT;
- fill_divert_port(action, av[0], *(av - 1));
+ arg1 = fill_divert_port(av[0], *(av - 1));
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_DIVERT, 0, arg1);
av++;
break;
case TOK_TEE:
- action->opcode = O_TEE;
- fill_divert_port(action, av[0], *(av - 1));
+ arg1 = fill_divert_port(av[0], *(av - 1));
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_TEE, 0, arg1);
av++;
break;
case TOK_CALL:
- action->opcode = O_CALLRETURN;
- action->arg1 = arg_or_targ(av[0], *(av - 1));
+ arg1 = arg_or_targ(av[0], *(av - 1));
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_CALLRETURN, 0, arg1);
av++;
break;
@@ -4288,37 +4498,35 @@
freeaddrinfo(res);
if (family == PF_INET) {
- ipfw_insn_sa *p = (ipfw_insn_sa *)action;
-
- action->opcode = O_FORWARD_IP;
- action->len = F_INSN_SIZE(ipfw_insn_sa);
- CHECK_ACTLEN;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&result;
/*
* In the kernel we assume AF_INET and use only
* sin_port and sin_addr. Remember to set sin_len as
* the routing code seems to use it too.
*/
- p->sa.sin_len = sizeof(struct sockaddr_in);
- p->sa.sin_family = AF_INET;
- p->sa.sin_port = port_number;
- p->sa.sin_addr.s_addr =
- ((struct sockaddr_in *)&result)->sin_addr.s_addr;
+ const ipfw_insn_sa cmd_fwd_inet = {
+ .o.opcode = O_FORWARD_IP,
+ .o.len = F_INSN_SIZE(ipfw_insn_sa),
+ .sa.sin_len = sizeof(struct sockaddr_in),
+ .sa.sin_family = AF_INET,
+ .sa.sin_port = port_number,
+ .sa.sin_addr = sin->sin_addr,
+ };
+ lipfw_rule_add_cmd_raw(ir, LIPFW_IR_ACT, &cmd_fwd_inet.o);
} else if (family == PF_INET6) {
- ipfw_insn_sa6 *p = (ipfw_insn_sa6 *)action;
-
- action->opcode = O_FORWARD_IP6;
- action->len = F_INSN_SIZE(ipfw_insn_sa6);
- CHECK_ACTLEN;
-
- p->sa.sin6_len = sizeof(struct sockaddr_in6);
- p->sa.sin6_family = AF_INET6;
- p->sa.sin6_port = port_number;
- p->sa.sin6_flowinfo = 0;
- p->sa.sin6_scope_id =
- ((struct sockaddr_in6 *)&result)->sin6_scope_id;
- bcopy(&((struct sockaddr_in6*)&result)->sin6_addr,
- &p->sa.sin6_addr, sizeof(p->sa.sin6_addr));
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&result;
+
+ const ipfw_insn_sa6 cmd_fwd_inet6 = {
+ .o.opcode = O_FORWARD_IP6,
+ .o.len = F_INSN_SIZE(ipfw_insn_sa6),
+ .sa.sin6_len = sizeof(struct sockaddr_in6),
+ .sa.sin6_family = AF_INET6,
+ .sa.sin6_port = port_number,
+ .sa.sin6_scope_id = sin6->sin6_scope_id,
+ .sa.sin6_addr = sin6->sin6_addr,
+ };
+ lipfw_rule_add_cmd_raw(ir, LIPFW_IR_ACT, &cmd_fwd_inet6.o);
} else {
errx(EX_DATAERR, "Invalid address family in forward action");
}
@@ -4327,7 +4535,7 @@
}
case TOK_COMMENT:
/* pretend it is a 'count' rule followed by the comment */
- action->opcode = O_COUNT;
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_COUNT, 0, 0);
av--; /* go back... */
break;
@@ -4336,20 +4544,20 @@
int numfibs;
size_t intsize = sizeof(int);
- action->opcode = O_SETFIB;
NEED1("missing fib number");
if (_substrcmp(*av, "tablearg") == 0) {
- action->arg1 = IP_FW_TARG;
+ arg1 = IP_FW_TARG;
} else {
- action->arg1 = strtoul(*av, NULL, 10);
+ arg1 = strtoul(*av, NULL, 10);
if (sysctlbyname("net.fibs", &numfibs, &intsize,
NULL, 0) == -1)
errx(EX_DATAERR, "fibs not supported.\n");
- if (action->arg1 >= numfibs) /* Temporary */
+ if (arg1 >= numfibs) /* Temporary */
errx(EX_DATAERR, "fib too large.\n");
/* Add high-order bit to fib to make room for tablearg*/
- action->arg1 |= 0x8000;
+ arg1 |= 0x8000;
}
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_SETFIB, 0, arg1);
av++;
break;
}
@@ -4358,47 +4566,53 @@
{
int code;
- action->opcode = O_SETDSCP;
NEED1("missing DSCP code");
if (_substrcmp(*av, "tablearg") == 0) {
- action->arg1 = IP_FW_TARG;
+ arg1 = IP_FW_TARG;
} else {
if (isalpha(*av[0])) {
if ((code = match_token(f_ipdscp, *av)) == -1)
errx(EX_DATAERR, "Unknown DSCP code");
- action->arg1 = code;
+ arg1 = code;
} else
- action->arg1 = strtoul(*av, NULL, 10);
+ arg1 = strtoul(*av, NULL, 10);
/*
* Add high-order bit to DSCP to make room
* for tablearg
*/
- action->arg1 |= 0x8000;
+ arg1 |= 0x8000;
}
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_SETDSCP, 0, arg1);
av++;
break;
}
case TOK_REASS:
- action->opcode = O_REASS;
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_REASS, 0, 0);
break;
case TOK_RETURN:
- fill_cmd(action, O_CALLRETURN, F_NOT, 0);
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_CALLRETURN, F_NOT, 0);
break;
case TOK_SETMARK: {
- action->opcode = O_SETMARK;
- action->len = F_INSN_SIZE(ipfw_insn_u32);
NEED1("missing mark");
+ uint32_t mark = 0;
+
if (strcmp(*av, "tablearg") == 0) {
- action->arg1 = IP_FW_TARG;
+ arg1 = IP_FW_TARG;
} else {
- ((ipfw_insn_u32 *)action)->d[0] =
- strtoul(*av, NULL, 0);
+ mark = strtoul(*av, NULL, 0);
/* This is not a tablearg */
- action->arg1 |= 0x8000;
+ arg1 = 0x8000;
}
+ const ipfw_insn_u32 cmd_mark = {
+ .o.opcode = O_SETMARK,
+ .o.len = F_INSN_SIZE(ipfw_insn_u32),
+ .o.arg1 = arg1,
+ .d = { mark },
+ };
+ lipfw_rule_add_cmd_raw(ir, LIPFW_IR_ACT, &cmd_mark.o);
av++;
CHECK_CMDLEN;
break;
@@ -4411,15 +4625,12 @@
idx = pack_object(tstate, "tcp-setmss", IPFW_TLV_EACTION);
if (idx == 0)
errx(EX_DATAERR, "pack_object failed");
- fill_cmd(action, O_EXTERNAL_ACTION, 0, idx);
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_EXTERNAL_ACTION, 0, idx);
NEED1("Missing MSS value");
- action = next_cmd(action, &ablen);
- action->len = 1;
- CHECK_ACTLEN;
mss = strtoul(*av, NULL, 10);
if (mss == 0 || mss > UINT16_MAX)
errx(EX_USAGE, "invalid MSS value %s", *av);
- fill_cmd(action, O_EXTERNAL_DATA, 0, (uint16_t)mss);
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_EXTERNAL_DATA, 0, mss);
av++;
break;
}
@@ -4445,12 +4656,9 @@
idx = pack_object(tstate, *av, IPFW_TLV_EACTION);
if (idx == 0)
errx(EX_DATAERR, "pack_object failed");
- fill_cmd(action, O_EXTERNAL_ACTION, 0, idx);
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_EXTERNAL_ACTION, 0, idx);
av++;
NEED1("Missing eaction instance name");
- action = next_cmd(action, &ablen);
- action->len = 1;
- CHECK_ACTLEN;
if (eaction_check_name(*av) != 0)
errx(EX_DATAERR, "Invalid eaction instance name %s",
*av);
@@ -4462,11 +4670,10 @@
idx = pack_object(tstate, *av, 0);
if (idx == 0)
errx(EX_DATAERR, "pack_object failed");
- fill_cmd(action, O_EXTERNAL_INSTANCE, 0, idx);
+ lipfw_rule_add_cmd(ir, LIPFW_IR_ACT, O_EXTERNAL_INSTANCE, 0, idx);
av++;
}
}
- action = next_cmd(action, &ablen);
/*
* [altq queuename] -- altq tag, optional
@@ -4554,7 +4761,7 @@
cmd = next_cmd(cmd, &cblen);
}
- if (have_state) { /* must be a check-state, we are done */
+ if (buf_is_empty(ir, LIPFW_IR_STA)) { /* must be a check-state, we are done */
if (*av != NULL &&
match_token(rule_options, *av) == TOK_COMMENT) {
/* check-state has a comment */
@@ -5038,7 +5245,7 @@
if (open_par)
errx(EX_USAGE, "keep-state or record-state cannot be part "
"of an or block");
- if (have_state)
+ if (buf_is_empty(ir, LIPFW_IR_STA))
errx(EX_USAGE, "only one of keep-state, record-state, "
" limit and set-limit is allowed");
if (*av != NULL && *av[0] == ':') {
@@ -5051,9 +5258,9 @@
} else
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);
+ lipfw_rule_add_cmd(ir, LIPFW_IR_STA, O_KEEP_STATE, 0, uidx);
break;
}
@@ -5065,10 +5272,9 @@
if (open_par)
errx(EX_USAGE,
"limit or set-limit cannot be part of an or block");
- if (have_state)
+ if (buf_is_empty(ir, LIPFW_IR_STA))
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);
@@ -5100,6 +5306,13 @@
} else
cmd->arg1 = pack_object(tstate,
default_state_name, IPFW_TLV_STATE_NAME);
+ const ipfw_insn_limit cmd_limit = {
+ .o.opcode = O_LIMIT,
+ .o.len = F_INSN_SIZE(ipfw_insn_limit),
+ .limit_mask = c->limit_mask,
+ .conn_limit = c->conn_limit,
+ };
+ lipfw_rule_add_cmd_raw(ir, LIPFW_IR_STA, &cmd_limit.o);
break;
}
@@ -5308,7 +5521,7 @@
done:
- if (!have_state && have_skipcmd)
+ if (!buf_is_empty(ir, LIPFW_IR_STA) && have_skipcmd)
warnx("Rule contains \"defer-immediate-action\" "
"and doesn't contain any state-related options.");
@@ -5334,9 +5547,13 @@
/*
* generate O_PROBE_STATE if necessary
*/
- 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);
+ if (buf_is_empty(ir, LIPFW_IR_STA)) {
+ ipfw_insn *tmp = buf_get(ir, LIPFW_IR_STA);
+
+ if (tmp->opcode != O_CHECK_STATE && !have_rstate) {
+ fill_cmd(dst, O_PROBE_STATE, 0, tmp->arg1);
+ dst = next_cmd(dst, &rblen);
+ }
}
/*
@@ -5364,11 +5581,15 @@
/*
* put back the have_state command as last opcode
*/
- if (have_state && have_state->opcode != O_CHECK_STATE) {
- i = F_LEN(have_state);
- CHECK_RBUFLEN(i);
- bcopy(have_state, dst, i * sizeof(uint32_t));
- dst += i;
+ if (buf_is_empty(ir, LIPFW_IR_STA)) {
+ ipfw_insn *tmp = buf_get(ir, LIPFW_IR_STA);
+
+ if (tmp->opcode != O_CHECK_STATE) {
+ i = F_LEN(ir->state_insn);
+ CHECK_RBUFLEN(i);
+ bcopy(tmp, dst, i * sizeof(uint32_t));
+ dst += i;
+ }
}
/*
@@ -5409,7 +5630,9 @@
/*
* copy all other actions
*/
- for (src = (ipfw_insn *)actbuf; src != action; src += i) {
+ struct cmd_buffer *_abuf = &ir->buffers[LIPFW_IR_ACT];
+ ipfw_insn *action = (ipfw_insn *)(void *)&_abuf->data[_abuf->off];
+ for (src = (ipfw_insn *)(void *)_abuf->data; src != action; src += i) {
i = F_LEN(src);
CHECK_RBUFLEN(i);
bcopy(src, dst, i * sizeof(uint32_t));
@@ -5544,15 +5767,17 @@
uint32_t rulebuf[1024];
int rbufsize, default_off, tlen, rlen;
size_t sz;
- struct tidx ts;
struct ip_fw_rule *rule;
caddr_t tbuf;
ip_fw3_opheader *op3;
ipfw_obj_ctlv *ctlv, *tstate;
+ ipfw_ctx_t ctx;
+ struct tidx ts = { .ctx = &ctx };
+
+ lipfw_ctx_init(&ctx);
rbufsize = sizeof(rulebuf);
memset(rulebuf, 0, rbufsize);
- memset(&ts, 0, sizeof(ts));
/* Optimize case with no tables */
default_off = sizeof(ipfw_obj_ctlv) + sizeof(ip_fw3_opheader);
@@ -5561,7 +5786,7 @@
rule = (struct ip_fw_rule *)(ctlv + 1);
rbufsize -= default_off;
- compile_rule(av, (uint32_t *)rule, &rbufsize, &ts);
+ compile_rule(&ctx, av, (uint32_t *)rule, &rbufsize, &ts);
/* Align rule size to u64 boundary */
rlen = roundup2(rbufsize, sizeof(uint64_t));
@@ -5615,11 +5840,10 @@
bp_free(&bp);
}
+ lipfw_ctx_free(&ctx);
+
if (tbuf != NULL)
free(tbuf);
-
- if (ts.idx != NULL)
- free(ts.idx);
}
/*
diff --git a/sbin/ipfw/ipv6.c b/sbin/ipfw/ipv6.c
--- a/sbin/ipfw/ipv6.c
+++ b/sbin/ipfw/ipv6.c
@@ -55,8 +55,8 @@
{ NULL, 0 }
};
-void
-fill_unreach6_code(u_short *codep, char *str)
+uint16_t
+fill_unreach6_code(char *str)
{
int val;
char *s;
@@ -66,8 +66,7 @@
val = match_token(icmp6codes, str);
if (val < 0)
errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str);
- *codep = val;
- return;
+ return (val);
}
void
diff --git a/sbin/ipfw/tests/test_add_rule.py b/sbin/ipfw/tests/test_add_rule.py
--- a/sbin/ipfw/tests/test_add_rule.py
+++ b/sbin/ipfw/tests/test_add_rule.py
@@ -173,6 +173,39 @@
},
id="test_comment",
),
+ pytest.param(
+ {
+ "in": "add tcp-setmss 123 ip from any to 1.2.3.4",
+ "out": {
+ "objs": [
+ NTlv(IpFwTlvType.IPFW_TLV_EACTION, idx=1, name="tcp-setmss"),
+ ],
+ "insns": [
+ InsnIp(IpFwOpcode.O_IP_DST, ip="1.2.3.4"),
+ Insn(IpFwOpcode.O_EXTERNAL_ACTION, arg1=1),
+ Insn(IpFwOpcode.O_EXTERNAL_DATA, arg1=123),
+ ],
+ },
+ },
+ id="test_eaction_tcp-setmss",
+ ),
+ pytest.param(
+ {
+ "in": "add eaction ntpv6 AAA ip from any to 1.2.3.4",
+ "out": {
+ "objs": [
+ NTlv(IpFwTlvType.IPFW_TLV_EACTION, idx=1, name="ntpv6"),
+ NTlv(0, idx=2, name="AAA"),
+ ],
+ "insns": [
+ InsnIp(IpFwOpcode.O_IP_DST, ip="1.2.3.4"),
+ Insn(IpFwOpcode.O_EXTERNAL_ACTION, arg1=1),
+ Insn(IpFwOpcode.O_EXTERNAL_INSTANCE, arg1=2),
+ ],
+ },
+ },
+ id="test_eaction_ntp",
+ ),
],
)
def test_add_rule(self, rule):
diff --git a/tests/atf_python/sys/netpfil/ipfw/ioctl.py b/tests/atf_python/sys/netpfil/ipfw/ioctl.py
--- a/tests/atf_python/sys/netpfil/ipfw/ioctl.py
+++ b/tests/atf_python/sys/netpfil/ipfw/ioctl.py
@@ -90,6 +90,11 @@
for obj in self.obj_list:
obj.print_obj(prepend)
+ def print_obj_hex(self, prepend=""):
+ print(prepend)
+ print()
+ print(" ".join(["x{:02X}".format(b) for b in bytes(self)]))
+
@classmethod
def _validate(cls, data):
if len(data) < sizeof(IpFwObjTlv):
@@ -487,6 +492,7 @@
[
AttrDescr(IpFwTlvType.IPFW_TLV_TBL_NAME, NTlv),
AttrDescr(IpFwTlvType.IPFW_TLV_STATE_NAME, NTlv),
+ AttrDescr(IpFwTlvType.IPFW_TLV_EACTION, NTlv),
],
True,
),
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, May 26, 6:05 PM (8 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33534573
Default Alt Text
D40512.diff (27 KB)
Attached To
Mode
D40512: ipfw: simplify action parsing
Attached
Detach File
Event Timeline
Log In to Comment