implement TCP MSS clamping (for non-ethernet uplinks)

We didn’t have a need to clamp the TCP Maximum Segment Size (MSS) up until now,
because fiber7 uses an MTU of 1500.

Because Path MTU discovery is often broken on the internet, it’s best practice
to limit the Maximum Segment Size (MSS) of each TCP connection, achieving the
same effect (but only for TCP connections).

This change is beneficial when running router7 behind a non-ethernet uplink,
such as a Fritz!Box cable modem.

This has no adverse effect on fiber7: after clamping, the MSS is still 1440, as
without clamping.
This commit is contained in:
Michael Stapelberg 2018-10-22 18:42:09 +02:00
parent c037bf9c5f
commit 2e8e0daa0a
2 changed files with 72 additions and 0 deletions

View File

@ -287,6 +287,7 @@ func TestNetconfig(t *testing.T) {
` chain forward {`, ` chain forward {`,
` type filter hook forward priority 0; policy accept;`, ` type filter hook forward priority 0; policy accept;`,
` counter name "fwded"`, ` counter name "fwded"`,
` oifname "uplink0" tcp flags syn tcp option maxseg size set rt mtu`,
` }`, ` }`,
`}`, `}`,
`table ip6 filter {`, `table ip6 filter {`,
@ -297,6 +298,7 @@ func TestNetconfig(t *testing.T) {
` chain forward {`, ` chain forward {`,
` type filter hook forward priority 0; policy accept;`, ` type filter hook forward priority 0; policy accept;`,
` counter name "fwded"`, ` counter name "fwded"`,
` oifname "uplink0" tcp flags syn tcp option maxseg size set rt mtu`,
` }`, ` }`,
`}`, `}`,
} }
@ -352,6 +354,7 @@ func TestNetconfig(t *testing.T) {
` chain forward {`, ` chain forward {`,
` type filter hook forward priority 0; policy accept;`, ` type filter hook forward priority 0; policy accept;`,
` counter name "fwded"`, ` counter name "fwded"`,
` oifname "uplink0" tcp flags syn tcp option maxseg size set rt mtu`,
` }`, ` }`,
`}`, `}`,
`table ip6 filter {`, `table ip6 filter {`,
@ -362,6 +365,7 @@ func TestNetconfig(t *testing.T) {
` chain forward {`, ` chain forward {`,
` type filter hook forward priority 0; policy accept;`, ` type filter hook forward priority 0; policy accept;`,
` counter name "fwded"`, ` counter name "fwded"`,
` oifname "uplink0" tcp flags syn tcp option maxseg size set rt mtu`,
` }`, ` }`,
`}`, `}`,
} }

View File

@ -576,6 +576,74 @@ func applyFirewall(dir string) error {
Type: nftables.ChainTypeFilter, Type: nftables.ChainTypeFilter,
}) })
c.AddRule(&nftables.Rule{
Table: filter,
Chain: forward,
Exprs: []expr.Any{
// [ meta load oifname => reg 1 ]
&expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},
// [ cmp eq reg 1 0x30707070 0x00000000 0x00000000 0x00000000 ]
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: ifname("uplink0"),
},
// [ meta load l4proto => reg 1 ]
&expr.Meta{Key: expr.MetaKeyL4PROTO, Register: 1},
// [ cmp eq reg 1 0x00000006 ]
&expr.Cmp{
Op: expr.CmpOpEq,
Register: 1,
Data: []byte{unix.IPPROTO_TCP},
},
// [ payload load 1b @ transport header + 13 => reg 1 ]
&expr.Payload{
DestRegister: 1,
Base: expr.PayloadBaseTransportHeader,
Offset: 13, // TODO
Len: 1, // TODO
},
// [ bitwise reg 1 = (reg=1 & 0x00000002 ) ^ 0x00000000 ]
&expr.Bitwise{
DestRegister: 1,
SourceRegister: 1,
Len: 1,
Mask: []byte{0x02},
Xor: []byte{0x00},
},
// [ cmp neq reg 1 0x00000000 ]
&expr.Cmp{
Op: expr.CmpOpNeq,
Register: 1,
Data: []byte{0x00},
},
// [ rt load tcpmss => reg 1 ]
&expr.Rt{
Register: 1,
Key: expr.RtTCPMSS,
},
// [ byteorder reg 1 = hton(reg 1, 2, 2) ]
&expr.Byteorder{
DestRegister: 1,
SourceRegister: 1,
Op: expr.ByteorderHton,
Len: 2,
Size: 2,
},
// [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
&expr.Exthdr{
SourceRegister: 1,
Type: 2, // TODO
Offset: 2,
Len: 2,
Op: expr.ExthdrOpTcpopt,
},
},
})
counterObj := getCounterObj(c, &nftables.CounterObj{ counterObj := getCounterObj(c, &nftables.CounterObj{
Table: filter, Table: filter,
Name: "fwded", Name: "fwded",