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>
This commit is contained in:
parent
afb87ed2fd
commit
9714563d83
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=61420
@ -650,6 +650,25 @@ The supported IP options are:
|
||||
The absence of a particular option may be denoted
|
||||
with a
|
||||
.Ql ! .
|
||||
.It Cm tcpoptions Ar spec
|
||||
Match if the TCP header contains the comma separated list of
|
||||
options specified in
|
||||
.Ar spec .
|
||||
The supported TCP options are:
|
||||
.Pp
|
||||
.Cm mss
|
||||
(maximum segment size),
|
||||
.Cm window
|
||||
(tcp window advertisement),
|
||||
.Cm sack
|
||||
(selective ack),
|
||||
.Cm ts
|
||||
(rfc1323 timestamp) and
|
||||
.Cm cc
|
||||
(rfc1644 t/tcp connection count).
|
||||
The absence of a particular option may be denoted
|
||||
with a
|
||||
.Ql ! .
|
||||
.It Cm established
|
||||
TCP packets only.
|
||||
Match packets that have the RST or ACK bits set.
|
||||
|
@ -437,7 +437,7 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth)
|
||||
#define PRINTFLG(x) {if (_flg_printed) printf(",");\
|
||||
printf(x); _flg_printed = 1;}
|
||||
|
||||
printf(" tcpflg ");
|
||||
printf(" tcpflags ");
|
||||
if (chain->fw_tcpf & IP_FW_TCPF_FIN) PRINTFLG("fin");
|
||||
if (chain->fw_tcpnf & IP_FW_TCPF_FIN) PRINTFLG("!fin");
|
||||
if (chain->fw_tcpf & IP_FW_TCPF_SYN) PRINTFLG("syn");
|
||||
@ -451,6 +451,24 @@ show_ipfw(struct ip_fw *chain, int pcwidth, int bcwidth)
|
||||
if (chain->fw_tcpf & IP_FW_TCPF_URG) PRINTFLG("urg");
|
||||
if (chain->fw_tcpnf & IP_FW_TCPF_URG) PRINTFLG("!urg");
|
||||
}
|
||||
if (chain->fw_tcpopt || chain->fw_tcpnopt) {
|
||||
int _opt_printed = 0;
|
||||
#define PRINTTOPT(x) {if (_opt_printed) printf(",");\
|
||||
printf(x); _opt_printed = 1;}
|
||||
|
||||
printf(" tcpoptions ");
|
||||
if (chain->fw_tcpopt & IP_FW_TCPOPT_MSS) PRINTTOPT("mss");
|
||||
if (chain->fw_tcpnopt & IP_FW_TCPOPT_MSS) PRINTTOPT("!mss");
|
||||
if (chain->fw_tcpopt & IP_FW_TCPOPT_WINDOW) PRINTTOPT("window");
|
||||
if (chain->fw_tcpnopt & IP_FW_TCPOPT_WINDOW) PRINTTOPT("!window");
|
||||
if (chain->fw_tcpopt & IP_FW_TCPOPT_SACK) PRINTTOPT("sack");
|
||||
if (chain->fw_tcpnopt & IP_FW_TCPOPT_SACK) PRINTTOPT("!sack");
|
||||
if (chain->fw_tcpopt & IP_FW_TCPOPT_TS) PRINTTOPT("ts");
|
||||
if (chain->fw_tcpnopt & IP_FW_TCPOPT_TS) PRINTTOPT("!ts");
|
||||
if (chain->fw_tcpopt & IP_FW_TCPOPT_CC) PRINTTOPT("cc");
|
||||
if (chain->fw_tcpnopt & IP_FW_TCPOPT_CC) PRINTTOPT("!cc");
|
||||
}
|
||||
|
||||
if (chain->fw_flg & IP_FW_F_ICMPBIT) {
|
||||
int type_index;
|
||||
int first = 1;
|
||||
@ -818,6 +836,7 @@ show_usage(const char *fmt, ...)
|
||||
" {established|setup}\n"
|
||||
" tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n"
|
||||
" ipoptions [!]{ssrr|lsrr|rr|ts},...\n"
|
||||
" tcpoptions [!]{mss|window|sack|ts|cc},...\n"
|
||||
" icmptypes {type[,type]}...\n"
|
||||
" pipeconfig:\n"
|
||||
" {bw|bandwidth} <number>{bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n"
|
||||
@ -1025,9 +1044,7 @@ fill_port(cnt, ptr, off, arg)
|
||||
}
|
||||
|
||||
static void
|
||||
fill_tcpflag(set, reset, vp)
|
||||
u_char *set, *reset;
|
||||
char **vp;
|
||||
fill_tcpflag(u_char *set, u_char *reset, char **vp)
|
||||
{
|
||||
char *p = *vp,*q;
|
||||
u_char *d;
|
||||
@ -1066,6 +1083,45 @@ fill_tcpflag(set, reset, vp)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fill_tcpopts(u_char *set, u_char *reset, char **vp)
|
||||
{
|
||||
char *p = *vp,*q;
|
||||
u_char *d;
|
||||
|
||||
while (p && *p) {
|
||||
struct tpcopts {
|
||||
char * name;
|
||||
u_char value;
|
||||
} opts[] = {
|
||||
{ "mss", IP_FW_TCPOPT_MSS },
|
||||
{ "window", IP_FW_TCPOPT_WINDOW },
|
||||
{ "sack", IP_FW_TCPOPT_SACK },
|
||||
{ "ts", IP_FW_TCPOPT_TS },
|
||||
{ "cc", IP_FW_TCPOPT_CC },
|
||||
};
|
||||
int i;
|
||||
|
||||
if (*p == '!') {
|
||||
p++;
|
||||
d = reset;
|
||||
} else {
|
||||
d = set;
|
||||
}
|
||||
q = strchr(p, ',');
|
||||
if (q)
|
||||
*q++ = '\0';
|
||||
for (i = 0; i < sizeof(opts) / sizeof(opts[0]); ++i)
|
||||
if (!strncmp(p, opts[i].name, strlen(p))) {
|
||||
*d |= opts[i].value;
|
||||
break;
|
||||
}
|
||||
if (i == sizeof(opts) / sizeof(opts[0]))
|
||||
show_usage("invalid tcp option ``%s''", p);
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fill_ipopt(u_char *set, u_char *reset, char **vp)
|
||||
{
|
||||
@ -1839,7 +1895,7 @@ add(ac,av)
|
||||
rule.fw_tcpnf |= IP_FW_TCPF_ACK;
|
||||
av++; ac--; continue;
|
||||
}
|
||||
if (!strncmp(*av,"tcpflags",strlen(*av))) {
|
||||
if (!strncmp(*av,"tcpflags",strlen(*av)) || !strncmp(*av,"tcpflgs",strlen(*av))) {
|
||||
av++; ac--;
|
||||
if (!ac)
|
||||
show_usage("missing argument"
|
||||
@ -1847,6 +1903,14 @@ add(ac,av)
|
||||
fill_tcpflag(&rule.fw_tcpf, &rule.fw_tcpnf, av);
|
||||
av++; ac--; continue;
|
||||
}
|
||||
if (!strncmp(*av,"tcpoptions",strlen(*av)) || !strncmp(*av, "tcpopts",strlen(*av))) {
|
||||
av++; ac--;
|
||||
if (!ac)
|
||||
show_usage("missing argument"
|
||||
" for ``tcpflags''");
|
||||
fill_tcpopts(&rule.fw_tcpopt, &rule.fw_tcpnopt, av);
|
||||
av++; ac--; continue;
|
||||
}
|
||||
}
|
||||
if (rule.fw_prot == IPPROTO_ICMP) {
|
||||
if (!strncmp(*av,"icmptypes",strlen(*av))) {
|
||||
|
@ -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 @@ ip_fw_chk(struct ip **pip, int hlen,
|
||||
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;
|
||||
|
@ -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 */
|
||||
@ -229,6 +230,15 @@ struct ipfw_dyn_rule {
|
||||
#define IP_FW_IPOPT_RR 0x04
|
||||
#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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user