Page MenuHomeFreeBSD

D40512.diff
No OneTemporary

D40512.diff

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

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)

Event Timeline