mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 21:27:31 +00:00
control/controlclient: delete old naclbox code, require ts2021 Noise
Updates #11585 Updates tailscale/corp#18882 Change-Id: I90e2e4a211c58d429e2b128604614dde18986442 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:

committed by
Brad Fitzpatrick

parent
b9611461e5
commit
2409661a0d
@@ -562,16 +562,11 @@ func TestAddPingRequest(t *testing.T) {
|
||||
func TestC2NPingRequest(t *testing.T) {
|
||||
tstest.Shard(t)
|
||||
tstest.Parallel(t)
|
||||
env := newTestEnv(t)
|
||||
n1 := newTestNode(t, env)
|
||||
n1.StartDaemon()
|
||||
|
||||
n1.AwaitListening()
|
||||
n1.MustUp()
|
||||
n1.AwaitRunning()
|
||||
env := newTestEnv(t)
|
||||
|
||||
gotPing := make(chan bool, 1)
|
||||
waitPing := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
env.Control.HandleC2N = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
t.Errorf("unexpected ping method %q", r.Method)
|
||||
}
|
||||
@@ -584,8 +579,14 @@ func TestC2NPingRequest(t *testing.T) {
|
||||
t.Errorf("body error\n got: %q\nwant: %q", got, want)
|
||||
}
|
||||
gotPing <- true
|
||||
}))
|
||||
defer waitPing.Close()
|
||||
})
|
||||
|
||||
n1 := newTestNode(t, env)
|
||||
n1.StartDaemon()
|
||||
|
||||
n1.AwaitListening()
|
||||
n1.MustUp()
|
||||
n1.AwaitRunning()
|
||||
|
||||
nodes := env.Control.AllNodes()
|
||||
if len(nodes) != 1 {
|
||||
@@ -604,7 +605,7 @@ func TestC2NPingRequest(t *testing.T) {
|
||||
cancel()
|
||||
|
||||
pr := &tailcfg.PingRequest{
|
||||
URL: fmt.Sprintf("%s/ping-%d", waitPing.URL, try),
|
||||
URL: fmt.Sprintf("https://unused/some-c2n-path/ping-%d", try),
|
||||
Log: true,
|
||||
Types: "c2n",
|
||||
Payload: []byte("POST /echo HTTP/1.0\r\nContent-Length: 3\r\n\r\nabc"),
|
||||
|
@@ -24,7 +24,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go4.org/mem"
|
||||
"golang.org/x/net/http2"
|
||||
"tailscale.com/control/controlhttp"
|
||||
"tailscale.com/net/netaddr"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/tailcfg"
|
||||
@@ -50,6 +51,7 @@ type Server struct {
|
||||
Verbose bool
|
||||
DNSConfig *tailcfg.DNSConfig // nil means no DNS config
|
||||
MagicDNSDomain string
|
||||
HandleC2N http.Handler // if non-nil, used for /some-c2n-path/ in tests
|
||||
|
||||
// ExplicitBaseURL or HTTPTestServer must be set.
|
||||
ExplicitBaseURL string // e.g. "http://127.0.0.1:1234" with no trailing URL
|
||||
@@ -82,7 +84,7 @@ type Server struct {
|
||||
suppressAutoMapResponses set.Set[key.NodePublic]
|
||||
|
||||
noisePubKey key.MachinePublic
|
||||
noisePrivKey key.ControlPrivate // not strictly needed vs. MachinePrivate, but handy to test type interactions.
|
||||
noisePrivKey key.MachinePrivate
|
||||
|
||||
nodes map[key.NodePublic]*tailcfg.Node
|
||||
users map[key.NodePublic]*tailcfg.User
|
||||
@@ -253,6 +255,10 @@ func (s *Server) initMux() {
|
||||
})
|
||||
s.mux.HandleFunc("/key", s.serveKey)
|
||||
s.mux.HandleFunc("/machine/", s.serveMachine)
|
||||
s.mux.HandleFunc("/ts2021", s.serveNoiseUpgrade)
|
||||
if s.HandleC2N != nil {
|
||||
s.mux.Handle("/some-c2n-path/", s.HandleC2N)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -266,6 +272,36 @@ func (s *Server) serveUnhandled(w http.ResponseWriter, r *http.Request) {
|
||||
go panic(fmt.Sprintf("testcontrol.Server received unhandled request: %s", got.Bytes()))
|
||||
}
|
||||
|
||||
type peerMachinePublicContextKey struct{}
|
||||
|
||||
func (s *Server) serveNoiseUpgrade(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "POST required", 400)
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
noisePrivate := s.noisePrivKey
|
||||
s.mu.Unlock()
|
||||
cc, err := controlhttp.AcceptHTTP(ctx, w, r, noisePrivate, nil)
|
||||
if err != nil {
|
||||
log.Printf("AcceptHTTP: %v", err)
|
||||
return
|
||||
}
|
||||
defer cc.Close()
|
||||
|
||||
var h2srv http2.Server
|
||||
peerPub := cc.Peer()
|
||||
|
||||
h2srv.ServeConn(cc, &http2.ServeConnOpts{
|
||||
Context: context.WithValue(ctx, peerMachinePublicContextKey{}, peerPub),
|
||||
BaseConfig: &http.Server{
|
||||
Handler: s.mux,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) publicKeys() (noiseKey, pubKey key.MachinePublic) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
@@ -273,63 +309,50 @@ func (s *Server) publicKeys() (noiseKey, pubKey key.MachinePublic) {
|
||||
return s.noisePubKey, s.pubKey
|
||||
}
|
||||
|
||||
func (s *Server) privateKey() key.ControlPrivate {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.ensureKeyPairLocked()
|
||||
return s.privKey
|
||||
}
|
||||
|
||||
func (s *Server) ensureKeyPairLocked() {
|
||||
if !s.pubKey.IsZero() {
|
||||
return
|
||||
}
|
||||
s.noisePrivKey = key.NewControl()
|
||||
s.noisePrivKey = key.NewMachine()
|
||||
s.noisePubKey = s.noisePrivKey.Public()
|
||||
s.privKey = key.NewControl()
|
||||
s.pubKey = s.privKey.Public()
|
||||
}
|
||||
|
||||
func (s *Server) serveKey(w http.ResponseWriter, r *http.Request) {
|
||||
_, legacyKey := s.publicKeys()
|
||||
noiseKey, legacyKey := s.publicKeys()
|
||||
if r.FormValue("v") == "" {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
io.WriteString(w, legacyKey.UntypedHexString())
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
// TODO(maisem/bradfitz): support noise protocol here.
|
||||
json.NewEncoder(w).Encode(&tailcfg.OverTLSPublicKeyResponse{
|
||||
LegacyPublicKey: legacyKey,
|
||||
// PublicKey: noiseKey,
|
||||
PublicKey: noiseKey,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) serveMachine(w http.ResponseWriter, r *http.Request) {
|
||||
mkeyStr := strings.TrimPrefix(r.URL.Path, "/machine/")
|
||||
rem := ""
|
||||
if i := strings.IndexByte(mkeyStr, '/'); i != -1 {
|
||||
rem = mkeyStr[i:]
|
||||
mkeyStr = mkeyStr[:i]
|
||||
}
|
||||
|
||||
// TODO(maisem/bradfitz): support noise protocol here.
|
||||
mkey, err := key.ParseMachinePublicUntyped(mem.S(mkeyStr))
|
||||
if err != nil {
|
||||
http.Error(w, "bad machine key hex", 400)
|
||||
return
|
||||
}
|
||||
|
||||
if r.Method != "POST" {
|
||||
http.Error(w, "POST required", 400)
|
||||
return
|
||||
}
|
||||
ctx := r.Context()
|
||||
|
||||
switch rem {
|
||||
case "":
|
||||
s.serveRegister(w, r, mkey)
|
||||
case "/map":
|
||||
mkey, ok := ctx.Value(peerMachinePublicContextKey{}).(key.MachinePublic)
|
||||
if !ok {
|
||||
panic("no peer machine public key in context")
|
||||
}
|
||||
|
||||
switch r.URL.Path {
|
||||
case "/machine/map":
|
||||
s.serveMap(w, r, mkey)
|
||||
case "/machine/register":
|
||||
s.serveRegister(w, r, mkey)
|
||||
case "/machine/update-health":
|
||||
io.Copy(io.Discard, r.Body)
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
default:
|
||||
s.serveUnhandled(w, r)
|
||||
}
|
||||
@@ -549,7 +572,7 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key.
|
||||
}
|
||||
|
||||
var req tailcfg.RegisterRequest
|
||||
if err := s.decode(mkey, msg, &req); err != nil {
|
||||
if err := s.decode(msg, &req); err != nil {
|
||||
go panic(fmt.Sprintf("serveRegister: decode: %v", err))
|
||||
}
|
||||
if req.Version == 0 {
|
||||
@@ -563,7 +586,7 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key.
|
||||
log.Printf("Got %T: %s", req, j)
|
||||
}
|
||||
if s.RequireAuthKey != "" && req.Auth.AuthKey != s.RequireAuthKey {
|
||||
res := must.Get(s.encode(mkey, false, tailcfg.RegisterResponse{
|
||||
res := must.Get(s.encode(false, tailcfg.RegisterResponse{
|
||||
Error: "invalid authkey",
|
||||
}))
|
||||
w.WriteHeader(200)
|
||||
@@ -637,7 +660,7 @@ func (s *Server) serveRegister(w http.ResponseWriter, r *http.Request, mkey key.
|
||||
authURL = s.BaseURL() + authPath
|
||||
}
|
||||
|
||||
res, err := s.encode(mkey, false, tailcfg.RegisterResponse{
|
||||
res, err := s.encode(false, tailcfg.RegisterResponse{
|
||||
User: *user,
|
||||
Login: *login,
|
||||
NodeKeyExpired: allExpired,
|
||||
@@ -729,7 +752,7 @@ func (s *Server) serveMap(w http.ResponseWriter, r *http.Request, mkey key.Machi
|
||||
r.Body.Close()
|
||||
|
||||
req := new(tailcfg.MapRequest)
|
||||
if err := s.decode(mkey, msg, req); err != nil {
|
||||
if err := s.decode(msg, req); err != nil {
|
||||
go panic(fmt.Sprintf("bad map request: %v", err))
|
||||
}
|
||||
|
||||
@@ -1011,7 +1034,7 @@ func (s *Server) takeRawMapMessage(nk key.NodePublic) (mapResJSON []byte, ok boo
|
||||
}
|
||||
|
||||
func (s *Server) sendMapMsg(w http.ResponseWriter, mkey key.MachinePublic, compress bool, msg any) error {
|
||||
resBytes, err := s.encode(mkey, compress, msg)
|
||||
resBytes, err := s.encode(compress, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1034,19 +1057,14 @@ func (s *Server) sendMapMsg(w http.ResponseWriter, mkey key.MachinePublic, compr
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) decode(mkey key.MachinePublic, msg []byte, v any) error {
|
||||
func (s *Server) decode(msg []byte, v any) error {
|
||||
if len(msg) == msgLimit {
|
||||
return errors.New("encrypted message too long")
|
||||
}
|
||||
|
||||
decrypted, ok := s.privateKey().OpenFrom(mkey, msg)
|
||||
if !ok {
|
||||
return errors.New("can't decrypt request")
|
||||
}
|
||||
return json.Unmarshal(decrypted, v)
|
||||
return json.Unmarshal(msg, v)
|
||||
}
|
||||
|
||||
func (s *Server) encode(mkey key.MachinePublic, compress bool, v any) (b []byte, err error) {
|
||||
func (s *Server) encode(compress bool, v any) (b []byte, err error) {
|
||||
var isBytes bool
|
||||
if b, isBytes = v.([]byte); !isBytes {
|
||||
b, err = json.Marshal(v)
|
||||
@@ -1057,7 +1075,7 @@ func (s *Server) encode(mkey key.MachinePublic, compress bool, v any) (b []byte,
|
||||
if compress {
|
||||
b = zstdframe.AppendEncode(nil, b, zstdframe.FastestCompression)
|
||||
}
|
||||
return s.privateKey().SealTo(mkey, b), nil
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// filterInvalidIPv6Endpoints removes invalid IPv6 endpoints from eps,
|
||||
|
Reference in New Issue
Block a user