From c48253e63bb73e57ded5d934afd7f7e64090492d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 9 Nov 2020 23:22:23 -0800 Subject: [PATCH] wgengine/filter: add a method to run the packet filter without a packet. The goal is to move some of the shenanigans we have elsewhere into the filter package, so that all the weird things to do with poking at the filter is in a single place, behind clean APIs. Signed-off-by: David Anderson --- wgengine/filter/filter.go | 23 +++++++++++++++++++++++ wgengine/filter/filter_test.go | 7 ++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/wgengine/filter/filter.go b/wgengine/filter/filter.go index ebd4cdc1d..ac7111788 100644 --- a/wgengine/filter/filter.go +++ b/wgengine/filter/filter.go @@ -176,6 +176,29 @@ func (f *Filter) logRateLimit(runflags RunFlags, q *packet.ParsedPacket, dir dir } } +// dummyPacket is a 20-byte slice of garbage, to pass the filter +// pre-check when evaluating synthesized packets. +var dummyPacket = []byte{ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +} + +// CheckTCP determines whether TCP traffic from srcIP to dstIP:dstPort +// is allowed. +func (f *Filter) CheckTCP(srcIP, dstIP netaddr.IP, dstPort uint16) Response { + pkt := &packet.ParsedPacket{} + pkt.Decode(dummyPacket) // initialize private fields + pkt.IPVersion = 4 + pkt.IPProto = packet.TCP + pkt.TCPFlags = packet.TCPSyn + pkt.SrcIP = packet.IP4FromNetaddr(srcIP) // TODO: IPv6 + pkt.DstIP = packet.IP4FromNetaddr(dstIP) + pkt.SrcPort = 0 + pkt.DstPort = dstPort + + return f.RunIn(pkt, 0) +} + // RunIn determines whether this node is allowed to receive q from a // Tailscale peer. func (f *Filter) RunIn(q *packet.ParsedPacket, rf RunFlags) Response { diff --git a/wgengine/filter/filter_test.go b/wgengine/filter/filter_test.go index 69646c2fc..28aa945c0 100644 --- a/wgengine/filter/filter_test.go +++ b/wgengine/filter/filter_test.go @@ -165,7 +165,12 @@ func TestFilter(t *testing.T) { } for i, test := range tests { if got, _ := acl.runIn(&test.p); test.want != got { - t.Errorf("#%d got=%v want=%v packet:%v\n", i, got, test.want, test.p) + t.Errorf("#%d runIn got=%v want=%v packet:%v", i, got, test.want, test.p) + } + if test.p.IPProto == TCP { + if got := acl.CheckTCP(test.p.SrcIP.Netaddr(), test.p.DstIP.Netaddr(), test.p.DstPort); test.want != got { + t.Errorf("#%d CheckTCP got=%v want=%v packet:%v", i, got, test.want, test.p) + } } // Update UDP state _, _ = acl.runOut(&test.p)