Compare commits

...

8 Commits

Author SHA1 Message Date
Denton Gentry
949c400302 VERSION.txt: this is v1.30.1
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
2022-09-08 15:36:08 -07:00
Brad Fitzpatrick
0f2a786097 go.toolchain.rev: bump to Go 1.19.1
See https://github.com/tailscale/go/pull/34

Change-Id: I56806358cd1be4a2b8f509883e47c93083d82bdf
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
(cherry picked from commit 2266b59446)
2022-09-08 08:24:55 -07:00
Colin Adler
1a4f0f50a7 wgengine/magicsock: fix panic in http debug server
Fixes an panic in `(*magicsock.Conn).ServeHTTPDebug` when the
`recentPongs` ring buffer for an endpoint wraps around.

Signed-off-by: Colin Adler <colin1adler@gmail.com>
(cherry picked from commit 9c8bbc7888)
2022-09-08 07:14:03 -07:00
Maisem Ali
66cc9e6301 docs/k8s: make run.sh handle SIGINT
It was previously using jobcontrol to achieve this, but that apparently
doesn't work when there is no tty. This makes it so that it directly
handles SIGINT and SIGTERM and passes it on to tailscaled. I tested this
works on a Digital Ocean K8s cluster.

Fixes #5512

Signed-off-by: Maisem Ali <maisem@tailscale.com>
(cherry picked from commit 060ecb010f)
2022-09-08 05:28:57 -07:00
James Tucker
78584a8552 wgengine: fix race on endpoints in getStatus
Signed-off-by: James Tucker <james@tailscale.com>
(cherry picked from commit 265b008e49)
2022-09-07 19:53:58 -07:00
Andrew Dunham
bd14112d0b wgengine/netstack: only accept connection after dialing (#5503)
If we accept a forwarded TCP connection before dialing, we can
erroneously signal to a client that we support IPv6 (or IPv4) without
that actually being possible. Instead, we only complete the client's TCP
handshake after we've dialed the outbound connection; if that fails, we
respond with a RST.

Updates #5425 (maybe fixes!)

Signed-off-by: Andrew Dunham <andrew@tailscale.com>
(cherry picked from commit 9240f5c1e2)
2022-09-07 19:36:17 -07:00
Xe Iaso
b14e31831a cmd/gitops-pusher: standardize hujson before posting to validate (#5525)
Apparently the validate route doesn't check content-types or handle
hujson with comments correctly. This patch makes gitops-pusher convert
the hujson to normal json.

Signed-off-by: Xe <xe@tailscale.com>

Signed-off-by: Xe <xe@tailscale.com>
(cherry picked from commit 3564fd61b5)
2022-09-01 14:57:46 -07:00
Denton Gentry
0b00b7a135 VERSION.txt: this is v1.28.0
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
2022-08-31 06:25:05 -07:00
7 changed files with 111 additions and 44 deletions

View File

@@ -1 +1 @@
1.29.0
1.30.1

View File

@@ -8,6 +8,7 @@
package main
import (
"bytes"
"context"
"crypto/sha256"
"encoding/json"
@@ -264,13 +265,16 @@ func applyNewACL(ctx context.Context, tailnet, apiKey, policyFname, oldEtag stri
}
func testNewACLs(ctx context.Context, tailnet, apiKey, policyFname string) error {
fin, err := os.Open(policyFname)
data, err := os.ReadFile(policyFname)
if err != nil {
return err
}
data, err = hujson.Standardize(data)
if err != nil {
return err
}
defer fin.Close()
req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("https://api.tailscale.com/api/v2/tailnet/%s/acl/validate", tailnet), fin)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("https://api.tailscale.com/api/v2/tailnet/%s/acl/validate", tailnet), bytes.NewBuffer(data))
if err != nil {
return err
}

View File

@@ -4,8 +4,6 @@
#! /bin/sh
set -m # enable job control
export PATH=$PATH:/tailscale/bin
TS_AUTH_KEY="${TS_AUTH_KEY:-}"
@@ -60,8 +58,16 @@ if [[ ! -z "${TS_TAILSCALED_EXTRA_ARGS}" ]]; then
TAILSCALED_ARGS="${TAILSCALED_ARGS} ${TS_TAILSCALED_EXTRA_ARGS}"
fi
handler() {
echo "Caught SIGINT/SIGTERM, shutting down tailscaled"
kill -s SIGINT $PID
wait ${PID}
}
echo "Starting tailscaled"
tailscaled ${TAILSCALED_ARGS} &
PID=$!
trap handler SIGINT SIGTERM
UP_ARGS="--accept-dns=${TS_ACCEPT_DNS}"
if [[ ! -z "${TS_ROUTES}" ]]; then
@@ -82,4 +88,5 @@ if [[ ! -z "${TS_DEST_IP}" ]]; then
iptables -t nat -I PREROUTING -d "$(tailscale --socket=/tmp/tailscaled.sock ip -4)" -j DNAT --to-destination "${TS_DEST_IP}"
fi
fg
echo "Waiting for tailscaled to exit"
wait ${PID}

View File

@@ -1 +1 @@
6dca83b256c7decd3dd6706ee47e04f21a0b935c
b13188dd36c1ad2509796ce10b6a1231b200c36a

View File

@@ -172,6 +172,11 @@ func printEndpointHTML(w io.Writer, ep *endpoint) {
break
}
pos := (int(s.recentPong) - i) % len(s.recentPongs)
// If s.recentPongs wraps around pos will be negative, so start
// again from the end of the slice.
if pos < 0 {
pos += len(s.recentPongs)
}
pr := s.recentPongs[pos]
fmt.Fprintf(w, "<li>pong %v ago: in %v, from %v src %v</li>\n",
fmtMono(pr.pongAt), pr.latency.Round(time.Millisecond/10),

View File

@@ -743,47 +743,64 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) {
ns.removeSubnetAddress(dialIP)
}
}()
var wq waiter.Queue
ep, err := r.CreateEndpoint(&wq)
if err != nil {
ns.logf("CreateEndpoint error for %s: %v", stringifyTEI(reqDetails), err)
r.Complete(true) // sends a RST
return
// We can't actually create the endpoint or complete the inbound
// request until we're sure that the connection can be handled by this
// endpoint. This function sets up the TCP connection and should be
// called immediately before a connection is handled.
createConn := func() *gonet.TCPConn {
ep, err := r.CreateEndpoint(&wq)
if err != nil {
ns.logf("CreateEndpoint error for %s: %v", stringifyTEI(reqDetails), err)
r.Complete(true) // sends a RST
return nil
}
r.Complete(false)
// SetKeepAlive so that idle connections to peers that have forgotten about
// the connection or gone completely offline eventually time out.
// Applications might be setting this on a forwarded connection, but from
// userspace we can not see those, so the best we can do is to always
// perform them with conservative timing.
// TODO(tailscale/tailscale#4522): Netstack defaults match the Linux
// defaults, and results in a little over two hours before the socket would
// be closed due to keepalive. A shorter default might be better, or seeking
// a default from the host IP stack. This also might be a useful
// user-tunable, as in userspace mode this can have broad implications such
// as lingering connections to fork style daemons. On the other side of the
// fence, the long duration timers are low impact values for battery powered
// peers.
ep.SocketOptions().SetKeepAlive(true)
// The ForwarderRequest.CreateEndpoint above asynchronously
// starts the TCP handshake. Note that the gonet.TCPConn
// methods c.RemoteAddr() and c.LocalAddr() will return nil
// until the handshake actually completes. But we have the
// remote address in reqDetails instead, so we don't use
// gonet.TCPConn.RemoteAddr. The byte copies in both
// directions to/from the gonet.TCPConn in forwardTCP will
// block until the TCP handshake is complete.
return gonet.NewTCPConn(&wq, ep)
}
r.Complete(false)
// SetKeepAlive so that idle connections to peers that have forgotten about
// the connection or gone completely offline eventually time out.
// Applications might be setting this on a forwarded connection, but from
// userspace we can not see those, so the best we can do is to always
// perform them with conservative timing.
// TODO(tailscale/tailscale#4522): Netstack defaults match the Linux
// defaults, and results in a little over two hours before the socket would
// be closed due to keepalive. A shorter default might be better, or seeking
// a default from the host IP stack. This also might be a useful
// user-tunable, as in userspace mode this can have broad implications such
// as lingering connections to fork style daemons. On the other side of the
// fence, the long duration timers are low impact values for battery powered
// peers.
ep.SocketOptions().SetKeepAlive(true)
// The ForwarderRequest.CreateEndpoint above asynchronously
// starts the TCP handshake. Note that the gonet.TCPConn
// methods c.RemoteAddr() and c.LocalAddr() will return nil
// until the handshake actually completes. But we have the
// remote address in reqDetails instead, so we don't use
// gonet.TCPConn.RemoteAddr. The byte copies in both
// directions to/from the gonet.TCPConn in forwardTCP will
// block until the TCP handshake is complete.
c := gonet.NewTCPConn(&wq, ep)
// DNS
if reqDetails.LocalPort == 53 && (dialIP == magicDNSIP || dialIP == magicDNSIPv6) {
c := createConn()
if c == nil {
return
}
go ns.dns.HandleTCPConn(c, netip.AddrPortFrom(clientRemoteIP, reqDetails.RemotePort))
return
}
if ns.lb != nil {
if reqDetails.LocalPort == 22 && ns.processSSH() && ns.isLocalIP(dialIP) {
c := createConn()
if c == nil {
return
}
if err := ns.lb.HandleSSHConn(c); err != nil {
ns.logf("ssh error: %v", err)
}
@@ -791,6 +808,11 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) {
}
if port, ok := ns.lb.GetPeerAPIPort(dialIP); ok {
if reqDetails.LocalPort == port && ns.isLocalIP(dialIP) {
c := createConn()
if c == nil {
return
}
src := netip.AddrPortFrom(clientRemoteIP, reqDetails.RemotePort)
dst := netip.AddrPortFrom(dialIP, port)
ns.lb.ServePeerAPIConnection(src, dst, c)
@@ -798,12 +820,20 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) {
}
}
if reqDetails.LocalPort == 80 && (dialIP == magicDNSIP || dialIP == magicDNSIPv6) {
c := createConn()
if c == nil {
return
}
ns.lb.HandleQuad100Port80Conn(c)
return
}
}
if ns.ForwardTCPIn != nil {
c := createConn()
if c == nil {
return
}
ns.ForwardTCPIn(c, reqDetails.LocalPort)
return
}
@@ -811,11 +841,13 @@ func (ns *Impl) acceptTCP(r *tcp.ForwarderRequest) {
dialIP = netaddr.IPv4(127, 0, 0, 1)
}
dialAddr := netip.AddrPortFrom(dialIP, uint16(reqDetails.LocalPort))
ns.forwardTCP(c, clientRemoteIP, &wq, dialAddr)
if !ns.forwardTCP(createConn, clientRemoteIP, &wq, dialAddr) {
r.Complete(true) // sends a RST
}
}
func (ns *Impl) forwardTCP(client *gonet.TCPConn, clientRemoteIP netip.Addr, wq *waiter.Queue, dialAddr netip.AddrPort) {
defer client.Close()
func (ns *Impl) forwardTCP(getClient func() *gonet.TCPConn, clientRemoteIP netip.Addr, wq *waiter.Queue, dialAddr netip.AddrPort) (handled bool) {
dialAddrStr := dialAddr.String()
if debugNetstack {
ns.logf("[v2] netstack: forwarding incoming connection to %s", dialAddrStr)
@@ -823,6 +855,7 @@ func (ns *Impl) forwardTCP(client *gonet.TCPConn, clientRemoteIP netip.Addr, wq
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
waitEntry, notifyCh := waiter.NewChannelEntry(waiter.EventHUp) // TODO(bradfitz): right EventMask?
wq.EventRegister(&waitEntry)
defer wq.EventUnregister(&waitEntry)
@@ -840,13 +873,29 @@ func (ns *Impl) forwardTCP(client *gonet.TCPConn, clientRemoteIP netip.Addr, wq
}
cancel()
}()
// Attempt to dial the outbound connection before we accept the inbound one.
var stdDialer net.Dialer
server, err := stdDialer.DialContext(ctx, "tcp", dialAddrStr)
if err != nil {
ns.logf("netstack: could not connect to local server at %s: %v", dialAddrStr, err)
ns.logf("netstack: could not connect to local server at %s: %v", dialAddr.String(), err)
return
}
defer server.Close()
// If we get here, either the getClient call below will succeed and
// return something we can Close, or it will fail and will properly
// respond to the client with a RST. Either way, the caller no longer
// needs to clean up the client connection.
handled = true
// We dialed the connection; we can complete the client's TCP handshake.
client := getClient()
if client == nil {
return
}
defer client.Close()
backendLocalAddr := server.LocalAddr().(*net.TCPAddr)
backendLocalIPPort := netaddr.Unmap(backendLocalAddr.AddrPort())
ns.e.RegisterIPPortIdentity(backendLocalIPPort, clientRemoteIP)
@@ -865,6 +914,7 @@ func (ns *Impl) forwardTCP(client *gonet.TCPConn, clientRemoteIP netip.Addr, wq
ns.logf("proxy connection closed with error: %v", err)
}
ns.logf("[v2] netstack: forwarder connection to %s closed", dialAddrStr)
return
}
func (ns *Impl) acceptUDP(r *udp.ForwarderRequest) {

View File

@@ -1005,6 +1005,7 @@ func (e *userspaceEngine) getStatus() (*Status, error) {
closing := e.closing
peerKeys := make([]key.NodePublic, len(e.peerSequence))
copy(peerKeys, e.peerSequence)
localAddrs := append([]tailcfg.Endpoint(nil), e.endpoints...)
e.mu.Unlock()
if closing {
@@ -1020,7 +1021,7 @@ func (e *userspaceEngine) getStatus() (*Status, error) {
return &Status{
AsOf: time.Now(),
LocalAddrs: append([]tailcfg.Endpoint(nil), e.endpoints...),
LocalAddrs: localAddrs,
Peers: peers,
DERPs: derpConns,
}, nil