From 2e8e0daa0ac8a6a123893b27fb1de566768383d0 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Mon, 22 Oct 2018 18:42:09 +0200 Subject: [PATCH] implement TCP MSS clamping (for non-ethernet uplinks) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- integration/netconfig/netconfig_test.go | 4 ++ internal/netconfig/netconfig.go | 68 +++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/integration/netconfig/netconfig_test.go b/integration/netconfig/netconfig_test.go index 4981874..28a7e58 100644 --- a/integration/netconfig/netconfig_test.go +++ b/integration/netconfig/netconfig_test.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`, ` }`, `}`, } diff --git a/internal/netconfig/netconfig.go b/internal/netconfig/netconfig.go index 1e28553..093606a 100644 --- a/internal/netconfig/netconfig.go +++ b/internal/netconfig/netconfig.go @@ -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",