ipn/ipnlocal: [serve] listen on all-interfaces for macOS sandboxed (#6771)

On macOS (AppStore and macsys), we need to bind to ""/all-interfaces
due to the network sandbox. Ideally we would only bind to the
Tailscale interface, but macOS errors out if we try to
to listen on privileged ports binding only to a specific
interface.

We also implement the lc.Control hook, same as we do for
peerapi. It doesn't solve our problem but it's better that
we do and would likely be required when Apple gets around to
fixing per-interface priviliged port binding.

Fixes: #6364

Signed-off-by: Shayne Sweeney <shayne@tailscale.com>
This commit is contained in:
shayne 2023-01-20 13:40:56 -05:00 committed by GitHub
parent 6793685bba
commit 4471e403aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -33,6 +33,7 @@
"tailscale.com/types/logger"
"tailscale.com/util/mak"
"tailscale.com/util/strs"
"tailscale.com/version"
)
// serveHTTPContextKey is the context.Value key for a *serveHTTPContext.
@ -91,7 +92,38 @@ func (s *serveListener) Close() error {
// Listen is retried until the context is canceled.
func (s *serveListener) Run() {
for {
ln, err := net.Listen("tcp", s.ap.String())
ip := s.ap.Addr()
ipStr := ip.String()
var lc net.ListenConfig
if initListenConfig != nil {
// On macOS, this sets the lc.Control hook to
// setsockopt the interface index to bind to. This is
// required by the network sandbox to allow binding to
// a specific interface. Without this hook, the system
// chooses a default interface to bind to.
if err := initListenConfig(&lc, ip, s.b.prevIfState, s.b.dialer.TUNName()); err != nil {
s.logf("serve failed to init listen config %v, backing off: %v", s.ap, err)
s.bo.BackOff(s.ctx, err)
continue
}
// On macOS (AppStore or macsys) and if we're binding to a privileged port,
if version.IsSandboxedMacOS() && s.ap.Port() < 1024 {
// On macOS, we need to bind to ""/all-interfaces due to
// the network sandbox. Ideally we would only bind to the
// Tailscale interface, but macOS errors out if we try to
// to listen on privileged ports binding only to a specific
// interface. (#6364)
ipStr = ""
}
}
tcp4or6 := "tcp4"
if ip.Is6() {
tcp4or6 = "tcp6"
}
ln, err := lc.Listen(s.ctx, tcp4or6, net.JoinHostPort(ipStr, fmt.Sprint(s.ap.Port())))
if err != nil {
if s.shouldWarnAboutListenError(err) {
s.logf("serve failed to listen on %v, backing off: %v", s.ap, err)