|
|
|
|
@ -58,13 +58,13 @@ type Server struct { |
|
|
|
|
cond *sync.Cond // lazily initialized by condLocked
|
|
|
|
|
pubKey key.MachinePublic |
|
|
|
|
privKey key.ControlPrivate // not strictly needed vs. MachinePrivate, but handy to test type interactions.
|
|
|
|
|
nodes map[tailcfg.NodeKey]*tailcfg.Node |
|
|
|
|
users map[tailcfg.NodeKey]*tailcfg.User |
|
|
|
|
logins map[tailcfg.NodeKey]*tailcfg.Login |
|
|
|
|
nodes map[key.NodePublic]*tailcfg.Node |
|
|
|
|
users map[key.NodePublic]*tailcfg.User |
|
|
|
|
logins map[key.NodePublic]*tailcfg.Login |
|
|
|
|
updates map[tailcfg.NodeID]chan updateType |
|
|
|
|
authPath map[string]*AuthPath |
|
|
|
|
nodeKeyAuthed map[tailcfg.NodeKey]bool // key => true once authenticated
|
|
|
|
|
pingReqsToAdd map[tailcfg.NodeKey]*tailcfg.PingRequest |
|
|
|
|
nodeKeyAuthed map[key.NodePublic]bool // key => true once authenticated
|
|
|
|
|
pingReqsToAdd map[key.NodePublic]*tailcfg.PingRequest |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// BaseURL returns the server's base URL, without trailing slash.
|
|
|
|
|
@ -103,7 +103,7 @@ func (s *Server) condLocked() *sync.Cond { |
|
|
|
|
|
|
|
|
|
// AwaitNodeInMapRequest waits for node k to be stuck in a map poll.
|
|
|
|
|
// It returns an error if and only if the context is done first.
|
|
|
|
|
func (s *Server) AwaitNodeInMapRequest(ctx context.Context, k tailcfg.NodeKey) error { |
|
|
|
|
func (s *Server) AwaitNodeInMapRequest(ctx context.Context, k key.NodePublic) error { |
|
|
|
|
s.mu.Lock() |
|
|
|
|
defer s.mu.Unlock() |
|
|
|
|
cond := s.condLocked() |
|
|
|
|
@ -135,11 +135,11 @@ func (s *Server) AwaitNodeInMapRequest(ctx context.Context, k tailcfg.NodeKey) e |
|
|
|
|
|
|
|
|
|
// AddPingRequest sends the ping pr to nodeKeyDst. It reports whether it did so. That is,
|
|
|
|
|
// it reports whether nodeKeyDst was connected.
|
|
|
|
|
func (s *Server) AddPingRequest(nodeKeyDst tailcfg.NodeKey, pr *tailcfg.PingRequest) bool { |
|
|
|
|
func (s *Server) AddPingRequest(nodeKeyDst key.NodePublic, pr *tailcfg.PingRequest) bool { |
|
|
|
|
s.mu.Lock() |
|
|
|
|
defer s.mu.Unlock() |
|
|
|
|
if s.pingReqsToAdd == nil { |
|
|
|
|
s.pingReqsToAdd = map[tailcfg.NodeKey]*tailcfg.PingRequest{} |
|
|
|
|
s.pingReqsToAdd = map[key.NodePublic]*tailcfg.PingRequest{} |
|
|
|
|
} |
|
|
|
|
// Now send the update to the channel
|
|
|
|
|
node := s.nodeLocked(nodeKeyDst) |
|
|
|
|
@ -154,7 +154,7 @@ func (s *Server) AddPingRequest(nodeKeyDst tailcfg.NodeKey, pr *tailcfg.PingRequ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type AuthPath struct { |
|
|
|
|
nodeKey tailcfg.NodeKey |
|
|
|
|
nodeKey key.NodePublic |
|
|
|
|
|
|
|
|
|
closeOnce sync.Once |
|
|
|
|
ch chan struct{} |
|
|
|
|
@ -254,7 +254,7 @@ func (s *Server) serveMachine(w http.ResponseWriter, r *http.Request) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Node returns the node for nodeKey. It's always nil or cloned memory.
|
|
|
|
|
func (s *Server) Node(nodeKey tailcfg.NodeKey) *tailcfg.Node { |
|
|
|
|
func (s *Server) Node(nodeKey key.NodePublic) *tailcfg.Node { |
|
|
|
|
s.mu.Lock() |
|
|
|
|
defer s.mu.Unlock() |
|
|
|
|
return s.nodeLocked(nodeKey) |
|
|
|
|
@ -263,7 +263,7 @@ func (s *Server) Node(nodeKey tailcfg.NodeKey) *tailcfg.Node { |
|
|
|
|
// nodeLocked returns the node for nodeKey. It's always nil or cloned memory.
|
|
|
|
|
//
|
|
|
|
|
// s.mu must be held.
|
|
|
|
|
func (s *Server) nodeLocked(nodeKey tailcfg.NodeKey) *tailcfg.Node { |
|
|
|
|
func (s *Server) nodeLocked(nodeKey key.NodePublic) *tailcfg.Node { |
|
|
|
|
return s.nodes[nodeKey].Clone() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -272,20 +272,21 @@ func (s *Server) AddFakeNode() { |
|
|
|
|
s.mu.Lock() |
|
|
|
|
defer s.mu.Unlock() |
|
|
|
|
if s.nodes == nil { |
|
|
|
|
s.nodes = make(map[tailcfg.NodeKey]*tailcfg.Node) |
|
|
|
|
s.nodes = make(map[key.NodePublic]*tailcfg.Node) |
|
|
|
|
} |
|
|
|
|
nk := key.NewNode().Public().AsNodeKey() |
|
|
|
|
nk := key.NewNode().Public() |
|
|
|
|
mk := key.NewMachine().Public() |
|
|
|
|
dk := tailcfg.DiscoKeyFromDiscoPublic(key.NewDisco().Public()) |
|
|
|
|
id := int64(binary.LittleEndian.Uint64(nk[:])) |
|
|
|
|
ip := netaddr.IPv4(nk[0], nk[1], nk[2], nk[3]) |
|
|
|
|
r := nk.Raw32() |
|
|
|
|
id := int64(binary.LittleEndian.Uint64(r[:])) |
|
|
|
|
ip := netaddr.IPv4(r[0], r[1], r[2], r[3]) |
|
|
|
|
addr := netaddr.IPPrefixFrom(ip, 32) |
|
|
|
|
s.nodes[nk] = &tailcfg.Node{ |
|
|
|
|
ID: tailcfg.NodeID(id), |
|
|
|
|
StableID: tailcfg.StableNodeID(fmt.Sprintf("TESTCTRL%08x", id)), |
|
|
|
|
User: tailcfg.UserID(id), |
|
|
|
|
Machine: mk, |
|
|
|
|
Key: nk, |
|
|
|
|
Key: nk.AsNodeKey(), |
|
|
|
|
MachineAuthorized: true, |
|
|
|
|
DiscoKey: dk, |
|
|
|
|
Addresses: []netaddr.IPPrefix{addr}, |
|
|
|
|
@ -306,14 +307,14 @@ func (s *Server) AllNodes() (nodes []*tailcfg.Node) { |
|
|
|
|
return nodes |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *Server) getUser(nodeKey tailcfg.NodeKey) (*tailcfg.User, *tailcfg.Login) { |
|
|
|
|
func (s *Server) getUser(nodeKey key.NodePublic) (*tailcfg.User, *tailcfg.Login) { |
|
|
|
|
s.mu.Lock() |
|
|
|
|
defer s.mu.Unlock() |
|
|
|
|
if s.users == nil { |
|
|
|
|
s.users = map[tailcfg.NodeKey]*tailcfg.User{} |
|
|
|
|
s.users = map[key.NodePublic]*tailcfg.User{} |
|
|
|
|
} |
|
|
|
|
if s.logins == nil { |
|
|
|
|
s.logins = map[tailcfg.NodeKey]*tailcfg.Login{} |
|
|
|
|
s.logins = map[key.NodePublic]*tailcfg.Login{} |
|
|
|
|
} |
|
|
|
|
if u, ok := s.users[nodeKey]; ok { |
|
|
|
|
return u, s.logins[nodeKey] |
|
|
|
|
@ -353,7 +354,7 @@ func (s *Server) authPathDone(authPath string) <-chan struct{} { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *Server) addAuthPath(authPath string, nodeKey tailcfg.NodeKey) { |
|
|
|
|
func (s *Server) addAuthPath(authPath string, nodeKey key.NodePublic) { |
|
|
|
|
s.mu.Lock() |
|
|
|
|
defer s.mu.Unlock() |
|
|
|
|
if s.authPath == nil { |
|
|
|
|
@ -385,7 +386,7 @@ func (s *Server) CompleteAuth(authPathOrURL string) bool { |
|
|
|
|
panic("zero AuthPath.NodeKey") |
|
|
|
|
} |
|
|
|
|
if s.nodeKeyAuthed == nil { |
|
|
|
|
s.nodeKeyAuthed = map[tailcfg.NodeKey]bool{} |
|
|
|
|
s.nodeKeyAuthed = map[key.NodePublic]bool{} |
|
|
|
|
} |
|
|
|
|
s.nodeKeyAuthed[ap.nodeKey] = true |
|
|
|
|
ap.CompleteSuccessfully() |
|
|
|
|
@ -433,10 +434,12 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key. |
|
|
|
|
// some follow-ups? For now all are successes.
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
user, login := s.getUser(req.NodeKey) |
|
|
|
|
nk := req.NodeKey.AsNodePublic() |
|
|
|
|
|
|
|
|
|
user, login := s.getUser(nk) |
|
|
|
|
s.mu.Lock() |
|
|
|
|
if s.nodes == nil { |
|
|
|
|
s.nodes = map[tailcfg.NodeKey]*tailcfg.Node{} |
|
|
|
|
s.nodes = map[key.NodePublic]*tailcfg.Node{} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
machineAuthorized := true // TODO: add Server.RequireMachineAuth
|
|
|
|
|
@ -449,7 +452,7 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key. |
|
|
|
|
v6Prefix, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s.nodes[req.NodeKey] = &tailcfg.Node{ |
|
|
|
|
s.nodes[nk] = &tailcfg.Node{ |
|
|
|
|
ID: tailcfg.NodeID(user.ID), |
|
|
|
|
StableID: tailcfg.StableNodeID(fmt.Sprintf("TESTCTRL%08x", int(user.ID))), |
|
|
|
|
User: user.ID, |
|
|
|
|
@ -461,7 +464,7 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key. |
|
|
|
|
Hostinfo: *req.Hostinfo, |
|
|
|
|
} |
|
|
|
|
requireAuth := s.RequireAuth |
|
|
|
|
if requireAuth && s.nodeKeyAuthed[req.NodeKey] { |
|
|
|
|
if requireAuth && s.nodeKeyAuthed[nk] { |
|
|
|
|
requireAuth = false |
|
|
|
|
} |
|
|
|
|
s.mu.Unlock() |
|
|
|
|
@ -471,7 +474,7 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key. |
|
|
|
|
randHex := make([]byte, 10) |
|
|
|
|
crand.Read(randHex) |
|
|
|
|
authPath := fmt.Sprintf("/auth/%x", randHex) |
|
|
|
|
s.addAuthPath(authPath, req.NodeKey) |
|
|
|
|
s.addAuthPath(authPath, nk) |
|
|
|
|
authURL = s.BaseURL() + authPath |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -535,7 +538,7 @@ func (s *Server) UpdateNode(n *tailcfg.Node) (peersToUpdate []tailcfg.NodeID) { |
|
|
|
|
if n.Key.IsZero() { |
|
|
|
|
panic("zero nodekey") |
|
|
|
|
} |
|
|
|
|
s.nodes[n.Key] = n.Clone() |
|
|
|
|
s.nodes[n.Key.AsNodePublic()] = n.Clone() |
|
|
|
|
for _, n2 := range s.nodes { |
|
|
|
|
if n.ID != n2.ID { |
|
|
|
|
peersToUpdate = append(peersToUpdate, n2.ID) |
|
|
|
|
@ -578,7 +581,7 @@ func (s *Server) serveMap(w http.ResponseWriter, r *http.Request, mkey key.Machi |
|
|
|
|
jitter := time.Duration(rand.Intn(8000)) * time.Millisecond |
|
|
|
|
keepAlive := 50*time.Second + jitter |
|
|
|
|
|
|
|
|
|
node := s.Node(req.NodeKey) |
|
|
|
|
node := s.Node(req.NodeKey.AsNodePublic()) |
|
|
|
|
if node == nil { |
|
|
|
|
http.Error(w, "node not found", 400) |
|
|
|
|
return |
|
|
|
|
@ -690,12 +693,13 @@ var keepAliveMsg = &struct { |
|
|
|
|
//
|
|
|
|
|
// No updates to s are done here.
|
|
|
|
|
func (s *Server) MapResponse(req *tailcfg.MapRequest) (res *tailcfg.MapResponse, err error) { |
|
|
|
|
node := s.Node(req.NodeKey) |
|
|
|
|
nk := req.NodeKey.AsNodePublic() |
|
|
|
|
node := s.Node(nk) |
|
|
|
|
if node == nil { |
|
|
|
|
// node key rotated away (once test server supports that)
|
|
|
|
|
return nil, nil |
|
|
|
|
} |
|
|
|
|
user, _ := s.getUser(req.NodeKey) |
|
|
|
|
user, _ := s.getUser(nk) |
|
|
|
|
res = &tailcfg.MapResponse{ |
|
|
|
|
Node: node, |
|
|
|
|
DERPMap: s.DERPMap, |
|
|
|
|
@ -727,9 +731,9 @@ func (s *Server) MapResponse(req *tailcfg.MapRequest) (res *tailcfg.MapResponse, |
|
|
|
|
|
|
|
|
|
// Consume the PingRequest while protected by mutex if it exists
|
|
|
|
|
s.mu.Lock() |
|
|
|
|
if pr, ok := s.pingReqsToAdd[node.Key]; ok { |
|
|
|
|
if pr, ok := s.pingReqsToAdd[nk]; ok { |
|
|
|
|
res.PingRequest = pr |
|
|
|
|
delete(s.pingReqsToAdd, node.Key) |
|
|
|
|
delete(s.pingReqsToAdd, nk) |
|
|
|
|
} |
|
|
|
|
s.mu.Unlock() |
|
|
|
|
return res, nil |
|
|
|
|
|