Skip to content

Commit

Permalink
ipn/ipnlocal: [serve] listen on all-interfaces for macOS sandboxed (#…
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
shayne committed Jan 20, 2023
1 parent 6793685 commit 4471e40
Showing 1 changed file with 33 additions and 1 deletion.
34 changes: 33 additions & 1 deletion ipn/ipnlocal/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"tailscale.com/types/logger"
"tailscale.com/util/mak"
"tailscale.com/util/strs"
"tailscale.com/version"
)

// serveHTTPContextKey is the context.Value key for a *serveHTTPContext.
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 4471e40

Please sign in to comment.