Implement buffer size checking in ipfw(8) add cmd.
PR: bin/65961 Submitted by: Eugene Grosbein <eugen@grosbein.pp.ru> MFC after: 2 weeks
This commit is contained in:
parent
472a9fc8d8
commit
12a0d12e98
@ -64,6 +64,22 @@ int ipfw_socket = -1;
|
||||
#define s6_addr32 __u6_addr.__u6_addr32
|
||||
#endif
|
||||
|
||||
#define CHECK_LENGTH(v, len) do { \
|
||||
if ((v) < (len)) \
|
||||
errx(EX_DATAERR, "Rule too long"); \
|
||||
} while (0)
|
||||
/*
|
||||
* Check if we have enough space in cmd buffer. Note that since
|
||||
* first 8? u32 words are reserved by reserved header, full cmd
|
||||
* buffer can't be used, so we need to protect from buffer overrun
|
||||
* only. At the beginnig, cblen is less than actual buffer size by
|
||||
* size of ipfw_insn_u32 instruction + 1 u32 work. This eliminates need
|
||||
* for checking small instructions fitting in given range.
|
||||
* We also (ab)use the fact that ipfw_insn is always the first field
|
||||
* for any custom instruction.
|
||||
*/
|
||||
#define CHECK_CMDLEN CHECK_LENGTH(cblen, F_LEN((ipfw_insn *)cmd))
|
||||
|
||||
#define GET_UINT_ARG(arg, min, max, tok, s_x) do { \
|
||||
if (!av[0]) \
|
||||
errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \
|
||||
@ -653,7 +669,7 @@ strtoport(char *s, char **end, int base, int proto)
|
||||
* Fill the body of the command with the list of port ranges.
|
||||
*/
|
||||
static int
|
||||
fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
|
||||
fill_newports(ipfw_insn_u16 *cmd, char *av, int proto, int cblen)
|
||||
{
|
||||
uint16_t a, b, *p = cmd->ports;
|
||||
int i = 0;
|
||||
@ -664,6 +680,8 @@ fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
|
||||
if (s == av) /* empty or invalid argument */
|
||||
return (0);
|
||||
|
||||
CHECK_LENGTH(cblen, i + 2);
|
||||
|
||||
switch (*s) {
|
||||
case '-': /* a range */
|
||||
av = s + 1;
|
||||
@ -2068,7 +2086,7 @@ lookup_host (char *host, struct in_addr *ipaddr)
|
||||
* We can have multiple comma-separated address/mask entries.
|
||||
*/
|
||||
static void
|
||||
fill_ip(ipfw_insn_ip *cmd, char *av)
|
||||
fill_ip(ipfw_insn_ip *cmd, char *av, int cblen)
|
||||
{
|
||||
int len = 0;
|
||||
uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
|
||||
@ -2108,6 +2126,8 @@ fill_ip(ipfw_insn_ip *cmd, char *av)
|
||||
int masklen;
|
||||
char md, nd = '\0';
|
||||
|
||||
CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn) + 2 + len);
|
||||
|
||||
if (p) {
|
||||
md = *p;
|
||||
*p++ = '\0';
|
||||
@ -2366,11 +2386,13 @@ ipfw_delete(char *av[])
|
||||
* patterns which match interfaces.
|
||||
*/
|
||||
static void
|
||||
fill_iface(ipfw_insn_if *cmd, char *arg)
|
||||
fill_iface(ipfw_insn_if *cmd, char *arg, int cblen)
|
||||
{
|
||||
cmd->name[0] = '\0';
|
||||
cmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
|
||||
|
||||
CHECK_CMDLEN;
|
||||
|
||||
/* Parse the interface or address */
|
||||
if (strcmp(arg, "any") == 0)
|
||||
cmd->o.len = 0; /* effectively ignore this command */
|
||||
@ -2441,8 +2463,10 @@ get_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask)
|
||||
* the new command in case it has been clobbered before.
|
||||
*/
|
||||
static ipfw_insn *
|
||||
next_cmd(ipfw_insn *cmd)
|
||||
next_cmd(ipfw_insn *cmd, int *len)
|
||||
{
|
||||
*len -= F_LEN(cmd);
|
||||
CHECK_LENGTH(*len, 0);
|
||||
cmd += F_LEN(cmd);
|
||||
bzero(cmd, sizeof(*cmd));
|
||||
return cmd;
|
||||
@ -2452,7 +2476,7 @@ next_cmd(ipfw_insn *cmd)
|
||||
* Takes arguments and copies them into a comment
|
||||
*/
|
||||
static void
|
||||
fill_comment(ipfw_insn *cmd, char **av)
|
||||
fill_comment(ipfw_insn *cmd, char **av, int cblen)
|
||||
{
|
||||
int i, l;
|
||||
char *p = (char *)(cmd + 1);
|
||||
@ -2470,6 +2494,8 @@ fill_comment(ipfw_insn *cmd, char **av)
|
||||
"comment too long (max 80 chars)");
|
||||
l = 1 + (l+3)/4;
|
||||
cmd->len = (cmd->len & (F_NOT | F_OR)) | l;
|
||||
CHECK_CMDLEN;
|
||||
|
||||
for (i = 0; av[i] != NULL; i++) {
|
||||
strcpy(p, av[i]);
|
||||
p += strlen(av[i]);
|
||||
@ -2495,7 +2521,7 @@ fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg)
|
||||
* two microinstructions, and returns the pointer to the last one.
|
||||
*/
|
||||
static ipfw_insn *
|
||||
add_mac(ipfw_insn *cmd, char *av[])
|
||||
add_mac(ipfw_insn *cmd, char *av[], int cblen)
|
||||
{
|
||||
ipfw_insn_mac *mac;
|
||||
|
||||
@ -2504,6 +2530,7 @@ add_mac(ipfw_insn *cmd, char *av[])
|
||||
|
||||
cmd->opcode = O_MACADDR2;
|
||||
cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac);
|
||||
CHECK_CMDLEN;
|
||||
|
||||
mac = (ipfw_insn_mac *)cmd;
|
||||
get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */
|
||||
@ -2513,12 +2540,13 @@ add_mac(ipfw_insn *cmd, char *av[])
|
||||
}
|
||||
|
||||
static ipfw_insn *
|
||||
add_mactype(ipfw_insn *cmd, char *av)
|
||||
add_mactype(ipfw_insn *cmd, char *av, int cblen)
|
||||
{
|
||||
if (!av)
|
||||
errx(EX_DATAERR, "missing MAC type");
|
||||
if (strcmp(av, "any") != 0) { /* we have a non-null type */
|
||||
fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE);
|
||||
fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE,
|
||||
cblen);
|
||||
cmd->opcode = O_MAC_TYPE;
|
||||
return cmd;
|
||||
} else
|
||||
@ -2587,9 +2615,9 @@ add_proto_compat(ipfw_insn *cmd, char *av, u_char *protop)
|
||||
}
|
||||
|
||||
static ipfw_insn *
|
||||
add_srcip(ipfw_insn *cmd, char *av)
|
||||
add_srcip(ipfw_insn *cmd, char *av, int cblen)
|
||||
{
|
||||
fill_ip((ipfw_insn_ip *)cmd, av);
|
||||
fill_ip((ipfw_insn_ip *)cmd, av, cblen);
|
||||
if (cmd->opcode == O_IP_DST_SET) /* set */
|
||||
cmd->opcode = O_IP_SRC_SET;
|
||||
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
|
||||
@ -2604,9 +2632,9 @@ add_srcip(ipfw_insn *cmd, char *av)
|
||||
}
|
||||
|
||||
static ipfw_insn *
|
||||
add_dstip(ipfw_insn *cmd, char *av)
|
||||
add_dstip(ipfw_insn *cmd, char *av, int cblen)
|
||||
{
|
||||
fill_ip((ipfw_insn_ip *)cmd, av);
|
||||
fill_ip((ipfw_insn_ip *)cmd, av, cblen);
|
||||
if (cmd->opcode == O_IP_DST_SET) /* set */
|
||||
;
|
||||
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
|
||||
@ -2621,12 +2649,12 @@ add_dstip(ipfw_insn *cmd, char *av)
|
||||
}
|
||||
|
||||
static ipfw_insn *
|
||||
add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
|
||||
add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode, int cblen)
|
||||
{
|
||||
/* XXX "any" is trapped before. Perhaps "to" */
|
||||
if (_substrcmp(av, "any") == 0) {
|
||||
return NULL;
|
||||
} else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) {
|
||||
} else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto, cblen)) {
|
||||
/* XXX todo: check that we have a protocol with ports */
|
||||
cmd->opcode = opcode;
|
||||
return cmd;
|
||||
@ -2635,7 +2663,7 @@ add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
|
||||
}
|
||||
|
||||
static ipfw_insn *
|
||||
add_src(ipfw_insn *cmd, char *av, u_char proto)
|
||||
add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen)
|
||||
{
|
||||
struct in6_addr a;
|
||||
char *host, *ch;
|
||||
@ -2648,11 +2676,11 @@ add_src(ipfw_insn *cmd, char *av, u_char proto)
|
||||
|
||||
if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 ||
|
||||
inet_pton(AF_INET6, host, &a) == 1)
|
||||
ret = add_srcip6(cmd, av);
|
||||
ret = add_srcip6(cmd, av, cblen);
|
||||
/* XXX: should check for IPv4, not !IPv6 */
|
||||
if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
|
||||
inet_pton(AF_INET6, host, &a) != 1))
|
||||
ret = add_srcip(cmd, av);
|
||||
ret = add_srcip(cmd, av, cblen);
|
||||
if (ret == NULL && strcmp(av, "any") != 0)
|
||||
ret = cmd;
|
||||
|
||||
@ -2661,7 +2689,7 @@ add_src(ipfw_insn *cmd, char *av, u_char proto)
|
||||
}
|
||||
|
||||
static ipfw_insn *
|
||||
add_dst(ipfw_insn *cmd, char *av, u_char proto)
|
||||
add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen)
|
||||
{
|
||||
struct in6_addr a;
|
||||
char *host, *ch;
|
||||
@ -2674,11 +2702,11 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto)
|
||||
|
||||
if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 ||
|
||||
inet_pton(AF_INET6, host, &a) == 1)
|
||||
ret = add_dstip6(cmd, av);
|
||||
ret = add_dstip6(cmd, av, cblen);
|
||||
/* XXX: should check for IPv4, not !IPv6 */
|
||||
if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
|
||||
inet_pton(AF_INET6, host, &a) != 1))
|
||||
ret = add_dstip(cmd, av);
|
||||
ret = add_dstip(cmd, av, cblen);
|
||||
if (ret == NULL && strcmp(av, "any") != 0)
|
||||
ret = cmd;
|
||||
|
||||
@ -2708,6 +2736,7 @@ ipfw_add(char *av[])
|
||||
* go into actbuf[].
|
||||
*/
|
||||
static uint32_t rulebuf[255], actbuf[255], cmdbuf[255];
|
||||
int rblen, ablen, cblen;
|
||||
|
||||
ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
|
||||
ipfw_insn *first_cmd; /* first match pattern */
|
||||
@ -2738,6 +2767,15 @@ ipfw_add(char *av[])
|
||||
cmd = (ipfw_insn *)cmdbuf;
|
||||
action = (ipfw_insn *)actbuf;
|
||||
|
||||
rblen = sizeof(rulebuf) / sizeof(rulebuf[0]);
|
||||
rblen -= offsetof(struct ip_fw, cmd) / sizeof(rulebuf[0]);
|
||||
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)
|
||||
|
||||
av++;
|
||||
|
||||
/* [rule N] -- Rule number optional */
|
||||
@ -2769,6 +2807,7 @@ ipfw_add(char *av[])
|
||||
i = match_token(rule_actions, *av);
|
||||
av++;
|
||||
action->len = 1; /* default */
|
||||
CHECK_ACTLEN;
|
||||
switch(i) {
|
||||
case TOK_CHECKSTATE:
|
||||
have_state = action;
|
||||
@ -2820,6 +2859,7 @@ ipfw_add(char *av[])
|
||||
case TOK_NAT:
|
||||
action->opcode = O_NAT;
|
||||
action->len = F_INSN_SIZE(ipfw_insn_nat);
|
||||
CHECK_ACTLEN;
|
||||
if (_substrcmp(*av, "global") == 0) {
|
||||
action->arg1 = 0;
|
||||
av++;
|
||||
@ -2936,6 +2976,7 @@ chkarg:
|
||||
|
||||
action->opcode = O_FORWARD_IP;
|
||||
action->len = F_INSN_SIZE(ipfw_insn_sa);
|
||||
CHECK_ACTLEN;
|
||||
|
||||
/*
|
||||
* In the kernel we assume AF_INET and use only
|
||||
@ -2952,6 +2993,7 @@ chkarg:
|
||||
|
||||
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;
|
||||
@ -3005,7 +3047,7 @@ chkarg:
|
||||
default:
|
||||
errx(EX_DATAERR, "invalid action %s\n", av[-1]);
|
||||
}
|
||||
action = next_cmd(action);
|
||||
action = next_cmd(action, &ablen);
|
||||
|
||||
/*
|
||||
* [altq queuename] -- altq tag, optional
|
||||
@ -3027,6 +3069,7 @@ chkarg:
|
||||
"log cannot be specified more than once");
|
||||
have_log = (ipfw_insn *)c;
|
||||
cmd->len = F_INSN_SIZE(ipfw_insn_log);
|
||||
CHECK_CMDLEN;
|
||||
cmd->opcode = O_LOG;
|
||||
if (av[0] && _substrcmp(*av, "logamount") == 0) {
|
||||
av++;
|
||||
@ -3058,6 +3101,7 @@ chkarg:
|
||||
"altq cannot be specified more than once");
|
||||
have_altq = (ipfw_insn *)a;
|
||||
cmd->len = F_INSN_SIZE(ipfw_insn_altq);
|
||||
CHECK_CMDLEN;
|
||||
cmd->opcode = O_ALTQ;
|
||||
a->qid = altq_name_to_qid(*av);
|
||||
av++;
|
||||
@ -3083,7 +3127,7 @@ chkarg:
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
cmd = next_cmd(cmd);
|
||||
cmd = next_cmd(cmd, &cblen);
|
||||
}
|
||||
|
||||
if (have_state) /* must be a check-state, we are done */
|
||||
@ -3168,7 +3212,7 @@ chkarg:
|
||||
av++;
|
||||
if (F_LEN(cmd) != 0) {
|
||||
prev = cmd;
|
||||
cmd = next_cmd(cmd);
|
||||
cmd = next_cmd(cmd, &cblen);
|
||||
}
|
||||
} else if (first_cmd != cmd) {
|
||||
errx(EX_DATAERR, "invalid protocol ``%s''", *av);
|
||||
@ -3189,11 +3233,11 @@ chkarg:
|
||||
OR_START(source_ip);
|
||||
NOT_BLOCK; /* optional "not" */
|
||||
NEED1("missing source address");
|
||||
if (add_src(cmd, *av, proto)) {
|
||||
if (add_src(cmd, *av, proto, cblen)) {
|
||||
av++;
|
||||
if (F_LEN(cmd) != 0) { /* ! any */
|
||||
prev = cmd;
|
||||
cmd = next_cmd(cmd);
|
||||
cmd = next_cmd(cmd, &cblen);
|
||||
}
|
||||
} else
|
||||
errx(EX_USAGE, "bad source address %s", *av);
|
||||
@ -3205,10 +3249,10 @@ chkarg:
|
||||
NOT_BLOCK; /* optional "not" */
|
||||
if ( av[0] != NULL ) {
|
||||
if (_substrcmp(*av, "any") == 0 ||
|
||||
add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
|
||||
add_ports(cmd, *av, proto, O_IP_SRCPORT, cblen)) {
|
||||
av++;
|
||||
if (F_LEN(cmd) != 0)
|
||||
cmd = next_cmd(cmd);
|
||||
cmd = next_cmd(cmd, &cblen);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3225,11 +3269,11 @@ chkarg:
|
||||
OR_START(dest_ip);
|
||||
NOT_BLOCK; /* optional "not" */
|
||||
NEED1("missing dst address");
|
||||
if (add_dst(cmd, *av, proto)) {
|
||||
if (add_dst(cmd, *av, proto, cblen)) {
|
||||
av++;
|
||||
if (F_LEN(cmd) != 0) { /* ! any */
|
||||
prev = cmd;
|
||||
cmd = next_cmd(cmd);
|
||||
cmd = next_cmd(cmd, &cblen);
|
||||
}
|
||||
} else
|
||||
errx( EX_USAGE, "bad destination address %s", *av);
|
||||
@ -3241,10 +3285,10 @@ chkarg:
|
||||
NOT_BLOCK; /* optional "not" */
|
||||
if (av[0]) {
|
||||
if (_substrcmp(*av, "any") == 0 ||
|
||||
add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
|
||||
add_ports(cmd, *av, proto, O_IP_DSTPORT, cblen)) {
|
||||
av++;
|
||||
if (F_LEN(cmd) != 0)
|
||||
cmd = next_cmd(cmd);
|
||||
cmd = next_cmd(cmd, &cblen);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3332,7 +3376,7 @@ read_options:
|
||||
case TOK_VIA:
|
||||
NEED1("recv, xmit, via require interface name"
|
||||
" or address");
|
||||
fill_iface((ipfw_insn_if *)cmd, av[0]);
|
||||
fill_iface((ipfw_insn_if *)cmd, av[0], cblen);
|
||||
av++;
|
||||
if (F_LEN(cmd) == 0) /* not a valid address */
|
||||
break;
|
||||
@ -3352,14 +3396,14 @@ read_options:
|
||||
|
||||
case TOK_ICMP6TYPES:
|
||||
NEED1("icmptypes requires list of types");
|
||||
fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av);
|
||||
fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av, cblen);
|
||||
av++;
|
||||
break;
|
||||
|
||||
case TOK_IPTTL:
|
||||
NEED1("ipttl requires TTL");
|
||||
if (strpbrk(*av, "-,")) {
|
||||
if (!add_ports(cmd, *av, 0, O_IPTTL))
|
||||
if (!add_ports(cmd, *av, 0, O_IPTTL, cblen))
|
||||
errx(EX_DATAERR, "invalid ipttl %s", *av);
|
||||
} else
|
||||
fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0));
|
||||
@ -3369,7 +3413,7 @@ read_options:
|
||||
case TOK_IPID:
|
||||
NEED1("ipid requires id");
|
||||
if (strpbrk(*av, "-,")) {
|
||||
if (!add_ports(cmd, *av, 0, O_IPID))
|
||||
if (!add_ports(cmd, *av, 0, O_IPID, cblen))
|
||||
errx(EX_DATAERR, "invalid ipid %s", *av);
|
||||
} else
|
||||
fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0));
|
||||
@ -3379,7 +3423,7 @@ read_options:
|
||||
case TOK_IPLEN:
|
||||
NEED1("iplen requires length");
|
||||
if (strpbrk(*av, "-,")) {
|
||||
if (!add_ports(cmd, *av, 0, O_IPLEN))
|
||||
if (!add_ports(cmd, *av, 0, O_IPLEN, cblen))
|
||||
errx(EX_DATAERR, "invalid ip len %s", *av);
|
||||
} else
|
||||
fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0));
|
||||
@ -3475,7 +3519,7 @@ read_options:
|
||||
case TOK_TCPDATALEN:
|
||||
NEED1("tcpdatalen requires length");
|
||||
if (strpbrk(*av, "-,")) {
|
||||
if (!add_ports(cmd, *av, 0, O_TCPDATALEN))
|
||||
if (!add_ports(cmd, *av, 0, O_TCPDATALEN, cblen))
|
||||
errx(EX_DATAERR, "invalid tcpdata len %s", *av);
|
||||
} else
|
||||
fill_cmd(cmd, O_TCPDATALEN, 0,
|
||||
@ -3501,7 +3545,7 @@ read_options:
|
||||
case TOK_TCPWIN:
|
||||
NEED1("tcpwin requires length");
|
||||
if (strpbrk(*av, "-,")) {
|
||||
if (!add_ports(cmd, *av, 0, O_TCPWIN))
|
||||
if (!add_ports(cmd, *av, 0, O_TCPWIN, cblen))
|
||||
errx(EX_DATAERR, "invalid tcpwin len %s", *av);
|
||||
} else
|
||||
fill_cmd(cmd, O_TCPWIN, 0,
|
||||
@ -3540,6 +3584,7 @@ read_options:
|
||||
have_state = cmd;
|
||||
|
||||
cmd->len = F_INSN_SIZE(ipfw_insn_limit);
|
||||
CHECK_CMDLEN;
|
||||
cmd->opcode = O_LIMIT;
|
||||
c->limit_mask = c->conn_limit = 0;
|
||||
|
||||
@ -3571,28 +3616,28 @@ read_options:
|
||||
|
||||
case TOK_SRCIP:
|
||||
NEED1("missing source IP");
|
||||
if (add_srcip(cmd, *av)) {
|
||||
if (add_srcip(cmd, *av, cblen)) {
|
||||
av++;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOK_DSTIP:
|
||||
NEED1("missing destination IP");
|
||||
if (add_dstip(cmd, *av)) {
|
||||
if (add_dstip(cmd, *av, cblen)) {
|
||||
av++;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOK_SRCIP6:
|
||||
NEED1("missing source IP6");
|
||||
if (add_srcip6(cmd, *av)) {
|
||||
if (add_srcip6(cmd, *av, cblen)) {
|
||||
av++;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOK_DSTIP6:
|
||||
NEED1("missing destination IP6");
|
||||
if (add_dstip6(cmd, *av)) {
|
||||
if (add_dstip6(cmd, *av, cblen)) {
|
||||
av++;
|
||||
}
|
||||
break;
|
||||
@ -3600,7 +3645,7 @@ read_options:
|
||||
case TOK_SRCPORT:
|
||||
NEED1("missing source port");
|
||||
if (_substrcmp(*av, "any") == 0 ||
|
||||
add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
|
||||
add_ports(cmd, *av, proto, O_IP_SRCPORT, cblen)) {
|
||||
av++;
|
||||
} else
|
||||
errx(EX_DATAERR, "invalid source port %s", *av);
|
||||
@ -3609,7 +3654,7 @@ read_options:
|
||||
case TOK_DSTPORT:
|
||||
NEED1("missing destination port");
|
||||
if (_substrcmp(*av, "any") == 0 ||
|
||||
add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
|
||||
add_ports(cmd, *av, proto, O_IP_DSTPORT, cblen)) {
|
||||
av++;
|
||||
} else
|
||||
errx(EX_DATAERR, "invalid destination port %s",
|
||||
@ -3617,13 +3662,13 @@ read_options:
|
||||
break;
|
||||
|
||||
case TOK_MAC:
|
||||
if (add_mac(cmd, av))
|
||||
if (add_mac(cmd, av, cblen))
|
||||
av += 2;
|
||||
break;
|
||||
|
||||
case TOK_MACTYPE:
|
||||
NEED1("missing mac type");
|
||||
if (!add_mactype(cmd, *av))
|
||||
if (!add_mactype(cmd, *av, cblen))
|
||||
errx(EX_DATAERR, "invalid mac type %s", *av);
|
||||
av++;
|
||||
break;
|
||||
@ -3661,18 +3706,18 @@ read_options:
|
||||
if (proto != IPPROTO_IPV6 )
|
||||
errx( EX_USAGE, "flow-id filter is active "
|
||||
"only for ipv6 protocol\n");
|
||||
fill_flow6( (ipfw_insn_u32 *) cmd, *av );
|
||||
fill_flow6( (ipfw_insn_u32 *) cmd, *av, cblen);
|
||||
av++;
|
||||
break;
|
||||
|
||||
case TOK_COMMENT:
|
||||
fill_comment(cmd, av);
|
||||
fill_comment(cmd, av, cblen);
|
||||
av[0]=NULL;
|
||||
break;
|
||||
|
||||
case TOK_TAGGED:
|
||||
if (av[0] && strpbrk(*av, "-,")) {
|
||||
if (!add_ports(cmd, *av, 0, O_TAGGED))
|
||||
if (!add_ports(cmd, *av, 0, O_TAGGED, cblen))
|
||||
errx(EX_DATAERR, "tagged: invalid tag"
|
||||
" list: %s", *av);
|
||||
}
|
||||
@ -3725,7 +3770,7 @@ read_options:
|
||||
}
|
||||
if (F_LEN(cmd) > 0) { /* prepare to advance */
|
||||
prev = cmd;
|
||||
cmd = next_cmd(cmd);
|
||||
cmd = next_cmd(cmd, &cblen);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3754,12 +3799,13 @@ done:
|
||||
*/
|
||||
if (have_state && have_state->opcode != O_CHECK_STATE) {
|
||||
fill_cmd(dst, O_PROBE_STATE, 0, 0);
|
||||
dst = next_cmd(dst);
|
||||
dst = next_cmd(dst, &rblen);
|
||||
}
|
||||
|
||||
/* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */
|
||||
for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
|
||||
i = F_LEN(src);
|
||||
CHECK_RBUFLEN(i);
|
||||
|
||||
switch (src->opcode) {
|
||||
case O_LOG:
|
||||
@ -3779,6 +3825,7 @@ done:
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@ -3790,24 +3837,29 @@ done:
|
||||
/* put back O_LOG, O_ALTQ, O_TAG if necessary */
|
||||
if (have_log) {
|
||||
i = F_LEN(have_log);
|
||||
CHECK_RBUFLEN(i);
|
||||
bcopy(have_log, dst, i * sizeof(uint32_t));
|
||||
dst += i;
|
||||
}
|
||||
if (have_altq) {
|
||||
i = F_LEN(have_altq);
|
||||
CHECK_RBUFLEN(i);
|
||||
bcopy(have_altq, dst, i * sizeof(uint32_t));
|
||||
dst += i;
|
||||
}
|
||||
if (have_tag) {
|
||||
i = F_LEN(have_tag);
|
||||
CHECK_RBUFLEN(i);
|
||||
bcopy(have_tag, dst, i * sizeof(uint32_t));
|
||||
dst += i;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy all other actions
|
||||
*/
|
||||
for (src = (ipfw_insn *)actbuf; src != action; src += i) {
|
||||
i = F_LEN(src);
|
||||
CHECK_RBUFLEN(i);
|
||||
bcopy(src, dst, i * sizeof(uint32_t));
|
||||
dst += i;
|
||||
}
|
||||
|
@ -283,10 +283,10 @@ void print_flow6id(struct _ipfw_insn_u32 *cmd);
|
||||
void print_icmp6types(struct _ipfw_insn_u32 *cmd);
|
||||
void print_ext6hdr(struct _ipfw_insn *cmd );
|
||||
|
||||
struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av);
|
||||
struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av);
|
||||
struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av, int cblen);
|
||||
struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av, int cblen);
|
||||
|
||||
void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av );
|
||||
void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av, int cblen);
|
||||
void fill_unreach6_code(u_short *codep, char *str);
|
||||
void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av);
|
||||
void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av, int cblen);
|
||||
int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
|
||||
|
@ -42,6 +42,11 @@
|
||||
#include <netinet/ip_fw.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define CHECK_LENGTH(v, len) do { \
|
||||
if ((v) < (len)) \
|
||||
errx(EX_DATAERR, "Rule too long"); \
|
||||
} while (0)
|
||||
|
||||
static struct _s_x icmp6codes[] = {
|
||||
{ "no-route", ICMP6_DST_UNREACH_NOROUTE },
|
||||
{ "admin-prohib", ICMP6_DST_UNREACH_ADMIN },
|
||||
@ -131,10 +136,12 @@ print_ip6(ipfw_insn_ip6 *cmd, char const *s)
|
||||
}
|
||||
|
||||
void
|
||||
fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av)
|
||||
fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen)
|
||||
{
|
||||
uint8_t type;
|
||||
|
||||
CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_icmp6));
|
||||
|
||||
bzero(cmd, sizeof(*cmd));
|
||||
while (*av) {
|
||||
if (*av == ',')
|
||||
@ -327,7 +334,7 @@ lookup_host6 (char *host, struct in6_addr *ip6addr)
|
||||
* Return 1 on success, 0 on failure.
|
||||
*/
|
||||
static int
|
||||
fill_ip6(ipfw_insn_ip6 *cmd, char *av)
|
||||
fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen)
|
||||
{
|
||||
int len = 0;
|
||||
struct in6_addr *d = &(cmd->addr6);
|
||||
@ -379,6 +386,8 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av)
|
||||
int masklen;
|
||||
char md = '\0';
|
||||
|
||||
CHECK_LENGTH(cblen, 1 + len + 2 * F_INSN_SIZE(struct in6_addr));
|
||||
|
||||
if ((p = strpbrk(av, "/,")) ) {
|
||||
md = *p; /* save the separator */
|
||||
*p = '\0'; /* terminate address string */
|
||||
@ -453,7 +462,7 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av)
|
||||
* additional flow-id we want to filter, the basic is 1
|
||||
*/
|
||||
void
|
||||
fill_flow6( ipfw_insn_u32 *cmd, char *av )
|
||||
fill_flow6( ipfw_insn_u32 *cmd, char *av, int cblen)
|
||||
{
|
||||
u_int32_t type; /* Current flow number */
|
||||
u_int16_t nflow = 0; /* Current flow index */
|
||||
@ -461,6 +470,8 @@ fill_flow6( ipfw_insn_u32 *cmd, char *av )
|
||||
cmd->d[0] = 0; /* Initializing the base number*/
|
||||
|
||||
while (s) {
|
||||
CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_u32) + nflow + 1);
|
||||
|
||||
av = strsep( &s, ",") ;
|
||||
type = strtoul(av, &av, 0);
|
||||
if (*av != ',' && *av != '\0')
|
||||
@ -481,10 +492,10 @@ fill_flow6( ipfw_insn_u32 *cmd, char *av )
|
||||
}
|
||||
|
||||
ipfw_insn *
|
||||
add_srcip6(ipfw_insn *cmd, char *av)
|
||||
add_srcip6(ipfw_insn *cmd, char *av, int cblen)
|
||||
{
|
||||
|
||||
fill_ip6((ipfw_insn_ip6 *)cmd, av);
|
||||
fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen);
|
||||
if (cmd->opcode == O_IP_DST_SET) /* set */
|
||||
cmd->opcode = O_IP_SRC_SET;
|
||||
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
|
||||
@ -503,10 +514,10 @@ add_srcip6(ipfw_insn *cmd, char *av)
|
||||
}
|
||||
|
||||
ipfw_insn *
|
||||
add_dstip6(ipfw_insn *cmd, char *av)
|
||||
add_dstip6(ipfw_insn *cmd, char *av, int cblen)
|
||||
{
|
||||
|
||||
fill_ip6((ipfw_insn_ip6 *)cmd, av);
|
||||
fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen);
|
||||
if (cmd->opcode == O_IP_DST_SET) /* set */
|
||||
;
|
||||
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
|
||||
|
Loading…
x
Reference in New Issue
Block a user