derp, cmd/derper: add rate limiting support, add default 5Mbps limit

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2020-02-20 15:14:24 -08:00
committed by Dave Anderson
parent 1166c34f6c
commit 88f1cc0c98
6 changed files with 38 additions and 12 deletions
+5 -4
View File
@@ -27,10 +27,11 @@ import (
const magic = "DERP🔑" // 8 bytes: 0x44 45 52 50 f0 9f 94 91
const (
nonceLen = 24
keyLen = 32
maxInfoLen = 1 << 20
keepAlive = 60 * time.Second
nonceLen = 24
keyLen = 32
maxInfoLen = 1 << 20
keepAlive = 60 * time.Second
maxPacketData = 64 << 10
)
// frameType is the one byte frame type at the beginning of the frame
+1 -1
View File
@@ -131,7 +131,7 @@ func (c *Client) send(dstKey key.Public, pkt []byte) (ret error) {
}
}()
if len(pkt) > 64<<10 {
if len(pkt) > maxPacketData {
return fmt.Errorf("packet too big: %d", len(pkt))
}
+21 -3
View File
@@ -21,12 +21,17 @@ import (
"time"
"golang.org/x/crypto/nacl/box"
"golang.org/x/time/rate"
"tailscale.com/types/key"
"tailscale.com/types/logger"
)
// Server is a DERP server.
type Server struct {
// BytesPerSecond, if non-zero, specifies how many bytes per
// second to cap per-client reads at.
BytesPerSecond int
privateKey key.Private
publicKey key.Public
logf logger.Logf
@@ -179,6 +184,13 @@ func (s *Server) accept(nc net.Conn, brw *bufio.ReadWriter) error {
defer cancel()
go s.sendClientKeepAlives(ctx, c)
lim := rate.Inf
if s.BytesPerSecond != 0 {
lim = rate.Limit(s.BytesPerSecond)
}
const burstBytes = 1 << 20 // generous bandwidth delay product? must be over 64k max packet size.
limiter := rate.NewLimiter(lim, burstBytes)
for {
ft, fl, err := readFrameHeader(c.br)
if err != nil {
@@ -188,8 +200,7 @@ func (s *Server) accept(nc net.Conn, brw *bufio.ReadWriter) error {
// TODO: nothing else yet supported
return fmt.Errorf("client %x: unsupported frame %v", c.key, ft)
}
dstKey, contents, err := s.recvPacket(c.br, fl)
dstKey, contents, err := s.recvPacket(ctx, c.br, fl, limiter)
if err != nil {
return fmt.Errorf("client %x: recvPacket: %v", c.key, err)
}
@@ -229,6 +240,7 @@ func (s *Server) sendClientKeepAlives(ctx context.Context, c *sclient) {
func (s *Server) verifyClient(clientKey key.Public, info *sclientInfo) error {
// TODO(crawshaw): implement policy constraints on who can use the DERP server
// TODO(bradfitz): ... and at what rate.
return nil
}
@@ -308,7 +320,7 @@ func (s *Server) sendPacket(bw *bufio.Writer, srcKey key.Public, contents []byte
return bw.Flush()
}
func (s *Server) recvPacket(br *bufio.Reader, frameLen uint32) (dstKey key.Public, contents []byte, err error) {
func (s *Server) recvPacket(ctx context.Context, br *bufio.Reader, frameLen uint32, limiter *rate.Limiter) (dstKey key.Public, contents []byte, err error) {
if frameLen < keyLen {
return key.Public{}, nil, errors.New("short send packet frame")
}
@@ -316,6 +328,12 @@ func (s *Server) recvPacket(br *bufio.Reader, frameLen uint32) (dstKey key.Publi
return key.Public{}, nil, err
}
packetLen := frameLen - keyLen
if packetLen > maxPacketData {
return key.Public{}, nil, fmt.Errorf("data packet longer (%d) than max of %v", packetLen, maxPacketData)
}
if err := limiter.WaitN(ctx, int(packetLen)); err != nil {
return key.Public{}, nil, fmt.Errorf("rate limit: %v", err)
}
contents = make([]byte, packetLen)
if _, err := io.ReadFull(br, contents); err != nil {
return key.Public{}, nil, err