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 @@ type InOut struct { } 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)