mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-23 10:12:07 +01:00
Implement a few options, check for ACL tags
Signed-off-by: Harry Harpham <harry@tailscale.com>
This commit is contained in:
parent
645808c3e9
commit
0922a4727c
@ -1241,38 +1241,43 @@ func (s *Server) ListenFunnel(network, addr string, opts ...FunnelOption) (net.L
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: doc
|
// TODO: doc
|
||||||
// TODO: name?
|
|
||||||
// TODO: can this mirror the format accepted by set-config?
|
|
||||||
// For now, configures a single endpoint
|
|
||||||
// Maybe this should be an interface, with implementations like ListenTCPService, etc.
|
|
||||||
type ListenServiceConfig struct {
|
|
||||||
Port uint16
|
|
||||||
PortHandler ipn.TCPPortHandler // TODO: what about UDP support in the future?
|
|
||||||
|
|
||||||
// TODO: could be HTTP-specific if this config becomes an interface
|
|
||||||
WebHandlers map[ipn.HostPort]*ipn.WebServerConfig
|
|
||||||
|
|
||||||
// TODO: maybe something like this for things like PROXY protocol support?
|
|
||||||
// L4Options
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: do we actually need this?
|
|
||||||
type ServiceOption interface {
|
type ServiceOption interface {
|
||||||
serviceOption()
|
serviceOption()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type serviceOptionTerminateTLS struct{}
|
||||||
|
|
||||||
|
func (serviceOptionTerminateTLS) serviceOption() {}
|
||||||
|
|
||||||
|
// TODO: doc
|
||||||
|
func ServiceOptionTerminateTLS() ServiceOption {
|
||||||
|
return serviceOptionTerminateTLS{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type serviceOptionPROXYProtocol struct {
|
||||||
|
version int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (serviceOptionPROXYProtocol) serviceOption() {}
|
||||||
|
|
||||||
|
// TODO: doc
|
||||||
|
func ServiceOptionPROXYProtocol(version int) ServiceOption {
|
||||||
|
return serviceOptionPROXYProtocol{version}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUntaggedServiceHost is returned by ListenService when run on a node
|
||||||
|
// without any ACL tags. A node must use a tag-based identity to act as a
|
||||||
|
// Service host. For more information, see:
|
||||||
|
// https://tailscale.com/kb/1552/tailscale-services#prerequisites
|
||||||
|
var ErrUntaggedServiceHost = errors.New("service hosts must be tagged nodes")
|
||||||
|
|
||||||
// TODO: doc
|
// TODO: doc
|
||||||
// TODO: tailcfg.ServiceName?
|
// TODO: tailcfg.ServiceName?
|
||||||
func (s *Server) ListenService(name string, port uint16) (net.Listener, error) {
|
func (s *Server) ListenService(name string, port uint16, opts ...ServiceOption) (net.Listener, error) {
|
||||||
if err := tailcfg.ServiceName(name).Validate(); err != nil {
|
if err := tailcfg.ServiceName(name).Validate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// - get existing serve config
|
|
||||||
// - make changes and update
|
|
||||||
// - pipe to local TCP listener
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - try above with simple TCP listener first
|
// - try above with simple TCP listener first
|
||||||
// - handle Services with multiple ports defined
|
// - handle Services with multiple ports defined
|
||||||
@ -1280,6 +1285,20 @@ func (s *Server) ListenService(name string, port uint16) (net.Listener, error) {
|
|||||||
// - make sure extras like PROXY mode are supported
|
// - make sure extras like PROXY mode are supported
|
||||||
// - support TUN mode
|
// - support TUN mode
|
||||||
|
|
||||||
|
// Process options.
|
||||||
|
terminateTLS := false
|
||||||
|
proxyProtocol := 0
|
||||||
|
for _, o := range opts {
|
||||||
|
switch opt := o.(type) {
|
||||||
|
case serviceOptionTerminateTLS:
|
||||||
|
terminateTLS = true
|
||||||
|
case serviceOptionPROXYProtocol:
|
||||||
|
proxyProtocol = opt.version
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown opts FunnelOption type %T", o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
_, err := s.Up(ctx)
|
_, err := s.Up(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1288,7 +1307,13 @@ func (s *Server) ListenService(name string, port uint16) (net.Listener, error) {
|
|||||||
|
|
||||||
lc := s.localClient
|
lc := s.localClient
|
||||||
|
|
||||||
// TODO: check for ACL tags
|
st, err := lc.StatusWithoutPeers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("fetching ACL tags: %w", err)
|
||||||
|
}
|
||||||
|
if st.Self.Tags == nil || st.Self.Tags.Len() == 0 {
|
||||||
|
return nil, ErrUntaggedServiceHost
|
||||||
|
}
|
||||||
|
|
||||||
prefs, err := lc.GetPrefs(ctx)
|
prefs, err := lc.GetPrefs(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1314,17 +1339,13 @@ func (s *Server) ListenService(name string, port uint16) (net.Listener, error) {
|
|||||||
srvConfig = new(ipn.ServeConfig)
|
srvConfig = new(ipn.ServeConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start listening on a TCP socket. We will direct the local client to
|
// Start listening on a TCP socket.
|
||||||
// forward connections to this listener.
|
|
||||||
ln, err := net.Listen("tcp", "localhost:0")
|
ln, err := net.Listen("tcp", "localhost:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("starting local listener: %w", err)
|
return nil, fmt.Errorf("starting local listener: %w", err)
|
||||||
}
|
}
|
||||||
|
// Forward all connections from service-hostname:port to our socket.
|
||||||
// TODO:
|
srvConfig.SetTCPForwarding(port, ln.Addr().String(), terminateTLS, proxyProtocol, name)
|
||||||
// - Handle terminateTLS
|
|
||||||
// - Handle proxyProtocol
|
|
||||||
srvConfig.SetTCPForwarding(port, ln.Addr().String(), false, 0, name)
|
|
||||||
|
|
||||||
if err := lc.SetServeConfig(ctx, srvConfig); err != nil {
|
if err := lc.SetServeConfig(ctx, srvConfig); err != nil {
|
||||||
ln.Close()
|
ln.Close()
|
||||||
|
|||||||
@ -784,6 +784,10 @@ func TestListenService(t *testing.T) {
|
|||||||
netip.MustParsePrefix(serviceVIP + `/32`),
|
netip.MustParsePrefix(serviceVIP + `/32`),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
serviceHostNode := control.Node(serviceHost.lb.NodeKey())
|
||||||
|
serviceHostNode.Tags = append(serviceHostNode.Tags, "some-tag")
|
||||||
|
control.UpdateNode(serviceHostNode)
|
||||||
|
|
||||||
ln := must.Get(serviceHost.ListenService(serviceName.String(), servicePort))
|
ln := must.Get(serviceHost.ListenService(serviceName.String(), servicePort))
|
||||||
defer ln.Close()
|
defer ln.Close()
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user