net/packet, wgengine/{filter,tstun}: add TSMP ping

Fixes #1467

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2021-03-23 15:16:15 -07:00
committed by Brad Fitzpatrick
parent 4b77eca2de
commit 2384c112c9
13 changed files with 247 additions and 18 deletions

View File

@@ -109,6 +109,9 @@ type TUN struct {
// PostFilterOut is the outbound filter function that runs after the main filter.
PostFilterOut FilterFunc
// OnTSMPPongReceived, if non-nil, is called whenever a TSMP pong arrives.
OnTSMPPongReceived func(data [8]byte)
// disableFilter disables all filtering when set. This should only be used in tests.
disableFilter bool
}
@@ -323,6 +326,18 @@ func (t *TUN) filterIn(buf []byte) filter.Response {
defer parsedPacketPool.Put(p)
p.Decode(buf)
if p.IPProto == ipproto.TSMP {
if pingReq, ok := p.AsTSMPPing(); ok {
t.noteActivity()
t.injectOutboundPong(p, pingReq)
return filter.DropSilently
} else if data, ok := p.AsTSMPPong(); ok {
if f := t.OnTSMPPongReceived; f != nil {
f(data)
}
}
}
if t.PreFilterIn != nil {
if res := t.PreFilterIn(p, t); res.IsDrop() {
return res
@@ -440,6 +455,26 @@ func (t *TUN) InjectInboundCopy(packet []byte) error {
return t.InjectInboundDirect(buf, PacketStartOffset)
}
func (t *TUN) injectOutboundPong(pp *packet.Parsed, req packet.TSMPPingRequest) {
pong := packet.TSMPPongReply{
Data: req.Data,
}
switch pp.IPVersion {
case 4:
h4 := pp.IP4Header()
h4.ToResponse()
pong.IPHeader = h4
case 6:
h6 := pp.IP6Header()
h6.ToResponse()
pong.IPHeader = h6
default:
return
}
t.InjectOutbound(packet.Generate(pong, nil))
}
// InjectOutbound makes the TUN device behave as if a packet
// with the given contents was sent to the network.
// It does not block, but takes ownership of the packet.