| 
									
										
										
										
											2020-02-05 14:16:58 -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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bufio" | 
					
						
							| 
									
										
										
										
											2020-02-17 13:17:40 -08:00
										 |  |  | 	crand "crypto/rand" | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2020-03-05 15:00:56 -08:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"golang.org/x/crypto/nacl/box" | 
					
						
							| 
									
										
										
										
											2020-02-17 13:17:40 -08:00
										 |  |  | 	"tailscale.com/types/key" | 
					
						
							| 
									
										
										
										
											2020-02-14 19:23:16 -08:00
										 |  |  | 	"tailscale.com/types/logger" | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 14:42:20 -07:00
										 |  |  | // Client is a DERP client. | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | type Client struct { | 
					
						
							| 
									
										
										
										
											2020-08-17 16:14:07 -07:00
										 |  |  | 	serverKey  key.Public // of the DERP server; not a machine or node key | 
					
						
							|  |  |  | 	privateKey key.Private | 
					
						
							|  |  |  | 	publicKey  key.Public // of privateKey | 
					
						
							|  |  |  | 	logf       logger.Logf | 
					
						
							|  |  |  | 	nc         Conn | 
					
						
							|  |  |  | 	br         *bufio.Reader | 
					
						
							|  |  |  | 	meshKey    string | 
					
						
							| 
									
										
										
										
											2020-03-05 15:00:56 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-15 10:26:50 -07:00
										 |  |  | 	wmu sync.Mutex // hold while writing to bw | 
					
						
							|  |  |  | 	bw  *bufio.Writer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Owned by Recv: | 
					
						
							|  |  |  | 	peeked  int   // bytes to discard on next Recv | 
					
						
							| 
									
										
										
										
											2020-03-05 15:00:56 -08:00
										 |  |  | 	readErr error // sticky read error | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 11:40:12 -07:00
										 |  |  | // ClientOpt is an option passed to NewClient. | 
					
						
							|  |  |  | type ClientOpt interface { | 
					
						
							|  |  |  | 	update(*clientOpt) | 
					
						
							| 
									
										
										
										
											2020-06-01 15:19:41 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 11:40:12 -07:00
										 |  |  | type clientOptFunc func(*clientOpt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (f clientOptFunc) update(o *clientOpt) { f(o) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // clientOpt are the options passed to newClient. | 
					
						
							|  |  |  | type clientOpt struct { | 
					
						
							| 
									
										
										
										
											2020-08-18 15:32:32 -07:00
										 |  |  | 	MeshKey   string | 
					
						
							|  |  |  | 	ServerPub key.Public | 
					
						
							| 
									
										
										
										
											2020-06-04 11:40:12 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MeshKey returns a ClientOpt to pass to the DERP server during connect to get | 
					
						
							|  |  |  | // access to join the mesh. | 
					
						
							| 
									
										
										
										
											2020-06-01 15:19:41 -07:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2020-06-04 11:40:12 -07:00
										 |  |  | // An empty key means to not use a mesh key. | 
					
						
							|  |  |  | func MeshKey(key string) ClientOpt { return clientOptFunc(func(o *clientOpt) { o.MeshKey = key }) } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-18 15:32:32 -07:00
										 |  |  | // ServerPublicKey returns a ClientOpt to declare that the server's DERP public key is known. | 
					
						
							|  |  |  | // If key is the zero value, the returned ClientOpt is a no-op. | 
					
						
							|  |  |  | func ServerPublicKey(key key.Public) ClientOpt { | 
					
						
							|  |  |  | 	return clientOptFunc(func(o *clientOpt) { o.ServerPub = key }) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 11:40:12 -07:00
										 |  |  | func NewClient(privateKey key.Private, nc Conn, brw *bufio.ReadWriter, logf logger.Logf, opts ...ClientOpt) (*Client, error) { | 
					
						
							|  |  |  | 	var opt clientOpt | 
					
						
							|  |  |  | 	for _, o := range opts { | 
					
						
							|  |  |  | 		if o == nil { | 
					
						
							|  |  |  | 			return nil, errors.New("nil ClientOpt") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		o.update(&opt) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return newClient(privateKey, nc, brw, logf, opt) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newClient(privateKey key.Private, nc Conn, brw *bufio.ReadWriter, logf logger.Logf, opt clientOpt) (*Client, error) { | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	c := &Client{ | 
					
						
							|  |  |  | 		privateKey: privateKey, | 
					
						
							| 
									
										
										
										
											2020-02-17 13:17:40 -08:00
										 |  |  | 		publicKey:  privateKey.Public(), | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		logf:       logf, | 
					
						
							| 
									
										
										
										
											2020-02-20 09:11:43 -08:00
										 |  |  | 		nc:         nc, | 
					
						
							|  |  |  | 		br:         brw.Reader, | 
					
						
							|  |  |  | 		bw:         brw.Writer, | 
					
						
							| 
									
										
										
										
											2020-06-04 11:40:12 -07:00
										 |  |  | 		meshKey:    opt.MeshKey, | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-18 15:32:32 -07:00
										 |  |  | 	if opt.ServerPub.IsZero() { | 
					
						
							|  |  |  | 		if err := c.recvServerKey(); err != nil { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("derp.Client: failed to receive server key: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		c.serverKey = opt.ServerPub | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if err := c.sendClientKey(); err != nil { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("derp.Client: failed to send client key: %v", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return c, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *Client) recvServerKey() error { | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	var buf [40]byte | 
					
						
							|  |  |  | 	t, flen, err := readFrame(c.br, 1<<10, buf[:]) | 
					
						
							|  |  |  | 	if err == io.ErrShortBuffer { | 
					
						
							|  |  |  | 		// For future-proofing, allow server to send more in its greeting. | 
					
						
							|  |  |  | 		err = nil | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	if flen < uint32(len(buf)) || t != frameServerKey || string(buf[:len(magic)]) != magic { | 
					
						
							|  |  |  | 		return errors.New("invalid server greeting") | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	copy(c.serverKey[:], buf[len(magic):]) | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 16:14:07 -07:00
										 |  |  | func (c *Client) parseServerInfo(b []byte) (*serverInfo, error) { | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	const maxLength = nonceLen + maxInfoLen | 
					
						
							| 
									
										
										
										
											2020-08-17 16:14:07 -07:00
										 |  |  | 	fl := len(b) | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	if fl < nonceLen { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("short serverInfo frame") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if fl > maxLength { | 
					
						
							|  |  |  | 		return nil, fmt.Errorf("long serverInfo frame") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// TODO: add a read-nonce-and-box helper | 
					
						
							|  |  |  | 	var nonce [nonceLen]byte | 
					
						
							| 
									
										
										
										
											2020-08-17 16:14:07 -07:00
										 |  |  | 	copy(nonce[:], b) | 
					
						
							|  |  |  | 	msgbox := b[nonceLen:] | 
					
						
							| 
									
										
										
										
											2020-02-17 13:17:40 -08:00
										 |  |  | 	msg, ok := box.Open(nil, msgbox, &nonce, c.serverKey.B32(), c.privateKey.B32()) | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2020-08-17 16:14:07 -07:00
										 |  |  | 		return nil, fmt.Errorf("failed to open naclbox from server key %x", c.serverKey[:]) | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	info := new(serverInfo) | 
					
						
							|  |  |  | 	if err := json.Unmarshal(msg, info); err != nil { | 
					
						
							| 
									
										
										
										
											2020-08-17 16:14:07 -07:00
										 |  |  | 		return nil, fmt.Errorf("invalid JSON: %v", err) | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return info, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-04 09:35:32 -08:00
										 |  |  | type clientInfo struct { | 
					
						
							| 
									
										
										
										
											2020-08-19 14:36:43 -07:00
										 |  |  | 	Version int `json:"version,omitempty"` | 
					
						
							| 
									
										
										
										
											2020-06-01 15:19:41 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// MeshKey optionally specifies a pre-shared key used by | 
					
						
							|  |  |  | 	// trusted clients.  It's required to subscribe to the | 
					
						
							|  |  |  | 	// connection list & forward packets. It's empty for regular | 
					
						
							|  |  |  | 	// users. | 
					
						
							| 
									
										
										
										
											2020-08-19 14:36:43 -07:00
										 |  |  | 	MeshKey string `json:"meshKey,omitempty"` | 
					
						
							| 
									
										
										
										
											2020-03-04 09:35:32 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | func (c *Client) sendClientKey() error { | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	var nonce [nonceLen]byte | 
					
						
							| 
									
										
										
										
											2020-02-17 13:17:40 -08:00
										 |  |  | 	if _, err := crand.Read(nonce[:]); err != nil { | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-01 15:19:41 -07:00
										 |  |  | 	msg, err := json.Marshal(clientInfo{ | 
					
						
							| 
									
										
										
										
											2020-08-18 15:32:32 -07:00
										 |  |  | 		Version: ProtocolVersion, | 
					
						
							| 
									
										
										
										
											2020-06-01 15:19:41 -07:00
										 |  |  | 		MeshKey: c.meshKey, | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2020-03-04 09:35:32 -08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-17 13:17:40 -08:00
										 |  |  | 	msgbox := box.Seal(nil, msg, &nonce, c.serverKey.B32(), c.privateKey.B32()) | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	buf := make([]byte, 0, nonceLen+keyLen+len(msgbox)) | 
					
						
							|  |  |  | 	buf = append(buf, c.publicKey[:]...) | 
					
						
							|  |  |  | 	buf = append(buf, nonce[:]...) | 
					
						
							|  |  |  | 	buf = append(buf, msgbox...) | 
					
						
							|  |  |  | 	return writeFrame(c.bw, frameClientInfo, buf) | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 14:42:20 -07:00
										 |  |  | // ServerPublicKey returns the server's public key. | 
					
						
							|  |  |  | func (c *Client) ServerPublicKey() key.Public { return c.serverKey } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | // Send sends a packet to the Tailscale node identified by dstKey. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // It is an error if the packet is larger than 64KB. | 
					
						
							|  |  |  | func (c *Client) Send(dstKey key.Public, pkt []byte) error { return c.send(dstKey, pkt) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *Client) send(dstKey key.Public, pkt []byte) (ret error) { | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	defer func() { | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 		if ret != nil { | 
					
						
							| 
									
										
										
										
											2020-03-12 11:05:03 -04:00
										 |  |  | 			ret = fmt.Errorf("derp.Send: %w", ret) | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 19:10:54 -08:00
										 |  |  | 	if len(pkt) > MaxPacketSize { | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 		return fmt.Errorf("packet too big: %d", len(pkt)) | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-05 15:00:56 -08:00
										 |  |  | 	c.wmu.Lock() | 
					
						
							|  |  |  | 	defer c.wmu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	if err := writeFrameHeader(c.bw, frameSendPacket, uint32(len(dstKey)+len(pkt))); err != nil { | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	if _, err := c.bw.Write(dstKey[:]); err != nil { | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 	if _, err := c.bw.Write(pkt); err != nil { | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-20 09:11:43 -08:00
										 |  |  | 	return c.bw.Flush() | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-03 14:42:20 -07:00
										 |  |  | func (c *Client) ForwardPacket(srcKey, dstKey key.Public, pkt []byte) (err error) { | 
					
						
							|  |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			err = fmt.Errorf("derp.ForwardPacket: %w", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(pkt) > MaxPacketSize { | 
					
						
							|  |  |  | 		return fmt.Errorf("packet too big: %d", len(pkt)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	c.wmu.Lock() | 
					
						
							|  |  |  | 	defer c.wmu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	timer := time.AfterFunc(5*time.Second, c.writeTimeoutFired) | 
					
						
							|  |  |  | 	defer timer.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := writeFrameHeader(c.bw, frameForwardPacket, uint32(keyLen*2+len(pkt))); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err := c.bw.Write(srcKey[:]); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err := c.bw.Write(dstKey[:]); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err := c.bw.Write(pkt); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return c.bw.Flush() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *Client) writeTimeoutFired() { c.nc.Close() } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-09 12:53:02 -08:00
										 |  |  | func (c *Client) SendPong(data [8]byte) error { | 
					
						
							|  |  |  | 	c.wmu.Lock() | 
					
						
							|  |  |  | 	defer c.wmu.Unlock() | 
					
						
							|  |  |  | 	if err := writeFrameHeader(c.bw, framePong, 8); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if _, err := c.bw.Write(data[:]); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return c.bw.Flush() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-05 15:00:56 -08:00
										 |  |  | // NotePreferred sends a packet that tells the server whether this | 
					
						
							|  |  |  | // client is the user's preferred server. This is only used in the | 
					
						
							|  |  |  | // server for stats. | 
					
						
							|  |  |  | func (c *Client) NotePreferred(preferred bool) (err error) { | 
					
						
							|  |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			err = fmt.Errorf("derp.NotePreferred: %v", err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	c.wmu.Lock() | 
					
						
							|  |  |  | 	defer c.wmu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := writeFrameHeader(c.bw, frameNotePreferred, 1); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var b byte = 0x00 | 
					
						
							|  |  |  | 	if preferred { | 
					
						
							|  |  |  | 		b = 0x01 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if err := c.bw.WriteByte(b); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return c.bw.Flush() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 15:19:41 -07:00
										 |  |  | // WatchConnectionChanges sends a request to subscribe to the peer's connection list. | 
					
						
							| 
									
										
										
										
											2020-06-25 09:33:10 -07:00
										 |  |  | // It's a fatal error if the client wasn't created using MeshKey. | 
					
						
							| 
									
										
										
										
											2020-06-01 15:19:41 -07:00
										 |  |  | func (c *Client) WatchConnectionChanges() error { | 
					
						
							|  |  |  | 	c.wmu.Lock() | 
					
						
							|  |  |  | 	defer c.wmu.Unlock() | 
					
						
							|  |  |  | 	if err := writeFrameHeader(c.bw, frameWatchConns, 0); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return c.bw.Flush() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-25 09:33:10 -07:00
										 |  |  | // ClosePeer asks the server to close target's TCP connection. | 
					
						
							|  |  |  | // It's a fatal error if the client wasn't created using MeshKey. | 
					
						
							|  |  |  | func (c *Client) ClosePeer(target key.Public) error { | 
					
						
							|  |  |  | 	c.wmu.Lock() | 
					
						
							|  |  |  | 	defer c.wmu.Unlock() | 
					
						
							|  |  |  | 	return writeFrame(c.bw, frameClosePeer, target[:]) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 19:10:54 -08:00
										 |  |  | // ReceivedMessage represents a type returned by Client.Recv. Unless | 
					
						
							|  |  |  | // otherwise documented, the returned message aliases the byte slice | 
					
						
							|  |  |  | // provided to Recv and thus the message is only as good as that | 
					
						
							|  |  |  | // buffer, which is up to the caller. | 
					
						
							|  |  |  | type ReceivedMessage interface { | 
					
						
							|  |  |  | 	msg() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ReceivedPacket is a ReceivedMessage representing an incoming packet. | 
					
						
							| 
									
										
										
										
											2020-03-04 09:35:32 -08:00
										 |  |  | type ReceivedPacket struct { | 
					
						
							|  |  |  | 	Source key.Public | 
					
						
							|  |  |  | 	// Data is the received packet bytes. It aliases the memory | 
					
						
							|  |  |  | 	// passed to Client.Recv. | 
					
						
							|  |  |  | 	Data []byte | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-02-20 19:10:54 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func (ReceivedPacket) msg() {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-21 18:24:28 -07:00
										 |  |  | // PeerGoneMessage is a ReceivedMessage that indicates that the client | 
					
						
							|  |  |  | // identified by the underlying public key had previously sent you a | 
					
						
							|  |  |  | // packet but has now disconnected from the server. | 
					
						
							|  |  |  | type PeerGoneMessage key.Public | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (PeerGoneMessage) msg() {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 15:19:41 -07:00
										 |  |  | // PeerPresentMessage is a ReceivedMessage that indicates that the client | 
					
						
							|  |  |  | // is connected to the server. (Only used by trusted mesh clients) | 
					
						
							|  |  |  | type PeerPresentMessage key.Public | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (PeerPresentMessage) msg() {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-17 16:14:07 -07:00
										 |  |  | // ServerInfoMessage is sent by the server upon first connect. | 
					
						
							|  |  |  | type ServerInfoMessage struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (ServerInfoMessage) msg() {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-09 12:53:02 -08:00
										 |  |  | // PingMessage is a request from a client or server to reply to the | 
					
						
							|  |  |  | // other side with a PongMessage with the given payload. | 
					
						
							|  |  |  | type PingMessage [8]byte | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (PingMessage) msg() {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 19:10:54 -08:00
										 |  |  | // Recv reads a message from the DERP server. | 
					
						
							| 
									
										
										
										
											2020-06-15 10:26:50 -07:00
										 |  |  | // | 
					
						
							|  |  |  | // The returned message may alias memory owned by the Client; it | 
					
						
							|  |  |  | // should only be accessed until the next call to Client. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2020-02-20 09:11:43 -08:00
										 |  |  | // Once Recv returns an error, the Client is dead forever. | 
					
						
							| 
									
										
										
										
											2020-06-15 10:26:50 -07:00
										 |  |  | func (c *Client) Recv() (m ReceivedMessage, err error) { | 
					
						
							|  |  |  | 	return c.recvTimeout(120 * time.Second) | 
					
						
							| 
									
										
										
										
											2020-06-01 15:19:41 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-15 10:26:50 -07:00
										 |  |  | func (c *Client) recvTimeout(timeout time.Duration) (m ReceivedMessage, err error) { | 
					
						
							| 
									
										
										
										
											2020-02-20 09:11:43 -08:00
										 |  |  | 	if c.readErr != nil { | 
					
						
							| 
									
										
										
										
											2020-02-20 19:10:54 -08:00
										 |  |  | 		return nil, c.readErr | 
					
						
							| 
									
										
										
										
											2020-02-20 09:11:43 -08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2020-03-12 11:05:03 -04:00
										 |  |  | 			err = fmt.Errorf("derp.Recv: %w", err) | 
					
						
							| 
									
										
										
										
											2020-02-20 09:11:43 -08:00
										 |  |  | 			c.readErr = err | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2020-06-01 15:19:41 -07:00
										 |  |  | 		c.nc.SetReadDeadline(time.Now().Add(timeout)) | 
					
						
							| 
									
										
										
										
											2020-06-15 10:26:50 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Discard any peeked bytes from a previous Recv call. | 
					
						
							|  |  |  | 		if c.peeked != 0 { | 
					
						
							|  |  |  | 			if n, err := c.br.Discard(c.peeked); err != nil || n != c.peeked { | 
					
						
							|  |  |  | 				// Documented to never fail, but might as well check. | 
					
						
							| 
									
										
										
										
											2020-06-15 11:04:19 -07:00
										 |  |  | 				return nil, fmt.Errorf("bufio.Reader.Discard(%d bytes): got %v, %v", c.peeked, n, err) | 
					
						
							| 
									
										
										
										
											2020-06-15 10:26:50 -07:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			c.peeked = 0 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		t, n, err := readFrameHeader(c.br) | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2020-02-20 19:10:54 -08:00
										 |  |  | 			return nil, err | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-06-15 10:26:50 -07:00
										 |  |  | 		if n > 1<<20 { | 
					
						
							|  |  |  | 			return nil, fmt.Errorf("unexpectedly large frame of %d bytes returned", n) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var b []byte // frame payload (past the 5 byte header) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// If the frame fits in our bufio.Reader buffer, just use it. | 
					
						
							|  |  |  | 		// In practice it's 4KB (from derphttp.Client's bufio.NewReader(httpConn)) and | 
					
						
							|  |  |  | 		// in practive, WireGuard packets (and thus DERP frames) are under 1.5KB. | 
					
						
							| 
									
										
										
										
											2020-08-17 16:14:07 -07:00
										 |  |  | 		// So this is the common path. | 
					
						
							| 
									
										
										
										
											2020-06-15 10:26:50 -07:00
										 |  |  | 		if int(n) <= c.br.Size() { | 
					
						
							|  |  |  | 			b, err = c.br.Peek(int(n)) | 
					
						
							|  |  |  | 			c.peeked = int(n) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// But if for some reason we read a large DERP message (which isn't necessarily | 
					
						
							|  |  |  | 			// a Wireguard packet), then just allocate memory for it. | 
					
						
							|  |  |  | 			// TODO(bradfitz): use a pool if large frames ever happen in practice. | 
					
						
							|  |  |  | 			b = make([]byte, n) | 
					
						
							|  |  |  | 			_, err = io.ReadFull(c.br, b) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 		switch t { | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 			continue | 
					
						
							| 
									
										
										
										
											2020-08-17 16:14:07 -07:00
										 |  |  | 		case frameServerInfo: | 
					
						
							|  |  |  | 			// Server sends this at start-up. Currently unused. | 
					
						
							|  |  |  | 			// Just has a JSON message saying "version: 2", | 
					
						
							|  |  |  | 			// but the protocol seems extensible enough as-is without | 
					
						
							|  |  |  | 			// needing to wait an RTT to discover the version at startup. | 
					
						
							|  |  |  | 			// We'd prefer to give the connection to the client (magicsock) | 
					
						
							|  |  |  | 			// to start writing as soon as possible. | 
					
						
							|  |  |  | 			_, err := c.parseServerInfo(b) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, fmt.Errorf("invalid server info frame: %v", err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// TODO: add the results of parseServerInfo to ServerInfoMessage if we ever need it. | 
					
						
							|  |  |  | 			return ServerInfoMessage{}, nil | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 		case frameKeepAlive: | 
					
						
							| 
									
										
										
										
											2021-03-09 12:53:02 -08:00
										 |  |  | 			// A one-way keep-alive message that doesn't require an acknowledgement. | 
					
						
							|  |  |  | 			// This predated framePing/framePong. | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 			continue | 
					
						
							| 
									
										
										
										
											2020-03-21 18:24:28 -07:00
										 |  |  | 		case framePeerGone: | 
					
						
							|  |  |  | 			if n < keyLen { | 
					
						
							|  |  |  | 				c.logf("[unexpected] dropping short peerGone frame from DERP server") | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var pg PeerGoneMessage | 
					
						
							|  |  |  | 			copy(pg[:], b[:keyLen]) | 
					
						
							|  |  |  | 			return pg, nil | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-01 15:19:41 -07:00
										 |  |  | 		case framePeerPresent: | 
					
						
							|  |  |  | 			if n < keyLen { | 
					
						
							|  |  |  | 				c.logf("[unexpected] dropping short peerPresent frame from DERP server") | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var pg PeerPresentMessage | 
					
						
							|  |  |  | 			copy(pg[:], b[:keyLen]) | 
					
						
							|  |  |  | 			return pg, nil | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-20 12:27:12 -08:00
										 |  |  | 		case frameRecvPacket: | 
					
						
							| 
									
										
										
										
											2020-03-04 09:35:32 -08:00
										 |  |  | 			var rp ReceivedPacket | 
					
						
							| 
									
										
										
										
											2020-08-17 16:14:07 -07:00
										 |  |  | 			if n < keyLen { | 
					
						
							|  |  |  | 				c.logf("[unexpected] dropping short packet from DERP server") | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2020-03-04 09:35:32 -08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-08-17 16:14:07 -07:00
										 |  |  | 			copy(rp.Source[:], b[:keyLen]) | 
					
						
							|  |  |  | 			rp.Data = b[keyLen:n] | 
					
						
							| 
									
										
										
										
											2020-03-04 09:35:32 -08:00
										 |  |  | 			return rp, nil | 
					
						
							| 
									
										
										
										
											2021-03-09 12:53:02 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		case framePing: | 
					
						
							|  |  |  | 			var pm PingMessage | 
					
						
							|  |  |  | 			if n < 8 { | 
					
						
							|  |  |  | 				c.logf("[unexpected] dropping short ping frame") | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			copy(pm[:], b[:]) | 
					
						
							|  |  |  | 			return pm, nil | 
					
						
							| 
									
										
										
										
											2020-02-05 14:16:58 -08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |