|
|
@ -21,6 +21,7 @@ import (
|
|
|
|
"net/netip"
|
|
|
|
"net/netip"
|
|
|
|
"os"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"path/filepath"
|
|
|
|
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
@ -767,7 +768,7 @@ func (s *Server) Listen(network, addr string) (net.Listener, error) {
|
|
|
|
// ListenTLS announces only on the Tailscale network.
|
|
|
|
// ListenTLS announces only on the Tailscale network.
|
|
|
|
// It returns a TLS listener wrapping the tsnet listener.
|
|
|
|
// It returns a TLS listener wrapping the tsnet listener.
|
|
|
|
// It will start the server if it has not been started yet.
|
|
|
|
// It will start the server if it has not been started yet.
|
|
|
|
func (s *Server) ListenTLS(network string, addr string) (net.Listener, error) {
|
|
|
|
func (s *Server) ListenTLS(network, addr string) (net.Listener, error) {
|
|
|
|
if network != "tcp" {
|
|
|
|
if network != "tcp" {
|
|
|
|
return nil, fmt.Errorf("ListenTLS(%q, %q): only tcp is supported", network, addr)
|
|
|
|
return nil, fmt.Errorf("ListenTLS(%q, %q): only tcp is supported", network, addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -822,28 +823,32 @@ func FunnelOnly() FunnelOption { return funnelOnly(1) }
|
|
|
|
// and the only other supported addrs currently are ":8443" and ":10000".
|
|
|
|
// and the only other supported addrs currently are ":8443" and ":10000".
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// It will start the server if it has not been started yet.
|
|
|
|
// It will start the server if it has not been started yet.
|
|
|
|
func (s *Server) ListenFunnel(network string, addr string, opts ...FunnelOption) (net.Listener, error) {
|
|
|
|
func (s *Server) ListenFunnel(network, addr string, opts ...FunnelOption) (net.Listener, error) {
|
|
|
|
if network != "tcp" {
|
|
|
|
if network != "tcp" {
|
|
|
|
return nil, fmt.Errorf("ListenFunnel(%q, %q): only tcp is supported", network, addr)
|
|
|
|
return nil, fmt.Errorf("ListenFunnel(%q, %q): only tcp is supported", network, addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch addr {
|
|
|
|
host, portStr, err := net.SplitHostPort(addr)
|
|
|
|
case ":443", ":8443", ":10000":
|
|
|
|
if err != nil {
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
return nil, fmt.Errorf(`ListenFunnel(%q, %q): only valid addrs are ":443", ":8443", and ":10000"`, network, addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
if host != "" {
|
|
|
|
|
|
|
|
return nil, fmt.Errorf("ListenFunnel(%q, %q): host must be empty", network, addr)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
port, err := strconv.ParseUint(portStr, 10, 16)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
ctx := context.Background()
|
|
|
|
st, err := s.Up(ctx)
|
|
|
|
st, err := s.Up(ctx)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(st.CertDomains) == 0 {
|
|
|
|
if err := ipn.CheckFunnelAccess(uint16(port), st.Self.Capabilities); err != nil {
|
|
|
|
return nil, errors.New("tsnet: you must enable HTTPS in the admin panel to proceed")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ipn.CheckFunnelAccess(st.Self.Capabilities); err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
lc, err := s.LocalClient() // do local client first before listening.
|
|
|
|
lc, err := s.LocalClient()
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -857,7 +862,7 @@ func (s *Server) ListenFunnel(network string, addr string, opts ...FunnelOption)
|
|
|
|
srvConfig = &ipn.ServeConfig{}
|
|
|
|
srvConfig = &ipn.ServeConfig{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
domain := st.CertDomains[0]
|
|
|
|
domain := st.CertDomains[0]
|
|
|
|
hp := ipn.HostPort(domain + addr) // valid only because of the strong restrictions on addr above
|
|
|
|
hp := ipn.HostPort(domain + ":" + portStr)
|
|
|
|
if !srvConfig.AllowFunnel[hp] {
|
|
|
|
if !srvConfig.AllowFunnel[hp] {
|
|
|
|
mak.Set(&srvConfig.AllowFunnel, hp, true)
|
|
|
|
mak.Set(&srvConfig.AllowFunnel, hp, true)
|
|
|
|
srvConfig.AllowFunnel[hp] = true
|
|
|
|
srvConfig.AllowFunnel[hp] = true
|
|
|
|