Permalink
Browse files

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.
  • Loading branch information...
stapelberg committed Oct 22, 2018
1 parent c037bf9 commit 2e8e0daa0ac8a6a123893b27fb1de566768383d0
Showing with 72 additions and 0 deletions.
  1. +4 −0 integration/netconfig/netconfig_test.go
  2. +68 −0 internal/netconfig/netconfig.go
@@ -287,6 +287,7 @@ func TestNetconfig(t *testing.T) {
` chain forward {`,
` type filter hook forward priority 0; policy accept;`,
` counter name "fwded"`,
` oifname "uplink0" tcp flags syn tcp option maxseg size set rt mtu`,
` }`,
`}`,
`table ip6 filter {`,
@@ -297,6 +298,7 @@ func TestNetconfig(t *testing.T) {
` chain forward {`,
` type filter hook forward priority 0; policy accept;`,
` 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 {`,
` type filter hook forward priority 0; policy accept;`,
` counter name "fwded"`,
` oifname "uplink0" tcp flags syn tcp option maxseg size set rt mtu`,
` }`,
`}`,
`table ip6 filter {`,
@@ -362,6 +365,7 @@ func TestNetconfig(t *testing.T) {
` chain forward {`,
` type filter hook forward priority 0; policy accept;`,
` counter name "fwded"`,
` oifname "uplink0" tcp flags syn tcp option maxseg size set rt mtu`,
` }`,
`}`,
}
@@ -576,6 +576,74 @@ func applyFirewall(dir string) error {
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{
Table: filter,
Name: "fwded",

0 comments on commit 2e8e0da

Please sign in to comment.