mirror of
https://github.com/tailscale/tailscale.git
synced 2025-10-28 14:51:32 +01:00
Fixes #17283 Change-Id: Ia84d269683e4a68d7d10562561204934eeaf53bb Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
75 lines
2.4 KiB
Go
75 lines
2.4 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
//go:build !ts_omit_netstack
|
|
|
|
package ipnlocal
|
|
|
|
import (
|
|
"net"
|
|
"net/netip"
|
|
"time"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip"
|
|
"tailscale.com/types/ptr"
|
|
)
|
|
|
|
// TCPHandlerForDst returns a TCP handler for connections to dst, or nil if
|
|
// no handler is needed. It also returns a list of TCP socket options to
|
|
// apply to the socket before calling the handler.
|
|
// TCPHandlerForDst is called both for connections to our node's local IP
|
|
// as well as to the service IP (quad 100).
|
|
func (b *LocalBackend) TCPHandlerForDst(src, dst netip.AddrPort) (handler func(c net.Conn) error, opts []tcpip.SettableSocketOption) {
|
|
// First handle internal connections to the service IP
|
|
hittingServiceIP := dst.Addr() == magicDNSIP || dst.Addr() == magicDNSIPv6
|
|
if hittingServiceIP {
|
|
switch dst.Port() {
|
|
case 80:
|
|
// TODO(mpminardi): do we want to show an error message if the web client
|
|
// has been disabled instead of the more "basic" web UI?
|
|
if b.ShouldRunWebClient() {
|
|
return b.handleWebClientConn, opts
|
|
}
|
|
return b.HandleQuad100Port80Conn, opts
|
|
case DriveLocalPort:
|
|
return b.handleDriveConn, opts
|
|
}
|
|
}
|
|
|
|
if f, ok := hookServeTCPHandlerForVIPService.GetOk(); ok {
|
|
if handler := f(b, dst, src); handler != nil {
|
|
return handler, opts
|
|
}
|
|
}
|
|
// Then handle external connections to the local IP.
|
|
if !b.isLocalIP(dst.Addr()) {
|
|
return nil, nil
|
|
}
|
|
if dst.Port() == 22 && b.ShouldRunSSH() {
|
|
// Use a higher keepalive idle time for SSH connections, as they are
|
|
// typically long lived and idle connections are more likely to be
|
|
// intentional. Ideally we would turn this off entirely, but we can't
|
|
// tell the difference between a long lived connection that is idle
|
|
// vs a connection that is dead because the peer has gone away.
|
|
// We pick 72h as that is typically sufficient for a long weekend.
|
|
opts = append(opts, ptr.To(tcpip.KeepaliveIdleOption(72*time.Hour)))
|
|
return b.handleSSHConn, opts
|
|
}
|
|
// TODO(will,sonia): allow customizing web client port ?
|
|
if dst.Port() == webClientPort && b.ShouldExposeRemoteWebClient() {
|
|
return b.handleWebClientConn, opts
|
|
}
|
|
if port, ok := b.GetPeerAPIPort(dst.Addr()); ok && dst.Port() == port {
|
|
return func(c net.Conn) error {
|
|
b.handlePeerAPIConn(src, dst, c)
|
|
return nil
|
|
}, opts
|
|
}
|
|
if f, ok := hookTCPHandlerForServe.GetOk(); ok {
|
|
if handler := f(b, dst.Port(), src, nil); handler != nil {
|
|
return handler, opts
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|