2020-02-17 13:52:11 -08:00
|
|
|
// 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
|
|
|
|
|
2020-02-20 09:56:19 -08:00
|
|
|
/*
|
|
|
|
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
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2020-02-17 13:52:11 -08:00
|
|
|
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
|
|
|
|
}
|