summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authordan <dan@FreeBSD.org>2000-06-08 15:34:51 +0000
committerdan <dan@FreeBSD.org>2000-06-08 15:34:51 +0000
commitc3897dad80cc844b7f75b8cfa53825c031d02605 (patch)
treea156e91e6ecec2e7ac6b722fecb49d451eb5515b /sys/netinet
parent31f827d91f8e4147518f8d6192a98d5196ef935a (diff)
downloadFreeBSD-src-c3897dad80cc844b7f75b8cfa53825c031d02605.zip
FreeBSD-src-c3897dad80cc844b7f75b8cfa53825c031d02605.tar.gz
Add tcpoptions to ipfw. This works much in the same way as ipoptions do.
It also squashes 99% of packet kiddie synflood orgies. For example, to rate syn packets without MSS, ipfw pipe 10 config 56Kbit/s queue 10Packets ipfw add pipe 10 tcp from any to any in setup tcpoptions !mss Submitted by: Richard A. Steenbergen <ras@e-gerbil.net>
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/ip_fw.c70
-rw-r--r--sys/netinet/ip_fw.h10
2 files changed, 80 insertions, 0 deletions
diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c
index b9245bd..4ed2b0b 100644
--- a/sys/netinet/ip_fw.c
+++ b/sys/netinet/ip_fw.c
@@ -353,6 +353,73 @@ ipopts_match(struct ip *ip, struct ip_fw *f)
return 0;
}
+static int
+tcpopts_match(struct tcphdr *tcp, struct ip_fw *f)
+{
+ register u_char *cp;
+ int opt, optlen, cnt;
+ u_char opts, nopts, nopts_sve;
+
+ cp = (u_char *)(tcp + 1);
+ cnt = (tcp->th_off << 2) - sizeof (struct tcphdr);
+ opts = f->fw_tcpopt;
+ nopts = nopts_sve = f->fw_tcpnopt;
+
+ for (; cnt > 0; cnt -= optlen, cp += optlen) {
+ opt = cp[0];
+ if (opt == TCPOPT_EOL)
+ break;
+ if (opt == TCPOPT_NOP)
+ optlen = 1;
+ else {
+ optlen = cp[1];
+ if (optlen <= 0)
+ break;
+ }
+
+
+ switch (opt) {
+
+ default:
+ break;
+
+ case TCPOPT_MAXSEG:
+ opts &= ~IP_FW_TCPOPT_MSS;
+ nopts &= ~IP_FW_TCPOPT_MSS;
+ break;
+
+ case TCPOPT_WINDOW:
+ opts &= ~IP_FW_TCPOPT_WINDOW;
+ nopts &= ~IP_FW_TCPOPT_WINDOW;
+ break;
+
+ case TCPOPT_SACK_PERMITTED:
+ case TCPOPT_SACK:
+ opts &= ~IP_FW_TCPOPT_SACK;
+ nopts &= ~IP_FW_TCPOPT_SACK;
+ break;
+
+ case TCPOPT_TIMESTAMP:
+ opts &= ~IP_FW_TCPOPT_TS;
+ nopts &= ~IP_FW_TCPOPT_TS;
+ break;
+
+ case TCPOPT_CC:
+ case TCPOPT_CCNEW:
+ case TCPOPT_CCECHO:
+ opts &= ~IP_FW_TCPOPT_CC;
+ nopts &= ~IP_FW_TCPOPT_CC;
+ break;
+ }
+ if (opts == nopts)
+ break;
+ }
+ if (opts == 0 && nopts == nopts_sve)
+ return 1;
+ else
+ return 0;
+}
+
static __inline int
iface_match(struct ifnet *ifp, union ip_fw_if *ifu, int byname)
{
@@ -1143,6 +1210,9 @@ again:
break;
}
tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl);
+
+ if (f->fw_tcpopt != f->fw_tcpnopt && !tcpopts_match(tcp, f))
+ continue;
if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f))
continue;
goto check_ports;
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
index 9467624..78fd18d 100644
--- a/sys/netinet/ip_fw.h
+++ b/sys/netinet/ip_fw.h
@@ -64,6 +64,7 @@ struct ip_fw {
unsigned fw_icmptypes[IP_FW_ICMPTYPES_DIM]; /* ICMP types bitmap */
} fw_uar;
u_char fw_ipopt,fw_ipnopt; /* IP options set/unset */
+ u_char fw_tcpopt,fw_tcpnopt; /* TCP options set/unset */
u_char fw_tcpf,fw_tcpnf; /* TCP flags set/unset */
long timestamp; /* timestamp (tv_sec) of last match */
union ip_fw_if fw_in_if, fw_out_if; /* Incoming and outgoing interfaces */
@@ -230,6 +231,15 @@ struct ipfw_dyn_rule {
#define IP_FW_IPOPT_TS 0x08
/*
+ * Definitions for TCP option names.
+ */
+#define IP_FW_TCPOPT_MSS 0x01
+#define IP_FW_TCPOPT_WINDOW 0x02
+#define IP_FW_TCPOPT_SACK 0x04
+#define IP_FW_TCPOPT_TS 0x08
+#define IP_FW_TCPOPT_CC 0x10
+
+/*
* Definitions for TCP flags.
*/
#define IP_FW_TCPF_FIN TH_FIN
OpenPOWER on IntegriCloud