aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/ipfw/ipfw.88
-rw-r--r--sbin/ipfw/ipfw2.c20
-rw-r--r--sbin/ipfw/ipfw2.h1
-rw-r--r--sys/netinet/ip_fw.h1
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c42
-rw-r--r--sys/netpfil/ipfw/ip_fw_sockopt.c5
6 files changed, 65 insertions, 12 deletions
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index fcba4a4b03f2..bcc8017a571b 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -1,7 +1,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 24, 2019
+.Dd June 21, 2019
.Dt IPFW 8
.Os
.Sh NAME
@@ -1989,6 +1989,12 @@ a non-zero offset.
See the
.Cm frag
option for details on matching fragmented packets.
+.It Cm tcpmss Ar tcpmss-list
+Matches TCP packets whose MSS (maximum segment size) value is set to
+.Ar tcpmss-list ,
+which is either a single value or a list of values or ranges
+specified in the same way as
+.Ar ports .
.It Cm tcpseq Ar seq
TCP packets only.
Match if the TCP header sequence number field is set to
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 3e73fa3b8736..4fd977edb91f 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -338,6 +338,7 @@ static struct _s_x rule_options[] = {
{ "tcpdatalen", TOK_TCPDATALEN },
{ "tcpflags", TOK_TCPFLAGS },
{ "tcpflgs", TOK_TCPFLAGS },
+ { "tcpmss", TOK_TCPMSS },
{ "tcpoptions", TOK_TCPOPTS },
{ "tcpopts", TOK_TCPOPTS },
{ "tcpseq", TOK_TCPSEQ },
@@ -881,6 +882,7 @@ static struct _s_x _port_name[] = {
{"ipttl", O_IPTTL},
{"mac-type", O_MAC_TYPE},
{"tcpdatalen", O_TCPDATALEN},
+ {"tcpmss", O_TCPMSS},
{"tcpwin", O_TCPWIN},
{"tagged", O_TAGGED},
{NULL, 0}
@@ -1588,6 +1590,7 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
case O_IPTTL:
case O_IPLEN:
case O_TCPDATALEN:
+ case O_TCPMSS:
case O_TCPWIN:
if (F_LEN(cmd) == 1) {
switch (cmd->opcode) {
@@ -1603,6 +1606,9 @@ print_instruction(struct buf_pr *bp, const struct format_opts *fo,
case O_TCPDATALEN:
s = "tcpdatalen";
break;
+ case O_TCPMSS:
+ s = "tcpmss";
+ break;
case O_TCPWIN:
s = "tcpwin";
break;
@@ -4709,14 +4715,18 @@ read_options:
av++;
break;
+ case TOK_TCPMSS:
case TOK_TCPWIN:
- NEED1("tcpwin requires length");
+ NEED1("tcpmss/tcpwin requires size");
if (strpbrk(*av, "-,")) {
- if (!add_ports(cmd, *av, 0, O_TCPWIN, cblen))
- errx(EX_DATAERR, "invalid tcpwin len %s", *av);
+ if (add_ports(cmd, *av, 0,
+ i == TOK_TCPWIN ? O_TCPWIN : O_TCPMSS,
+ cblen) == NULL)
+ errx(EX_DATAERR, "invalid %s size %s",
+ s, *av);
} else
- fill_cmd(cmd, O_TCPWIN, 0,
- strtoul(*av, NULL, 0));
+ fill_cmd(cmd, i == TOK_TCPWIN ? O_TCPWIN :
+ O_TCPMSS, 0, strtoul(*av, NULL, 0));
av++;
break;
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index e6c209d65bab..215416eecc8a 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -151,6 +151,7 @@ enum tokens {
TOK_TCPOPTS,
TOK_TCPSEQ,
TOK_TCPACK,
+ TOK_TCPMSS,
TOK_TCPWIN,
TOK_ICMPTYPES,
TOK_MAC,
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index de0cc29db1d2..7a01c82ba58b 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -293,6 +293,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
O_EXTERNAL_DATA, /* variable length data */
O_SKIP_ACTION, /* none */
+ O_TCPMSS, /* arg1=MSS value */
O_LAST_OPCODE /* not an opcode! */
};
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index a4a3830132eb..6796ad81611d 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -331,10 +331,10 @@ ipopts_match(struct ip *ip, ipfw_insn *cmd)
}
static int
-tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
+tcpopts_parse(struct tcphdr *tcp, uint16_t *mss)
{
- int optlen, bits = 0;
u_char *cp = (u_char *)(tcp + 1);
+ int optlen, bits = 0;
int x = (tcp->th_off << 2) - sizeof(struct tcphdr);
for (; x > 0; x -= optlen, cp += optlen) {
@@ -350,12 +350,13 @@ tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
}
switch (opt) {
-
default:
break;
case TCPOPT_MAXSEG:
bits |= IP_FW_TCPOPT_MSS;
+ if (mss != NULL)
+ *mss = be16dec(cp + 2);
break;
case TCPOPT_WINDOW:
@@ -370,10 +371,16 @@ tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
case TCPOPT_TIMESTAMP:
bits |= IP_FW_TCPOPT_TS;
break;
-
}
}
- return (flags_match(cmd, bits));
+ return (bits);
+}
+
+static int
+tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
+{
+
+ return (flags_match(cmd, tcpopts_parse(tcp, NULL)));
}
static int
@@ -2316,6 +2323,31 @@ do { \
TCP(ulp)->th_ack);
break;
+ case O_TCPMSS:
+ if (proto == IPPROTO_TCP &&
+ (args->f_id._flags & TH_SYN) != 0 &&
+ ulp != NULL) {
+ uint16_t mss, *p;
+ int i;
+
+ PULLUP_LEN(hlen, ulp,
+ (TCP(ulp)->th_off << 2));
+ if ((tcpopts_parse(TCP(ulp), &mss) &
+ IP_FW_TCPOPT_MSS) == 0)
+ break;
+ if (cmdlen == 1) {
+ match = (cmd->arg1 == mss);
+ break;
+ }
+ /* Otherwise we have ranges. */
+ p = ((ipfw_insn_u16 *)cmd)->ports;
+ i = cmdlen - 1;
+ for (; !match && i > 0; i--, p += 2)
+ match = (mss >= p[0] &&
+ mss <= p[1]);
+ }
+ break;
+
case O_TCPWIN:
if (proto == IPPROTO_TCP && offset == 0) {
uint16_t x;
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
index a83e75447633..297b01ca7d3d 100644
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
@@ -1176,7 +1176,9 @@ move_objects(struct ip_fw_chain *ch, ipfw_range_tlv *rt)
}
}
return (c);
-}/*
+}
+
+/*
* Changes set of given rule rannge @rt
* with each other.
*
@@ -1907,6 +1909,7 @@ check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci)
case O_IPTTL:
case O_IPLEN:
case O_TCPDATALEN:
+ case O_TCPMSS:
case O_TCPWIN:
case O_TAGGED:
if (cmdlen < 1 || cmdlen > 31)