tsnet: resolve issues listening on multiple ports, refactor input

Issues were resolved mainly via cherry-picked commits prior to this.

Signed-off-by: Harry Harpham <harry@tailscale.com>
Harry Harpham 7 days ago
parent f779b0089d
commit c2e81dd9d9
No known key found for this signature in database

@ -7,8 +7,10 @@ package tsnet
import (
"context"
crand "crypto/rand"
"crypto/sha256"
"crypto/tls"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
@ -1263,7 +1265,7 @@ type ServiceTransportOptions interface {
// TODO: doc
type ServiceTCPOptions struct {
TerminateTLS bool
PROXYProtocol int
PROXYProtocol int // TODO: does this have meaning for HTTP Services?
}
func (ServiceTCPOptions) serviceTransportOptions() {}
@ -1326,26 +1328,18 @@ func (s *Server) ListenService(name string, port uint16, opts ServiceTransportOp
return nil, err
}
lc := s.localClient
st, err := lc.StatusWithoutPeers(ctx)
if err != nil {
return nil, fmt.Errorf("fetching ACL tags: %w", err)
}
st := s.lb.StatusWithoutPeers()
if st.Self.Tags == nil || st.Self.Tags.Len() == 0 {
return nil, ErrUntaggedServiceHost
}
prefs, err := lc.GetPrefs(ctx)
if err != nil {
return nil, fmt.Errorf("fetching node preferences: %w", err)
}
if !slices.Contains(prefs.AdvertiseServices, svcName) {
advertisedServices := s.lb.Prefs().AdvertiseServices().AsSlice()
if !slices.Contains(advertisedServices, svcName) {
// TODO: do we need to undo this edit on error?
_, err = lc.EditPrefs(ctx, &ipn.MaskedPrefs{
_, err = s.lb.EditPrefs(&ipn.MaskedPrefs{
AdvertiseServicesSet: true,
Prefs: ipn.Prefs{
AdvertiseServices: append(prefs.AdvertiseServices, svcName),
AdvertiseServices: append(advertisedServices, svcName),
},
})
if err != nil {
@ -1353,12 +1347,18 @@ func (s *Server) ListenService(name string, port uint16, opts ServiceTransportOp
}
}
srvConfig, err := lc.GetServeConfig(ctx)
if err != nil {
return nil, fmt.Errorf("fetching node serve config: %w", err)
}
if srvConfig == nil {
srvConfig = new(ipn.ServeConfig)
srvConfig := new(ipn.ServeConfig)
etag := "empty"
if sc := s.lb.ServeConfig(); sc.Valid() {
srvConfig = sc.AsStruct()
// TODO: it's weird that we have to calculate the ETag ourselves.
// Shouldn't the backend do this for us?
b, err := json.Marshal(srvConfig)
if err != nil {
return nil, fmt.Errorf("marshaling serve config: %w", err)
}
sum := sha256.Sum256(b)
etag = hex.EncodeToString(sum[:])
}
// Start listening on a TCP socket.
@ -1405,7 +1405,7 @@ func (s *Server) ListenService(name string, port uint16, opts ServiceTransportOp
return nil, fmt.Errorf("unknown ServiceTransportOptions type %T", opts)
}
if err := lc.SetServeConfig(ctx, srvConfig); err != nil {
if err := s.lb.SetServeConfig(srvConfig, etag); err != nil {
ln.Close()
return nil, err
}

@ -1091,10 +1091,31 @@ func TestListenService(t *testing.T) {
assertEchoHTTP(t, listeners[0].FQDN, "/foo/bar", peer.Dial)
},
},
{
name: "multiple_ports",
inputs: []input{
{
port: 99,
},
{
opts: ServiceHTTPOptions{},
port: 80,
},
},
run: func(t *testing.T, listeners []*ServiceListener, peer *Server) {
go acceptAndEcho(t, listeners[0])
target := fmt.Sprintf("%s:%d", listeners[0].FQDN, 99)
conn := must.Get(peer.Dial(t.Context(), "tcp", target))
defer conn.Close()
assertEcho(t, conn)
go checkAndEcho(t, listeners[1], nil)
assertEchoHTTP(t, listeners[1].FQDN, "", peer.Dial)
},
},
// TODO:
// Success cases:
// - TLS-terminated-TCP
// - Service with multiple ports
// - TUN Service
// Error cases:
// - Untagged node

Loading…
Cancel
Save