mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
net/netcheck: do PCP discovery without side effects
Manually cherry-picked subset of c64bd587ae
back into the 1.4 branch.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
3b9fcc2b81
commit
1aeeeb7e45
@ -8,9 +8,7 @@
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -701,16 +699,14 @@ func (rs *reportState) probePortMapServices() {
|
||||
return
|
||||
}
|
||||
defer uc.Close()
|
||||
tempPort := uc.LocalAddr().(*net.UDPAddr).Port
|
||||
uc.SetReadDeadline(time.Now().Add(portMapServiceProbeTimeout))
|
||||
|
||||
// Send request packets for all three protocols.
|
||||
uc.WriteTo(uPnPPacket, port1900)
|
||||
uc.WriteTo(pmpPacket, port5351)
|
||||
uc.WriteTo(pcpPacket(myIP, tempPort, false), port5351)
|
||||
uc.WriteTo(pcpAnnounceRequest(myIP), port5351)
|
||||
|
||||
res := make([]byte, 1500)
|
||||
sentPCPDelete := false
|
||||
for {
|
||||
n, addr, err := uc.ReadFrom(res)
|
||||
if err != nil {
|
||||
@ -725,17 +721,8 @@ func (rs *reportState) probePortMapServices() {
|
||||
if n == 12 && res[0] == 0x00 { // right length and version 0
|
||||
rs.setOptBool(&rs.report.PMP, true)
|
||||
}
|
||||
if n == 60 && res[0] == 0x02 { // right length and version 2
|
||||
if n == 24 && res[0] == 0x02 { // right length and version 2
|
||||
rs.setOptBool(&rs.report.PCP, true)
|
||||
|
||||
if !sentPCPDelete {
|
||||
sentPCPDelete = true
|
||||
// And now delete the mapping.
|
||||
// (PCP is the only protocol of the three that requires
|
||||
// we cause a side effect to detect whether it's present,
|
||||
// so we need to redo that side effect now.)
|
||||
uc.WriteTo(pcpPacket(myIP, tempPort, true), port5351)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -751,32 +738,19 @@ func (rs *reportState) probePortMapServices() {
|
||||
|
||||
var v4unspec, _ = netaddr.ParseIP("0.0.0.0")
|
||||
|
||||
// pcpPacket generates a PCP packet with a MAP opcode.
|
||||
func pcpPacket(myIP netaddr.IP, mapToLocalPort int, delete bool) []byte {
|
||||
const udpProtoNumber = 17
|
||||
lifetimeSeconds := uint32(1)
|
||||
if delete {
|
||||
lifetimeSeconds = 0
|
||||
}
|
||||
const opMap = 1
|
||||
const (
|
||||
pcpVersion = 2
|
||||
pcpOpAnnounce = 0
|
||||
)
|
||||
|
||||
// 24 byte header + 36 byte map opcode
|
||||
pkt := make([]byte, (32+32+128)/8+(96+8+24+16+16+128)/8)
|
||||
|
||||
// The header (https://tools.ietf.org/html/rfc6887#section-7.1)
|
||||
pkt[0] = 2 // version
|
||||
pkt[1] = opMap
|
||||
binary.BigEndian.PutUint32(pkt[4:8], lifetimeSeconds)
|
||||
// pcpAnnounceRequest generates a PCP packet with an ANNOUNCE opcode.
|
||||
func pcpAnnounceRequest(myIP netaddr.IP) []byte {
|
||||
// See https://tools.ietf.org/html/rfc6887#section-7.1
|
||||
pkt := make([]byte, 24)
|
||||
pkt[0] = pcpVersion // version
|
||||
pkt[1] = pcpOpAnnounce
|
||||
myIP16 := myIP.As16()
|
||||
copy(pkt[8:], myIP16[:])
|
||||
|
||||
// The map opcode body (https://tools.ietf.org/html/rfc6887#section-11.1)
|
||||
mapOp := pkt[24:]
|
||||
rand.Read(mapOp[:12]) // 96 bit mappping nonce
|
||||
mapOp[12] = udpProtoNumber
|
||||
binary.BigEndian.PutUint16(mapOp[16:], uint16(mapToLocalPort))
|
||||
v4unspec16 := v4unspec.As16()
|
||||
copy(mapOp[20:], v4unspec16[:])
|
||||
return pkt
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user