You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tailscale/derp/derp.go

101 lines
2.6 KiB
Go

// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package derp implements DERP, the Detour Encrypted Routing Protocol.
//
// DERP routes packets to clients using curve25519 keys as addresses.
//
// DERP is used by Tailscale nodes to proxy encrypted WireGuard
// packets through the Tailscale cloud servers when a direct path
// cannot be found or opened. DERP is a last resort. Both sides
// between very aggressive NATs, firewalls, no IPv6, etc? Well, DERP.
package derp
import (
"bufio"
"encoding/binary"
"fmt"
"io"
"time"
)
// magic is the derp magic number, sent on the wire as a uint32.
// It's "DERP" with a non-ASCII high-bit.
const magic = 0x44c55250
// frameType is the one byte frame type header in frame headers.
type frameType byte
/*
Protocol flow:
Login:
* client connects
* server sends magic: [be_uint32(magic)]
* server sends typeServerKey frame: 1 byte typeServerKey + 32 bytes of public key
* client sends: (with no frameType)
- 32 bytes client public key
- 24 bytes nonce
- be_uint32 length of naclbox (capped at 256k)
- that many bytes of naclbox
* (server verifies client is authorized)
* server sends typeServerInfo frame byte + 24 byte nonce + beu32 len + naclbox(json)
Steady state:
* server occasionally sends typeKeepAlive. (One byte only)
* client sends typeSendPacket byte + 32 byte dest pub key + beu32 packet len + packet bytes
* server then sends typeRecvPacket byte + beu32 packet len + packet bytes to recipient conn
TODO(bradfitz): require pings to be acknowledged; copy http2 PING frame w/ ping payload
*/
const (
typeServerKey = frameType(0x01)
typeServerInfo = frameType(0x02)
typeSendPacket = frameType(0x03)
typeRecvPacket = frameType(0x04)
typeKeepAlive = frameType(0x05)
)
func (b frameType) Write(w io.ByteWriter) error {
return w.WriteByte(byte(b))
}
const keepAlive = 60 * time.Second
var bin = binary.BigEndian
const oneMB = 1 << 20
func readType(r *bufio.Reader, t frameType) error {
packetType, err := r.ReadByte()
if err != nil {
return err
}
if frameType(packetType) != t {
return fmt.Errorf("bad packet type 0x%X, want 0x%X", packetType, t)
}
return nil
}
func putUint32(w io.Writer, v uint32) error {
var b [4]byte
bin.PutUint32(b[:], v)
_, err := w.Write(b[:])
return err
}
func readUint32(r io.Reader, maxVal uint32) (uint32, error) {
b := make([]byte, 4)
if _, err := io.ReadFull(r, b); err != nil {
return 0, err
}
val := bin.Uint32(b)
if val > maxVal {
return 0, fmt.Errorf("uint32 %d exceeds limit %d", val, maxVal)
}
return val, nil
}