WIP: encode peer public key in endpoint

incomplete

new idea is to make a new type in wgcfg
an Endpoints type

that can be serialized/deserialized nicely at the edges
and be easy to deal with other places.
josh/wip/create-endpoint-no-public-key
Josh Bleecher Snyder 2021-03-27 14:07:50 -07:00
parent 4954fbfda6
commit 969a8540e2
7 changed files with 42 additions and 17 deletions

View File

@ -6,6 +6,7 @@ package deepprint
import ( import (
"bytes" "bytes"
"strings"
"testing" "testing"
"inet.af/netaddr" "inet.af/netaddr"
@ -33,6 +34,8 @@ func TestDeepPrint(t *testing.T) {
} }
} }
var dummyHeyKey = strings.Repeat("0", wgcfg.HexKeyLen)
func getVal() []interface{} { func getVal() []interface{} {
return []interface{}{ return []interface{}{
&wgcfg.Config{ &wgcfg.Config{
@ -41,7 +44,7 @@ func getVal() []interface{} {
ListenPort: 5, ListenPort: 5,
Peers: []wgcfg.Peer{ Peers: []wgcfg.Peer{
{ {
Endpoints: "foo:5", Endpoints2: dummyHeyKey + "@foo:5",
}, },
}, },
}, },

View File

@ -2745,7 +2745,6 @@ func (c *Conn) CreateBind(uint16) (conn.Bind, uint16, error) {
// is running code that supports active discovery, so CreateEndpoint returns // is running code that supports active discovery, so CreateEndpoint returns
// a discoEndpoint. // a discoEndpoint.
// //
func (c *Conn) CreateEndpoint(pubKey [32]byte, addrs string) (conn.Endpoint, error) { func (c *Conn) CreateEndpoint(pubKey [32]byte, addrs string) (conn.Endpoint, error) {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()

View File

@ -639,11 +639,11 @@ func isTrimmablePeer(p *wgcfg.Peer, numPeers int) bool {
if forceFullWireguardConfig(numPeers) { if forceFullWireguardConfig(numPeers) {
return false return false
} }
if !isSingleEndpoint(p.Endpoints) { if !isSingleEndpoint(p.Endpoints2) {
return false return false
} }
host, _, err := net.SplitHostPort(p.Endpoints) host, _, err := splitEndpointHostPort(p.Endpoints2)
if err != nil { if err != nil {
return false return false
} }
@ -986,7 +986,13 @@ func (e *userspaceEngine) Reconfig(cfg *wgcfg.Config, routerCfg *router.Config)
// isSingleEndpoint reports whether endpoints contains exactly one host:port pair. // isSingleEndpoint reports whether endpoints contains exactly one host:port pair.
func isSingleEndpoint(s string) bool { func isSingleEndpoint(s string) bool {
return s != "" && !strings.Contains(s, ",") return len(s) > wgcfg.HexKeyPrefixLen && !strings.Contains(s, ",")
}
// splitEndpointHostPort returns net.SplitHostPort of the sole endpoint in s.
func splitEndpointHostPort(s string) (host, port string, err error) {
ep := s[wgcfg.HexKeyPrefixLen:]
return net.SplitHostPort(ep)
} }
func (e *userspaceEngine) GetFilter() *filter.Filter { func (e *userspaceEngine) GetFilter() *filter.Filter {

View File

@ -27,12 +27,21 @@ type Config struct {
} }
type Peer struct { type Peer struct {
PublicKey Key PublicKey Key
AllowedIPs []netaddr.IPPrefix AllowedIPs []netaddr.IPPrefix
Endpoints string // comma-separated host/port pairs: "1.2.3.4:56,[::]:80" // Endpoints encodes information about the Peer.
// It has the form: "<HEXKEY>@1.2.3.4:56,[::]:80".
// The first 65 bytes are a hex-encoded public key, then '@'.
// The remainder is a comma-separated list of host/port pairs.
Endpoints2 string
PersistentKeepalive uint16 PersistentKeepalive uint16
} }
const (
HexKeyLength = KeySize * 2 // KeySize when encoded as hex bytes
HexKeyPrefixLen = HexKeyLength + len("@")
)
// Copy makes a deep copy of Config. // Copy makes a deep copy of Config.
// The result aliases no memory with the original. // The result aliases no memory with the original.
func (cfg Config) Copy() Config { func (cfg Config) Copy() Config {

View File

@ -51,7 +51,7 @@ func cidrIsSubnet(node *tailcfg.Node, cidr netaddr.IPPrefix) bool {
return true return true
} }
// WGCfg returns the NetworkMaps's Wireguard configuration. // WGCfg returns the NetworkMaps's WireGuard configuration.
func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags, exitNode tailcfg.StableNodeID) (*wgcfg.Config, error) { func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags, exitNode tailcfg.StableNodeID) (*wgcfg.Config, error) {
cfg := &wgcfg.Config{ cfg := &wgcfg.Config{
Name: "tailscale", Name: "tailscale",
@ -77,7 +77,7 @@ func WGCfg(nm *netmap.NetworkMap, logf logger.Logf, flags netmap.WGConfigFlags,
if err := appendEndpoint(cpeer, fmt.Sprintf("%x%s", peer.DiscoKey[:], wgcfg.EndpointDiscoSuffix)); err != nil { if err := appendEndpoint(cpeer, fmt.Sprintf("%x%s", peer.DiscoKey[:], wgcfg.EndpointDiscoSuffix)); err != nil {
return nil, err return nil, err
} }
cpeer.Endpoints = fmt.Sprintf("%x.disco.tailscale:12345", peer.DiscoKey[:]) cpeer.Endpoints2 = fmt.Sprintf("%x@%x.disco.tailscale:12345", peer.Key, peer.DiscoKey[:])
} else { } else {
if err := appendEndpoint(cpeer, peer.DERP); err != nil { if err := appendEndpoint(cpeer, peer.DERP); err != nil {
return nil, err return nil, err
@ -122,9 +122,11 @@ func appendEndpoint(peer *wgcfg.Peer, epStr string) error {
if err != nil { if err != nil {
return fmt.Errorf("invalid port in endpoint %q for peer %v", epStr, peer.PublicKey.ShortString()) return fmt.Errorf("invalid port in endpoint %q for peer %v", epStr, peer.PublicKey.ShortString())
} }
if peer.Endpoints != "" { if peer.Endpoints2 == "" {
peer.Endpoints += "," peer.Endpoints2 = peer.PublicKey.HexString() + "@"
} else {
peer.Endpoints2 += ","
} }
peer.Endpoints += epStr peer.Endpoints2 += epStr
return nil return nil
} }

View File

@ -175,7 +175,7 @@ func (cfg *Config) handlePeerLine(peer *Peer, key, value string) error {
if err != nil { if err != nil {
return err return err
} }
peer.Endpoints = value peer.Endpoints2 = peer.PublicKey.HexString() + "@" + value
case "persistent_keepalive_interval": case "persistent_keepalive_interval":
n, err := strconv.ParseUint(value, 10, 16) n, err := strconv.ParseUint(value, 10, 16)
if err != nil { if err != nil {

View File

@ -55,8 +55,8 @@ func (cfg *Config) ToUAPI(w io.Writer, prev *Config) error {
setPeer(p) setPeer(p)
set("protocol_version", "1") set("protocol_version", "1")
if !endpointsEqual(oldPeer.Endpoints, p.Endpoints) { if !endpointsEqual(oldPeer.Endpoints2, p.Endpoints2) {
set("endpoint", p.Endpoints) set("endpoint", p.Endpoints2)
} }
// TODO: replace_allowed_ips is expensive. // TODO: replace_allowed_ips is expensive.
@ -97,12 +97,18 @@ func endpointsEqual(x, y string) bool {
if x == y { if x == y {
return true return true
} }
// Public keys must match.
if x[:HexKeyPrefixLen] != y[:HexKeyPrefixLen] {
return false
}
// See whether the addresses are the same, but out of order.
x = x[HexKeyPrefixLen:]
y = y[HexKeyPrefixLen:]
xs := strings.Split(x, ",") xs := strings.Split(x, ",")
ys := strings.Split(y, ",") ys := strings.Split(y, ",")
if len(xs) != len(ys) { if len(xs) != len(ys) {
return false return false
} }
// Otherwise, see if they're the same, but out of order.
sort.Strings(xs) sort.Strings(xs)
sort.Strings(ys) sort.Strings(ys)
x = strings.Join(xs, ",") x = strings.Join(xs, ",")