Prior to Tailscale 1.12 it detected UPnP on any port.
Starting with Tailscale 1.11.x, it stopped detecting UPnP on all ports.
Then start plumbing its discovered Location header port number to the
code that was assuming port 5000.
Fixes#2109
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
For testing pfSense clients "behind" pfSense on Digital Ocean where
the main interface still exists. This is easier for debugging.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Instead of hashing the humanly formatted forms of a number,
hash the native machine bits of the integers themselves.
There is a small performance gain for this:
name old time/op new time/op delta
Hash-8 75.7µs ± 1% 76.0µs ± 2% ~ (p=0.315 n=10+9)
HashMapAcyclic-8 63.1µs ± 3% 61.3µs ± 1% -2.77% (p=0.000 n=10+10)
TailcfgNode-8 10.3µs ± 1% 10.2µs ± 1% -1.48% (p=0.000 n=10+10)
HashArray-8 1.07µs ± 1% 1.05µs ± 1% -1.79% (p=0.000 n=10+10)
Signed-off-by: Joe Tsai <joetsai@digital-static.net>
The swapping of bufio.Writer between hasher and mapHasher is subtle.
Just embed a hasher in mapHasher to avoid complexity here.
No notable change in performance:
name old time/op new time/op delta
Hash-8 76.7µs ± 1% 77.0µs ± 1% ~ (p=0.182 n=9+10)
HashMapAcyclic-8 62.4µs ± 1% 62.5µs ± 1% ~ (p=0.315 n=10+9)
TailcfgNode-8 10.3µs ± 1% 10.3µs ± 1% -0.62% (p=0.004 n=10+9)
HashArray-8 1.07µs ± 1% 1.06µs ± 1% -0.98% (p=0.001 n=8+9)
Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This is a simplified rate limiter geared for exactly our needs:
A fast, mono.Time-based rate limiter for use in tstun.
It was generated by stripping down the x/time/rate rate limiter
to just our needs and switching it to use mono.Time.
It removes one time.Now call per packet.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
magicsock makes multiple calls to Now per packet.
Move to mono.Now. Changing some of the calls to
use package mono has a cascading effect,
causing non-per-packet call sites to also switch.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
There's a call to Now once per packet.
Move to mono.Now.
Though the current implementation provides high precision,
we document it to be coarse, to preserve the ability
to switch to a coarse monotonic time later.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Package mono provides a fast monotonic time.
Its primary advantage is that it is fast:
It is approximately twice as fast as time.Now.
This is because time.Now uses two clock calls,
one for wall time and one for monotonic time.
We ask for the current time 4-6 times per network packet.
At ~50ns per call to time.Now, that's enough to show
up in CPU profiles.
Package mono is a first step towards addressing that.
It is designed to be a near drop-in replacement for package time.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Go 1.17 switches to a register ABI on amd64 platforms.
Part of that switch is that go and defer calls use an argument-less
closure, which allocates. This means that we have an extra
alloc in some DNS work. That's unfortunate but not a showstopper,
and I don't see a clear path to fixing it.
The other performance benefits from the register ABI will all
but certainly outweigh this extra alloc.
Fixes#2545
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The kr/pty module moved to creack/pty per the kr/pty README[1].
creack/pty brings in support for a number of OS/arch combos that
are lacking in kr/pty.
Run `go mod tidy` while here.
[1] https://github.com/kr/pty/blob/master/README.md
Signed-off-by: Aaron Bieber <aaron@bolddaemon.com>
I don't know how to get access to a real packet. Basing this commit
entirely off:
+------------+--------------+------------------------------+
| Field Name | Field Type | Description |
+------------+--------------+------------------------------+
| NAME | domain name | MUST be 0 (root domain) |
| TYPE | u_int16_t | OPT (41) |
| CLASS | u_int16_t | requestor's UDP payload size |
| TTL | u_int32_t | extended RCODE and flags |
| RDLEN | u_int16_t | length of all RDATA |
| RDATA | octet stream | {attribute,value} pairs |
+------------+--------------+------------------------------+
From https://datatracker.ietf.org/doc/html/rfc6891#section-6.1.2
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
The handoff between tstun.Wrap's Read and poll methods
is one of the per-packet hotspots. It shows up in pprof.
Making outbound buffered increases throughput.
It is hard to measure exactly how much, because the numbers
are highly variable, but I'd estimate it at about 1%,
using the best observed max throughput across three runs.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The handoff between tstun.Wrap's Read and poll methods
is one of the per-packet hotspots. It shows up in pprof.
Making outbound buffered increases throughput.
It is hard to measure exactly how much, because the numbers
are highly variable, but I'd estimate it at about 1%,
using the best observed max throughput across three runs.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Tested manually with:
$ go test -v ./net/dnscache/ -dial-test=bogusplane.dev.tailscale.com:80
Where bogusplane has three A records, only one of which works.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
A previously added metric which was float64 was being ignored in tsweb, because it previously
only accepted int64 and ints. It can be handled in the same way as ints.
Signed-off-by: julianknodt <julianknodt@gmail.com>
Instead of blasting away at all upstream resolvers at the same time,
make a timing plan upon reconfiguration and have each upstream have an
associated start delay, depending on the overall forwarding config.
So now if you have two or four upstream Google or Cloudflare DNS
servers (e.g. two IPv4 and two IPv6), we now usually only send a
query, not four.
This is especially nice on iOS where we start fewer DoH queries and
thus fewer HTTP/1 requests (because we still disable HTTP/2 on iOS),
fewer sockets, fewer goroutines, and fewer associated HTTP buffers,
etc, saving overall memory burstiness.
Fixes#2436
Updates tailscale/corp#2250
Updates tailscale/corp#2238
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Add a place to hang state in a future change for #2436.
For now this just simplifies the send signature without
any functional change.
Updates #2436
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The previous algorithm used a map of all visited pointers.
The strength of this approach is that it quickly prunes any nodes
that we have ever visited before. The detriment of the approach
is that pruning is heavily dependent on the order that pointers
were visited. This is especially relevant for hashing a map
where map entries are visited in a non-deterministic manner,
which would cause the map hash to be non-deterministic
(which defeats the point of a hash).
This new algorithm uses a stack of all visited pointers,
similar to how github.com/google/go-cmp performs cycle detection.
When we visit a pointer, we push it onto the stack, and when
we leave a pointer, we pop it from the stack.
Before visiting a pointer, we first check whether the pointer exists
anywhere in the stack. If yes, then we prune the node.
The detriment of this approach is that we may hash a node more often
than before since we do not prune as aggressively.
The set of visited pointers up until any node is only the
path of nodes up to that node and not any other pointers
that may have been visited elsewhere. This provides us
deterministic hashing regardless of visit order.
We can now delete hashMapFallback and associated complexity,
which only exists because the previous approach was non-deterministic
in the presence of cycles.
This fixes a failure of the old algorithm where obviously different
values are treated as equal because the pruning was too aggresive.
See https://github.com/tailscale/tailscale/issues/2443#issuecomment-883653534
The new algorithm is slightly slower since it prunes less aggresively:
name old time/op new time/op delta
Hash-8 66.1µs ± 1% 68.8µs ± 1% +4.09% (p=0.000 n=19+19)
HashMapAcyclic-8 63.0µs ± 1% 62.5µs ± 1% -0.76% (p=0.000 n=18+19)
TailcfgNode-8 9.79µs ± 2% 9.88µs ± 1% +0.95% (p=0.000 n=19+17)
HashArray-8 643ns ± 1% 653ns ± 1% +1.64% (p=0.000 n=19+19)
However, a slower but more correct algorithm seems
more favorable than a faster but incorrect algorithm.
Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This prevents centos tests from timing out because sshd does reverse dns
lookups on every session being established instead of doing it once on
the acutal ssh connection being established. This is odd. Appending this
to the sshd config and restarting it seems to fix it though.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
TCP was done in 662fbd4a09.
This does the same for UDP.
Tested by hand. Integration tests will have to come later. I'd wanted
to do it in this commit, but the SOCKS5 server needed for interop
testing between two userspace nodes doesn't yet support UDP and I
didn't want to invent some whole new userspace packet injection
interface at this point, as SOCKS seems like a better route, but
that's its own bug.
Fixes#2302
RELNOTE=netstack mode can now UDP relay to subnets
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
A Go interface may hold any number of different concrete types.
Just because two underlying values hash to the same thing
does not mean the two values are identical if they have different
concrete types. As such, include the type in the hash.
Previously, this was incorrectly returning the internal port, and using that with the external
exposed IP when it did not use WANIPConnection2. In the case when we must provide a port, we
return it instead.
Noticed this while implementing the integration test for upnp.
Signed-off-by: julianknodt <julianknodt@gmail.com>
Seed the hash upon first use with the current time.
This ensures that the stability of the hash is bounded within
the lifetime of one program execution.
Hopefully, this prevents future bugs where someone assumes that
this hash is stable.
Signed-off-by: Joe Tsai <joetsai@digital-static.net>
Filch doesn't like having multiple processes competing
for the same log files (#937).
Parallel integration tests were all using the same log files.
Add a TS_LOGS_DIR env var that the integration test can use
to use separate log files per test.
Fixes#2269
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Prep for #1591 which will need to make Linux's router react to changes
that the link monitor observes.
The router package already depended on the monitor package
transitively. Now it's explicit.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Instead of logging lsof execution failures to stdout,
incorporate them into the returned error.
While we're here, make it clear that the file
success case always returns a nil error.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The maximum unix domain socket path length on darwin is 104 bytes,
including the trailing NUL.
On my machine, the path created by some newly added tests (6eecf3c9)
was too long, resulting in cryptic test failures.
Shorten the names of the tests, and add a check to make
the diagnosis easier next time.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The fact that Hash returns a [sha256.Size]byte leaks details about
the underlying hash implementation. This could very well be any other
hashing algorithm with a possible different block size.
Abstract this implementation detail away by declaring an opaque type
that is comparable. While we are changing the signature of UpdateHash,
rename it to just Update to reduce stutter (e.g., deephash.Update).
Signed-off-by: Joe Tsai <joetsai@digital-static.net>
It was a huge chunk of the overall log output and made debugging
difficult. Omit and summarize the spammy *.arpa parts instead.
Fixestailscale/corp#2066 (to which nobody had opinions, so)
With this, I can now:
* install Tailscale
* stop the GUI
* net stop Tailscale
* net start Tailscale
* tailscale up --unattended
(where the middle three steps simulate what would happen on a Windows
Server Core machine without a GUI)
Fixes#2137
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
To unify the Windows service and non-service/non-Windows paths a bit.
And provides a way to make Linux act like Windows for testing.
(notably, for testing the fix to #2137)
One perhaps visible change of this is that tailscaled.exe when run in
cmd.exe/powershell (not as a Windows Service) no longer uses the
"_daemon" autostart key. But in addition to being naturally what falls
out of this change, that's also what Windows users would likely want,
as otherwise the unattended mode user is ignored when the "_daemon"
autostart key is specified. Notably, this would let people debug what
their normally-run-as-a-service tailscaled is doing, even when they're
running in Unattended Mode.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Adds TS_DEBUG_UP_FLAG_GOOS for integration tests to make "tailscale
up" act like other OSes.
For an upcoming change to test #2137.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
We have different deps depending on the platform.
If we pick a privileged platform, we'll miss some deps.
If we use the union of all platforms, the integration test
won't compile on some platforms, because it'll import
packages that don't compile on that platform.
Give in to the madness and give each platform its own deps file.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The earlier 2ba36c294b started listening
for ip rule changes and only cared about DELRULE events, buts its subscription
included all rule events, including new ones, which meant we were then
catching our own ip rule creations and logging about how they were unknown.
Stop that log spam.
Updates #1591
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
For debugging & working on #1591 where certain versions of systemd-networkd
delete Tailscale's ip rule entries.
Updates #1591
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This moves the distribution definitions into a maintainable hujson file
instead of just existing as constants in `distros.go`. Comments are
maintained from the inline definitions.
This uses jennifer[1] for hygenic source tree creation. This allows us
to generate a unique top-level test for each VM run. This should
hopefully help make the output of `go test` easier to read.
This also separates each test out into its own top-level test so that we
can better track the time that each distro takes. I really wish there
was a way to have the `test_codegen.go` file _always_ run as a part of
the compile process instead of having to rely on people remembering to
run `go generate`, but I am limited by my tools.
This will let us remove the `-distro-regex` flag and use `go test -run`
to pick which distros are run.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
Add in UPnP portmapping, using goupnp library in order to get the UPnP client and run the
portmapping functions. This rips out anywhere where UPnP used to be in portmapping, and has a
flow separate from PMP and PCP.
RELNOTE=portmapper now supports UPnP mappings
Fixes#682
Updates #2109
Signed-off-by: julianknodt <julianknodt@gmail.com>
Recognize Cloudflare, Google, Quad9 which are by far the
majority of upstream DNS servers that people use.
RELNOTE=MagicDNS now uses DNS-over-HTTPS when querying popular upstream resolvers,
so DNS queries aren't sent in the clear over the Internet.
Updates #915 (might fix it?)
Updates #988 (gets us closer, if it fixes Android)
Updates #74 (not yet configurable, but progress)
Updates #2056 (not yet configurable, dup of #74?)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Added the net/speedtest package that contains code for starting up a
speedtest server and a client. The speedtest command for starting a
client takes in a duration for the speedtest as well as the host and
port of the speedtest server to connect to. The speedtest command for
starting a server takes in a host:port pair to listen on.
Signed-off-by: Aaditya Chaudhary <32117362+AadityaChaudhary@users.noreply.github.com>
Apparently this test was flaking because I critically misunderstood how
the kernel buffers UDP packets for senders. I'm trying to send more UDP
packets and will see if that helps.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
This test used to try to run this only once, but this variant of the
test attempts to run `tailscale status` up to 6 times in a loop with
exponential backoff.
This fixes the flakiness found in previous instances of this test.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
This adds some convenient defaults for -c, so that user-provided DERPs require less command line
flags.
Signed-off-by: julianknodt <julianknodt@gmail.com>
With netns handling localhost now, existing tests no longer
need special handling. The tests set up their connections to
localhost, and the connections work without fuss.
Remove the special handling for tests.
Also remove the hostinfo.TestCase support, since this was
the only use of it. It can be added back later if really
needed, but it would be better to try to make tests work
without special cases.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
netns_linux checked whether "ip rule" could run to determine
whether to use SO_MARK for network namespacing. However in
Linux environments which lack CAP_NET_ADMIN, such as various
container runtimes, the "ip rule" command succeeds but SO_MARK
fails due to lack of permission. SO_BINDTODEVICE would work in
these environments, but isn't tried.
In addition to running "ip rule" check directly whether SO_MARK
works or not. Among others, this allows Microsoft Azure App
Service and AWS App Runner to work.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Connections to a control server or log server on localhost,
used in a number of tests, are working right now because the
calls to SO_MARK in netns fail for non-root but then we ignore
the failure when running in tests.
Unfortunately that failure in SO_MARK also affects container
environments without CAP_NET_ADMIN, breaking Tailscale
connectivity. We're about to fix netns to recognize when SO_MARK
doesn't work and use SO_BINDTODEVICE instead. Doing so makes
tests fail, as their sockets now BINDTODEVICE of the default
route and cannot connect to localhost.
Add support to skip namespacing for localhost connections,
which Darwin and Windows already do. This is not conditional
on running within a test, if you tell tailscaled to connect
to localhost it will automatically use a non-namespaced
socket to do so.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Several other AWS services like App Run and Lightsail Containers
appear to be layers atop Fargate, to the point that we cannot easily
tell them apart from within the container. Contacting the metadata
service would distinguish them, but doing that from inside tailscaled
seems uncalled for. Just report them as Fargate.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Treat automated tests as their own, unique environment
rather than the type of container they are running in.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
The localapi was double-unescaping: once by net/http populating
the URL, and once by ourselves later. We need to start with the raw
escaped URL if we're doing it ourselves.
Started to write a test but it got invasive. Will have to add those
tests later in a commit that's not being cherry-picked to a release
branch.
Fixes#2288
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
logBufWriter had no serialization.
It just so happens that none of its users currently ever log concurrently.
Make it safe for concurrent use.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Regression from 6d10655dc3, which added
UpdatePrefs but didn't write it out to disk.
I'd planned on adding tests to state_test.go which is why I'd earlier
added 46896a9311 to prepare for making
such persistence tests easier to write, but turns out state_test.go
didn't even test UpdatePrefs, so I'm staying out of there.
Instead, this is tested using integration tests.
Fixes#2321
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
As Brad suggested, mem.RO allows for a lot of easy perf gains. There were also some smaller
changes outside of mem.RO, such as using hex.Decode instead of hex.DecodeString.
```
name old time/op new time/op delta
FromUAPI-8 14.7µs ± 3% 12.3µs ± 4% -16.58% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
FromUAPI-8 9.52kB ± 0% 7.04kB ± 0% -26.05% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
FromUAPI-8 77.0 ± 0% 29.0 ± 0% -62.34% (p=0.008 n=5+5)
```
Signed-off-by: julianknodt <julianknodt@gmail.com>
Adds a benchmark for FromUAPI in wgcfg.
It appears that it's not actually that slow, the main allocations are from the scanner and new
config.
Updates #1912.
Signed-off-by: julianknodt <julianknodt@gmail.com>
My spatial memory functions poorly with large files and the vms_test.go
file recently surpassed the point where it functions adequately. This
patch splits up vms_test.go into more files to make my spatial memory
function like I need it to.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
It was once believed that it might be useful. It wasn't. We never used it.
Remove it so we don't slowly leak memory.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
In theory, some of the other table-driven tests could be moved into this
form now but I didn't want to disturb too much good test code.
Includes a commented-out test for #2384 that is currently failing.
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
The DERPTestPort int meant two things before: which port to use, and
whether to disable TLS verification. Users would like to set the port
without disabling TLS, so break it into two options.
Updates #1264
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
To avoid the generated nixos disk images from becoming immune from the
GC, I delete the symlink to the nix store at the end of tests.
`t.Cleanup` runs at the end of a test. I changed this part of the code
to have a separate timer for how long it takes to run NixOS builds, but
I did that by using a subtest. This means that it was creating the NixOS
image, deleting its symlink and then trying to use that symlink to find
the resulting disk image, making the whole thing ineffectual.
This was a mistake. I am reverting this change made in
https://github.com/tailscale/tailscale/pull/2360 to remove this layer of
subtesting.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
This allows the test to be run inside a mounted filesystem,
which I'm doing now as a I develop on a linux VM.
Fixes#2367.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This tests incoming and outgoing UDP traffic. It would test incoming UDP
traffic however our socks server doesn't seem to allow for connecting to
destinations over UDP. When the socks server gets that support the
incoming test should pass without issue.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
This adapts the existing in-process logcatcher from tstest/integration
into a public type and uses it on the side of testcontrol. This also
fixes a bug in the Alpine Linux OpenRC unit that makes every value in
`/etc/default/tailscaled` exported into tailscaled's environment, a-la
systemd [Service].EnviromentFile.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
This does a few things:
1. Rewrites the tests so that we get a log of what individual tests
failed at the end of a test run.
2. Adds a test that runs an HTTP server via the tester tailscale node and
then has the VMs connect to that over Tailscale.
3. Dials the VM over Tailscale and ensures it answers SSH requests.
4. Other minor framework refactoring.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
Oracle Linux[1] is a CentOS fork. It is not very special. I am adding it
to the integration jungle because I am adding it to pkgs and the website
directions.
[1]: https://www.oracle.com/linux/
Signed-off-by: Christine Dodrill <xe@tailscale.com>
To remove some multi-case selects, we intentionally allowed
sends on closed channels (cc23049cd2).
However, we also introduced concurrent sends and closes,
which is a data race.
This commit fixes the data race. The mutexes here are uncontended,
and thus very cheap.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
It was caching too aggressively, as it didn't see our deps due to our
running "go install tailscaled" as a child process.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
version.sh was removed in commit 5088af68. Use `build_dist.sh shellvars`
to provide version information instead.
Signed-off-by: Irshad Pananilath <pmirshad+code@gmail.com>
This makes sure `tailscale status` and `tailscale ping` works. It also
switches goexpect to use a batch instead of manually banging out each
line, which makes the tests so much easier to read.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
Running hex.Encode(b, b) is a bad idea.
The first byte of input will overwrite the first two bytes of output.
Subsequent bytes have no impact on the output.
Not related to today's IPv6 bug, but...wh::ps.
This caused us to spuriously ignore some wireguard config updates.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Calculate whether the packet is injected directly,
rather than via an else branch.
Unify the exit paths. It is easier here than duplicating them.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Every TUN Read went through several multi-case selects.
We know from past experience with wireguard-go that these are slow
and cause scheduler churn.
The selects served two purposes: they separated errors from data and
gracefully handled shutdown. The first is fairly easy to replace by sending
errors and data over a single channel. The second, less so.
We considered a few approaches: Intricate webs of channels,
global condition variables. They all get ugly fast.
Instead, let's embrace the ugly and handle shutdown ungracefully.
It's horrible, but the horror is simple and localized.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The implementation of the preview function has changed since the
API was documented, update the document to match.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
We can't access b.netMap without holding b.mu.
We already grabbed it earlier in the function with the lock held.
Introduced in Nov 2020 in 7ea809897d.
Discovered during stress testing.
Apparently it's a pretty rare?
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
For instance, ephemeral nodes with only IPv6 addresses can now
SOCKS5-dial out to names like "foo" and resolve foo's IPv6 address
rather than foo's IPv4 address and get a "no route"
(*tcpip.ErrNoRoute) error from netstack's dialer.
Per https://github.com/tailscale/tailscale/issues/2268#issuecomment-870027626
which is only part of the isuse.
Updates #2268
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
We also have to make a one-off change to /etc/wsl.conf to stop every
invocation of wsl.exe clobbering the /etc/resolv.conf. This appears to
be a safe change to make permanently, as even though the resolv.conf is
constantly clobbered, it is always the same stable internal IP that is
set as a nameserver. (I believe the resolv.conf clobbering predates the
MS stub resolver.)
Tested on WSL2, should work for WSL1 too.
Fixes#775
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
This is preliminary work for using the directManager as
part of a wslManager on windows, where in addition to configuring
windows we'll use wsl.exe to edit the linux file system and modify the
system resolv.conf.
The pinholeFS is a little funky, but it's designed to work through
simple unix tools via wsl.exe without invoking bash. I would not have
thought it would stand on its own like this, but it turns out it's
useful for writing a test for the directManager.
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
After allowing for custom DERP maps, it's convenient to be able to see their latency in
netcheck. This adds a query to the local tailscaled for the current DERPMap.
Updates #1264
Signed-off-by: julianknodt <julianknodt@gmail.com>
Turns out we never reliably log the control plane URL a client connects
to. Do it here, and include the server public key, which might
inadvertently tell us something interesting some day.
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
This is an experiment to see how often this test would fail if we run it
on every commit. This depends on #2145 to fix a flaky part of the test.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
Okay, so, at a high level testing NixOS is a lot different than
other distros due to NixOS' determinism. Normally NixOS wants packages to
be defined in either an overlay, a custom packageOverrides or even
yolo-inline as a part of the system configuration. This is going to have
us take a different approach compared to other distributions. The overall
plan here is as following:
1. make the binaries as normal
2. template in their paths as raw strings to the nixos system module
3. run `nixos-generators -f qcow -o $CACHE_DIR/tailscale/nixos/version -c generated-config.nix`
4. pass that to the steps that make the virtual machine
It doesn't really make sense for us to use a premade virtual machine image
for this as that will make it harder to deterministically create the image.
Nix commands generate a lot of output, so their output is hidden behind the
`-verbose-nix-output` flag.
This unfortunately makes this test suite have a hard dependency on
Nix/NixOS, however the test suite has only ever been run on NixOS (and I
am not sure if it runs on other distros at all), so this probably isn't too
big of an issue.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
This has been bothering me for a while, but everytime I run format from the root directory
it also formats this file. I didn't want to add it to my other PRs but it's annoying to have to
revert it every time.
Signed-off-by: julianknodt <julianknodt@gmail.com>
Move derpmap.Prod to a static JSON file (go:generate'd) instead,
to make its role explicit. And add a TODO about making dnsfallback
use an update-over-time DERP map file instead of a baked-in one.
Updates #1264
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Previously this test would reach out to the public DERP servers in order
to help machines connect with eachother. This is not ideal given our
plans to run these tests completely disconnected from the internet. This
patch introduces an in-process DERP server running on its own randomly
assigned HTTP port.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
Occasionally the test framework would fail with a timeout due to a
virtual machine not phoning home in time. This seems to be happen
whenever qemu can't bind the VNC or SSH ports for a virtual machine.
This was fixed by taking the following actions:
1. Don't listen on VNC unless the `-use-vnc` flag is passed, this
removes the need to listen on VNC at all in most cases. The option to
use VNC is still left in for debugging virtual machines, but removing
this makes it easier to deal with (VNC uses this odd system of
"displays" that are mapped to ports above 5900, and qemu doesn't
offer a decent way to use a normal port number, so we just disable
VNC by default as a compromise).
2. Use a (hopefully) inactive port for SSH. In an ideal world I'd just
have the VM's SSH port be exposed via a Unix socket, however the QEMU
documentation doesn't really say if you can do this or not. While I
do more research, this stopgap will have to make do.
3. Strictly tie more VM resource lifetimes to the tests themselves.
Previously the disk image layers for virtual machines were only
cleaned up at the end of the test and existed in the parent
test-scoped temporary folder. This can make your tmpfs run out of
space, which is not ideal. This should minimize the use of temporary
storage as much as I know how to.
4. Strictly tie the qemu process lifetime to the lifetime of the test
using testing.T#Cleanup. Previously it used a defer statement to
clean up the qemu process, however if the tests timed out this defer
was not run. This left around an orphaned qemu process that had to be
killed manually. This change ensures that all qemu processes exit
when their relevant tests finish.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
Fix regression from 19c3e6cc9e
which made the locking coarser.
Found while debugging #2245, which ended up looking like a tswin/Windows
issue where Crawshaw had blocked cmd.exe's output.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This uses a debug envvar to optionally disable filter logging rate
limits by setting the environment variable
TS_DEBUG_FILTER_RATE_LIMIT_LOGS to "all", and if it matches,
the code will effectively disable the limits on the log rate by
setting the limit to 1 millisecond. This should make sure that all
filter logs will be captured.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
This change (subject to some limitations) looks for the EDNS OPT record
in queries and responses, clamping the size field to fit within our DNS
receive buffer. If the size field is smaller than the DNS receive buffer
then it is left unchanged.
I think we will eventually need to transition to fully processing the
DNS queries to handle all situations, but this should cover the most
common case.
Mostly fixes#2066
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
This adds a flag to the DERP server which specifies to verify clients through a local
tailscaled. It is opt-in, so should not affect existing clients, and is mainly intended for
users who want to run their own DERP servers. It assumes there is a local tailscaled running and
will attempt to hit it for peer status information.
Updates #1264
Signed-off-by: julianknodt <julianknodt@gmail.com>
Unused so far, but eventually we'll want this for SOCKS5 UDP binds (we
currently only do TCP with SOCKS5), and also for #2102 for forwarding
MagicDNS upstream to Tailscale IPs over netstack.
Updates #2102
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Windows 8.1 incorrectly handles search paths on an interface with no
associated resolver, so we have to provide a full primary DNS config
rather than use Windows 8.1's nascent-but-present NRPT functionality.
Fixes#2237.
Signed-off-by: David Anderson <danderson@tailscale.com>
This adds a flag to derp maps which specifies that default Tailscale DERP servers should not be
used. If true and there are entries in this map, it indicates that the entries in this map
should take precedent and not hit any of tailscale's DERP servers.
This change is backwards compatible, as the default behavior should be false.
Updates #1264
Signed-off-by: julianknodt <julianknodt@gmail.com>
In order to clone DERPMaps, it was necessary to extend the cloner so that it supports
nested pointers inside of maps which are also cloneable. This also adds cloning for DERPRegions
and DERPNodes because they are on DERPMap's maps.
Signed-off-by: julianknodt <julianknodt@gmail.com>
The only connectivity an AWS Lambda container has is an IPv4 link-local
169.254.x.x address using NAT:
12: vtarget_1@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
qdisc noqueue state UP group default qlen 1000
link/ether 7e:1c:3f:00:00:00 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet 169.254.79.1/32 scope global vtarget_1
valid_lft forever preferred_lft forever
If there are no other IPv4/v6 addresses available, and we are running
in AWS Lambda, allow IPv4 169.254.x.x addresses to be used.
----
Similarly, a Google Cloud Run container's only connectivity is
a Unique Local Address fddf:3978:feb1:d745::c001/128.
If there are no other addresses available then allow IPv6
Unique Local Addresses to be used.
We actually did this in an earlier release, but now refactor it to
work the same way as the IPv4 link-local support is being done.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Before it was using the local address and port, so fix that.
The fields in the response from `ss` are:
State, Recv-Q, Send-Q, Local Address:Port, Peer Address:Port, Process
Signed-off-by: julianknodt <julianknodt@gmail.com>
This adds a handler on the DERP server for logging bytes send and received by clients of the
server, by holding open a connection and recording if there is a difference between the number
of bytes sent and received. It sends a JSON marshalled object if there is an increase in the
number of bytes.
Signed-off-by: julianknodt <julianknodt@gmail.com>
Split out of Denton's #2164, to make that diff smaller to review.
This change has no behavior changes.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Previously we used t.Logf indirectly via package log. This worked, but
it was not ideal for our needs. It could cause the streams of output to
get crossed. This change uses a logger.FuncWriter every place log.Output
was previously used, which will more correctly write log information to
the right test output stream.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
It's possible to install a configuration that passes our current checks
for systemd-resolved, without actually pointing to systemd-resolved. In
that case, we end up programming DNS in resolved, but that config never
applies to any name resolution requests on the system.
This is quite a far-out edge case, but there's a simple additional check
we can do: if the header comment names systemd-resolved, there should be
a single nameserver in resolv.conf pointing to 127.0.0.53. If not, the
configuration should be treated as an unmanaged resolv.conf.
Fixes#2136.
Signed-off-by: David Anderson <danderson@tailscale.com>
The dependency is a "soft" ordering dependency only, meaning that
tailscaled will start after those services if those services were
going to be run anyway, but doesn't force either of them to run.
That's why it's safe to specify this dependency unconditionally,
even for systems that don't run those services.
Updates #2127.
Signed-off-by: David Anderson <danderson@tailscale.com>
AWS Lambda uses Docker containers but does not
have the string "docker" in its /proc/1/cgroup.
Infer AWS Lambda via the environment variables
it sets.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
It would be useful to know the time that packets spend inside of a queue before they are sent
off, as that can be indicative of the load the server is handling (and there was also an
existing TODO). This adds a simple exponential moving average metric to track the average packet
queue duration.
Changes during review:
Add CAS loop for recording queue timing w/ expvar.Func, rm snake_case, annotate in milliseconds,
convert
Signed-off-by: julianknodt <julianknodt@gmail.com>
Alpine Linux[1] is a minimal Linux distribution built around musl libc.
It boots very quickly, requires very little ram and is as close as you
can get to an ideal citizen for testing Tailscale on musl. Alpine has a
Tailscale package already[2], but this patch also makes it easier for us
to provide an Alpine Linux package off of pkgs in the future.
Alpine only offers Tailscale on the rolling-release edge branch.
[1]: https://alpinelinux.org/
[2]: https://pkgs.alpinelinux.org/packages?name=tailscale&branch=edge
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
This fails pretty reliably with a lot of output now showing what's
happening:
TS_DEBUG_MAP=1 go test --failfast -v -run=Ping -race -count=20 ./tstest/integration --verbose-tailscaled
I haven't dug into the details yet, though.
Updates #2079
The route creation for the `tun` device was augmented in #1469 but
didn't account for adding IPv4 vs. IPv6 routes. There are 2 primary
changes as a result:
* Ensure that either `-inet` or `-inet6` was used in the
[`route(8)`](https://man.openbsd.org/route) command
* Use either the `localAddr4` or `localAddr6` for the gateway argument
depending which destination network is being added
The basis for the approach is based on the implementation from
`router_userspace_bsd.go`, including the `inet()` helper function.
Fixes#2048
References #1469
Signed-off-by: Fletcher Nichol <fnichol@nichol.ca>
This raises the maximum DNS response message size from 512 to 4095. This
should be large enough for almost all situations that do not need TCP.
We still do not recognize EDNS, so we will still forward requests that
claim support for a larger response size than 4095 (that will be solved
later). For now, when a response comes back that is too large to fit in
our receive buffer, we now set the truncation flag in the DNS header,
which is an improvement from before but will prompt attempts to use TCP
which isn't supported yet.
On Windows, WSARecvFrom into a buffer that's too small returns an error
in addition to the data. On other OSes, the extra data is silently
discarded. In this case, we prefer the latter so need to catch the error
on Windows.
Partially addresses #1123
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
This runner is in my homelab while we muse about a better, more
permanent home for these tests.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
This makes integration tests pull pristine VM images from Amazon S3 if
they don't exist on disk. If the S3 fetch fails, it will fall back to
grabbing the image from the public internet. The VM images on the public
internet are known to be updated without warning and thusly change their
SHA256 checksum. This is not ideal for a test that we want to be able to
fire and forget, then run reliably for a very long time.
This requires an AWS profile to be configured at the default path. The
S3 bucket is rigged so that the requester pays. The VM images are
currently about 6.9 gigabytes. Please keep this in mind when running
these tests on your machine.
Documentation was added to the integration test folder to aid others in
running these tests on their machine.
Some wording in the logs of the tests was altered.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
Some downstream distros eval'd version/version.sh to get at the shell variables
within their own build process. They can now `./build_dist.sh shellvars` to get
those.
Fixes#2058.
Signed-off-by: David Anderson <dave@natulte.net>
It is a bit faster.
But more importantly, it matches upstream byte-for-byte,
which ensures there'll be no corner cases in which we disagree.
name old time/op new time/op delta
SetPeers-8 3.58µs ± 0% 3.16µs ± 2% -11.74% (p=0.016 n=4+5)
name old alloc/op new alloc/op delta
SetPeers-8 2.53kB ± 0% 2.53kB ± 0% ~ (all equal)
name old allocs/op new allocs/op delta
SetPeers-8 99.0 ± 0% 99.0 ± 0% ~ (all equal)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The image downloads can take a significant amount of time for the tests.
This creates a new test that will download every distro image into the
local cache in parallel, optionally matching the distribution regex.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
I've run into a couple issues where the tests time out while a VM image
is being downloaded, making the cache poisoned for the next run. This
moves the hash checking into its own function and calls it much sooner
in the testing chain. If the hash check fails, the OS is redownloaded.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
Most of the time qemu will output nothing when it is running. This is
expected behavior. However when qemu is unable to start due to some
problem, it prints that to either stdout or stderr. Previously this
output wasn't being captured. This patch captures that output to aid in
debugging qemu issues.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
We were crashing on in initPeerAPIListener when called from
authReconfig when b.netMap is nil. But authReconfig already returns
before the call to initPeerAPIListener when b.netMap is nil, but it
releases the b.mu mutex before calling initPeerAPIListener which
reacquires it and assumes it's still nil.
The only thing that can be setting it to nil is setNetMapLocked, which
is called by ResetForClientDisconnect, Logout/logout, or Start, all of
which can happen during an authReconfig.
So be more defensive.
Fixes#1996
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
We used to use "redo" for that, but it was pretty vague.
Also, fix the build tags broken in interfaces_default_route_test.go from
a9745a0b68, moving those Linux-specific
tests to interfaces_linux_test.go.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Previously this built the binaries for every distro. This is a bit
overkill given we are using static binaries. This patch makes us only
build once.
There was also a weird issue with how processes were being managed.
Previously we just killed qemu with Process.Kill(), however that was
leaving behind zombies. This has been mended to not only kill qemu but
also waitpid() the process so it doesn't become a zombie.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
The OpenSUSE 15.1 image we are using (and conseqentially the only one
that is really available easily given it is EOL) has cloud-init
hardcoded to use the OpenStack metadata thingy. Other OpenSUSE Leap
images function fine with the NoCloud backend, but this one seems to
just not work with it. No bother, we can just pretend to be OpenStack.
Thanks to Okami for giving me an example OpenStack configuration seed
image.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
Arch is a bit of a weirder distro, however as a side effect it is much
more of a systemd purist experience. Adding it to our test suite will
make sure that we are working in the systemd happy path.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
This distro is about to be released. OpenSUSE has historically had the
least coverage for functional testing, so this may prove useful in the
future.
Signed-off-by: Christine Dodrill <xe@tailscale.com>
DNS names consist of labels, but outside of length limits, DNS
itself permits any content within the labels. Some records require
labels to conform to hostname limitations (which is what we implemented
before), but not all.
Fixes#2024.
Signed-off-by: David Anderson <danderson@tailscale.com>
Instead of testing all the VMs at once when they are all ready, this
patch changes the testing logic so that the vms are tested as soon as
they register with testcontrol. Also limit the amount of VM ram used at
once with the `-ram-limit` flag. That uses a semaphore to guard resource
use.
Also document CentOS' sins.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
The resulting empty Prefs had AllowSingleHosts=false and
Routeall=false, so that on iOS if you did these steps:
- Login and leave running
- Terminate the frontend
- Restart the frontend (fast path restart, missing prefs)
- Set WantRunning=false
- Set WantRunning=true
...then you would have Tailscale running, but with no routes. You would
also accidentally disable the ExitNodeID/IP prefs (symptom: the current
exit node setting didn't appear in the UI), but since nothing
else worked either, you probably didn't notice.
The fix was easy enough. It turns out we already knew about the
problem, so this also fixes one of the BUG entries in state_test.
Fixes: #1918 (BUG-1) and some as-yet-unreported bugs with exit nodes.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Previously, there was no server round trip required to log out, so when
you asked ipnlocal to Logout(), it could clear the netmap immediately
and switch to NeedsLogin state.
In v1.8, we added a true Logout operation. ipn.Logout() would trigger
an async cc.StartLogout() and *also* immediately switch to NeedsLogin.
Unfortunately, some frontends would see NeedsLogin and immediately
trigger a new StartInteractiveLogin() operation, before the
controlclient auth state machine actually acted on the Logout command,
thus accidentally invalidating the entire logout operation, retaining
the netmap, and violating the user's expectations.
Instead, add a new LogoutFinished signal from controlclient
(paralleling LoginFinished) and, upon starting a logout, don't update
the ipn state machine until it's received.
Updates: #1918 (BUG-2)
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
If you set `-distro-regex` to match a subset of distros, only those
distros will be tested. Ex:
$ go test -run-vm-tests -distro-regex='opensuse'
Signed-off-by: Christine Dodrill <xe@tailscale.com>
Don't try to do heuristics on the name. Use the net/interfaces package
which we already have to do this sort of stuff.
Fixes#2011
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Instead of pulling packages from pkgs.tailscale.com, we should use the
tailscale binaries that are local to this git commit. This exposes a bit
of the integration testing stack in order to copy the binaries
correctly.
This commit also bumps our version of github.com/pkg/sftp to the latest
commit.
If you run into trouble with yaml, be sure to check out the
commented-out alpine linux image complete with instructions on how to
use it.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
netaddr allocated at the time this was written. No longer.
name old time/op new time/op delta
TailscaleServiceAddr-4 5.46ns ± 4% 1.83ns ± 3% -66.52% (p=0.008 n=5+5)
A bunch of the others can probably be simplified too, but this
was the only one with just an IP and not an IPPrefix.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Previously we spewed a lot of output to stdout and stderr, even when
`-v` wasn't set. This is sub-optimal for various reasons. This patch
shunts that output to test logs so it only shows up when `-v` is set.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
The cyolosecurity fork of certstore did not update its module name and
thus can only be used with a replace directive. This interferes with
installing using `go install` so I created a tailscale fork with an
updated module name.
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
Instead of relying on a libvirtd bridge address that you probably won't
have on your system.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
On clean installs we didn't set use iptables, but during upgrades it
looks like we could use old prefs that directed us to go into the iptables
paths that might fail on Synology.
Updates #1995Fixestailscale/tailscale-synology#57 (I think)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This will spin up a few vms and then try and make them connect to a
testcontrol server.
Updates #1988
Signed-off-by: Christine Dodrill <xe@tailscale.com>
When tailscaled starts up, these lines run:
func run() error {
// ...
pol := logpolicy.New("tailnode.log.tailscale.io")
pol.SetVerbosityLevel(args.verbose)
// ...
}
If there are old log entries present, they immediate start getting uploaded. This races with the call to pol.SetVerbosityLevel.
This manifested itself as a test failure in tailscale.com/tstest/integration
when run with -race:
WARNING: DATA RACE
Read at 0x00c0001bc970 by goroutine 24:
tailscale.com/logtail.(*Logger).Write()
/Users/josh/t/corp/oss/logtail/logtail.go:517 +0x27c
log.(*Logger).Output()
/Users/josh/go/ts/src/log/log.go:184 +0x2b8
log.Printf()
/Users/josh/go/ts/src/log/log.go:323 +0x94
tailscale.com/logpolicy.newLogtailTransport.func1()
/Users/josh/t/corp/oss/logpolicy/logpolicy.go:509 +0x36c
net/http.(*Transport).dial()
/Users/josh/go/ts/src/net/http/transport.go:1168 +0x238
net/http.(*Transport).dialConn()
/Users/josh/go/ts/src/net/http/transport.go:1606 +0x21d0
net/http.(*Transport).dialConnFor()
/Users/josh/go/ts/src/net/http/transport.go:1448 +0xe4
Previous write at 0x00c0001bc970 by main goroutine:
tailscale.com/logtail.(*Logger).SetVerbosityLevel()
/Users/josh/t/corp/oss/logtail/logtail.go:131 +0x98
tailscale.com/logpolicy.(*Policy).SetVerbosityLevel()
/Users/josh/t/corp/oss/logpolicy/logpolicy.go:463 +0x60
main.run()
/Users/josh/t/corp/oss/cmd/tailscaled/tailscaled.go:178 +0x50
main.main()
/Users/josh/t/corp/oss/cmd/tailscaled/tailscaled.go:163 +0x71c
Goroutine 24 (running) created at:
net/http.(*Transport).queueForDial()
/Users/josh/go/ts/src/net/http/transport.go:1417 +0x4d8
net/http.(*Transport).getConn()
/Users/josh/go/ts/src/net/http/transport.go:1371 +0x5b8
net/http.(*Transport).roundTrip()
/Users/josh/go/ts/src/net/http/transport.go:585 +0x7f4
net/http.(*Transport).RoundTrip()
/Users/josh/go/ts/src/net/http/roundtrip.go:17 +0x30
net/http.send()
/Users/josh/go/ts/src/net/http/client.go:251 +0x4f0
net/http.(*Client).send()
/Users/josh/go/ts/src/net/http/client.go:175 +0x148
net/http.(*Client).do()
/Users/josh/go/ts/src/net/http/client.go:717 +0x1d0
net/http.(*Client).Do()
/Users/josh/go/ts/src/net/http/client.go:585 +0x358
tailscale.com/logtail.(*Logger).upload()
/Users/josh/t/corp/oss/logtail/logtail.go:367 +0x334
tailscale.com/logtail.(*Logger).uploading()
/Users/josh/t/corp/oss/logtail/logtail.go:289 +0xec
Rather than complicate the logpolicy API,
allow the verbosity to be adjusted concurrently.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Pull in the latest version of wireguard-windows.
Switch to upstream wireguard-go.
This requires reverting all of our import paths.
Unfortunately, this has to happen at the same time.
The wireguard-go change is very low risk,
as that commit matches our fork almost exactly.
(The only changes are import paths, CI files, and a go.mod entry.)
So if there are issues as a result of this commit,
the first place to look is wireguard-windows changes.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
We repeat many peers each time we call SetPeers.
Instead of constructing strings for them from scratch every time,
keep strings alive across iterations.
name old time/op new time/op delta
SetPeers-8 3.58µs ± 1% 2.41µs ± 1% -32.60% (p=0.000 n=9+10)
name old alloc/op new alloc/op delta
SetPeers-8 2.53kB ± 0% 1.30kB ± 0% -48.73% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
SetPeers-8 99.0 ± 0% 16.0 ± 0% -83.84% (p=0.000 n=10+10)
We could reduce alloc/op 12% and allocs/op 23% if strs had
type map[string]strCache instead of map[string]*strCache,
but that wipes out the execution time impact.
Given that re-use is the most common scenario, let's optimize for it.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
e66d4e4c81 added AppendTo methods
to some key types. Their marshaled form is longer than 64 bytes.
name old time/op new time/op delta
Hash-8 15.5µs ± 1% 14.8µs ± 1% -4.17% (p=0.000 n=9+9)
name old alloc/op new alloc/op delta
Hash-8 1.18kB ± 0% 0.47kB ± 0% -59.87% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
Hash-8 12.0 ± 0% 6.0 ± 0% -50.00% (p=0.000 n=10+10)
This is still a bit worse than explicitly handling the types,
but much nicer.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
All netaddr types that we are concerned with now implement AppendTo.
Use the AppendTo method if available, and remove all references to netaddr.
This is slower but cleaner, and more readily re-usable by others.
name old time/op new time/op delta
Hash-8 12.6µs ± 0% 14.8µs ± 1% +18.05% (p=0.000 n=8+10)
HashMapAcyclic-8 21.4µs ± 1% 21.9µs ± 1% +2.39% (p=0.000 n=10+9)
name old alloc/op new alloc/op delta
Hash-8 408B ± 0% 408B ± 0% ~ (p=1.000 n=10+10)
HashMapAcyclic-8 1.00B ± 0% 1.00B ± 0% ~ (all equal)
name old allocs/op new allocs/op delta
Hash-8 6.00 ± 0% 6.00 ± 0% ~ (all equal)
HashMapAcyclic-8 0.00 0.00 ~ (all equal)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
These exist so we can use the optimized MapIter APIs
while still working with released versions of Go.
They're pretty simple, but some docs won't hurt.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Reduce to just a single external endpoint.
Convert from a variadic number of interfaces to a slice there.
name old time/op new time/op delta
Hash-8 14.4µs ± 0% 14.0µs ± 1% -3.08% (p=0.000 n=9+9)
name old alloc/op new alloc/op delta
Hash-8 873B ± 0% 793B ± 0% -9.16% (p=0.000 n=9+6)
name old allocs/op new allocs/op delta
Hash-8 18.0 ± 0% 14.0 ± 0% -22.22% (p=0.000 n=10+10)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Slightly slower, but lots less garbage.
We will recover the speed lost in a follow-up commit.
name old time/op new time/op delta
Hash-8 13.5µs ± 1% 14.3µs ± 0% +5.84% (p=0.000 n=10+9)
name old alloc/op new alloc/op delta
Hash-8 1.46kB ± 0% 0.87kB ± 0% -40.10% (p=0.000 n=7+10)
name old allocs/op new allocs/op delta
Hash-8 43.0 ± 0% 18.0 ± 0% -58.14% (p=0.000 n=10+10)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This requires changes to the Go toolchain.
The changes are upstream at https://golang.org/cl/320929.
They haven't been pulled into our fork yet.
No need to allocate new iteration scratch values for every map.
name old time/op new time/op delta
Hash-8 13.6µs ± 0% 13.5µs ± 0% -1.01% (p=0.008 n=5+5)
HashMapAcyclic-8 21.2µs ± 1% 21.1µs ± 2% ~ (p=0.310 n=5+5)
name old alloc/op new alloc/op delta
Hash-8 1.58kB ± 0% 1.46kB ± 0% -7.60% (p=0.008 n=5+5)
HashMapAcyclic-8 152B ± 0% 128B ± 0% -15.79% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
Hash-8 49.0 ± 0% 43.0 ± 0% -12.24% (p=0.008 n=5+5)
HashMapAcyclic-8 4.00 ± 0% 2.00 ± 0% -50.00% (p=0.008 n=5+5)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
To get the benefit of this optimization requires help from the Go toolchain.
The changes are upstream at https://golang.org/cl/320929,
and have been pulled into the Tailscale fork at
728ecc58fd.
It also requires building with the build tag tailscale_go.
name old time/op new time/op delta
Hash-8 14.0µs ± 0% 13.6µs ± 0% -2.88% (p=0.008 n=5+5)
HashMapAcyclic-8 24.3µs ± 1% 21.2µs ± 1% -12.47% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Hash-8 2.16kB ± 0% 1.58kB ± 0% -27.01% (p=0.008 n=5+5)
HashMapAcyclic-8 2.53kB ± 0% 0.15kB ± 0% -93.99% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
Hash-8 77.0 ± 0% 49.0 ± 0% -36.36% (p=0.008 n=5+5)
HashMapAcyclic-8 202 ± 0% 4 ± 0% -98.02% (p=0.008 n=5+5)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
setkey
The acyclic map code interacts badly with netaddr.IPs.
One of the netaddr.IP fields is an *intern.Value,
and we use a few sentinel values.
Those sentinel values make many of the netaddr data structures appear cyclic.
One option would be to replace the cycle-detection code with
a Floyd-Warshall style algorithm. The downside is that this will take
longer to detect cycles, particularly if the cycle is long.
This problem is exacerbated by the fact that the acyclic cycle detection
code shares a single visited map for the entire data structure,
not just the subsection of the data structure localized to the map.
Unfortunately, the extra allocations and work (and code) to use per-map
visited maps make this option not viable.
Instead, continue to special-case netaddr data types.
name old time/op new time/op delta
Hash-8 22.4µs ± 0% 14.0µs ± 0% -37.59% (p=0.008 n=5+5)
HashMapAcyclic-8 23.8µs ± 0% 24.3µs ± 1% +1.75% (p=0.008 n=5+5)
name old alloc/op new alloc/op delta
Hash-8 2.49kB ± 0% 2.16kB ± 0% ~ (p=0.079 n=4+5)
HashMapAcyclic-8 2.53kB ± 0% 2.53kB ± 0% ~ (all equal)
name old allocs/op new allocs/op delta
Hash-8 86.0 ± 0% 77.0 ± 0% -10.47% (p=0.008 n=5+5)
HashMapAcyclic-8 202 ± 0% 202 ± 0% ~ (all equal)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Hash and xor each entry instead, then write final xor'ed result.
name old time/op new time/op delta
Hash-4 33.6µs ± 4% 34.6µs ± 3% +3.03% (p=0.013 n=10+9)
name old alloc/op new alloc/op delta
Hash-4 1.86kB ± 0% 1.77kB ± 0% -5.10% (p=0.000 n=10+9)
name old allocs/op new allocs/op delta
Hash-4 51.0 ± 0% 49.0 ± 0% -3.92% (p=0.000 n=10+10)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
At the start of a dev cycle we'll upgrade all dependencies.
Done with:
$ for Dep in $(cat go.mod | perl -ne '/(\S+) v/ and print "$1\n"'); do go get $Dep@upgrade; done
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Our wireguard-go fork used different values from upstream for
package device's memory limits on iOS.
This was the last blocker to removing our fork.
These values are now vars rather than consts for iOS.
c27ff9b9f6
Adjust them on startup to our preferred values.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Typical maps in production are considerably longer.
This helps benchmarks more accurately reflect the costs per key
vs the costs per map in deephash.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
A couple of code paths in ipnserver use a NewBackendServer with a nil
backend just to call the callback with an encapsulated error message.
This covers a panic case seen in logs.
For #1920
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
This leads to a cleaner separation of intent vs. implementation
(Routes is now the only place specifying who handles DNS requests),
and allows for cleaner expression of a configuration that creates
MagicDNS records without serving them to the OS.
Signed-off-by: David Anderson <danderson@tailscale.com>
* Added new Addresses / AllowedIPs fields to testcontrol when creating new &tailcfg.Node
Signed-off-by: Simeng He <simeng@tailscale.com>
* Added single node test to check Addresses and AllowedIPs
Signed-off-by: Simeng He <simeng@tailscale.com>
Co-authored-by: Simeng He <simeng@tailscale.com>
The script detects one of the supported OS/version combos, and issues
the right install instructions for it.
Co-authored-by: Christine Dodrill <xe@tailscale.com>
Signed-off-by: David Anderson <danderson@tailscale.com>
If --until-direct is set, the goal is to make a direct connection.
If we failed at that, say so, and exit with an error.
RELNOTE=tailscale ping --until-direct (the default) now exits with
a non-zero exit code if no direct connection was established.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This code path is very tricky since it was originally designed for the
"re-authenticate to refresh my keys" use case, which didn't want to
lose the original session even if the refresh cycle failed. This is why
it acts differently from the Logout(); Login(); case.
Maybe that's too fancy, considering that it probably never quite worked
at all, for switching between users without logging out first. But it
works now.
This was more invasive than I hoped, but the necessary fixes actually
removed several other suspicious BUG: lines from state_test.go, so I'm
pretty confident this is a significant net improvement.
Fixestailscale/corp#1756.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
If the engine was shutting down from a previous session
(e.closing=true), it would return an error code when trying to get
status. In that case, ipnlocal would never unblock any callers that
were waiting on the status.
Not sure if this ever happened in real life, but I accidentally
triggered it while writing a test.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
magicsock.Conn.ParseEndpoint requires a peer's public key,
disco key, and legacy ip/ports in order to do its job.
We currently accomplish that by:
* adding the public key in our wireguard-go fork
* encoding the disco key as magic hostname
* using a bespoke comma-separated encoding
It's a bit messy.
Instead, switch to something simpler: use a json-encoded struct
containing exactly the information we need, in the form we use it.
Our wireguard-go fork still adds the public key to the
address when it passes it to ParseEndpoint, but now the code
compensating for that is just a couple of simple, well-commented lines.
Once this commit is in, we can remove that part of the fork
and remove the compensating code.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
The new code is ugly, but much faster and leaner.
name old time/op new time/op delta
SetPeers-8 7.81µs ± 1% 3.59µs ± 1% -54.04% (p=0.000 n=9+10)
name old alloc/op new alloc/op delta
SetPeers-8 7.68kB ± 0% 2.53kB ± 0% -67.08% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
SetPeers-8 237 ± 0% 99 ± 0% -58.23% (p=0.000 n=10+10)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Because it showed up on hello profiles.
Cycle through some moderate-sized sets of peers.
This should cover the "small tweaks to netmap"
and the "up/down cycle" cases.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Yes, it printed, but that was an implementation detail for hashing.
And coming optimization will make it print even less.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Not that it matters, but we were missing a close parens.
It's cheap, so add it.
name old time/op new time/op delta
Hash-8 6.64µs ± 0% 6.67µs ± 1% +0.42% (p=0.008 n=9+10)
name old alloc/op new alloc/op delta
Hash-8 1.54kB ± 0% 1.54kB ± 0% ~ (all equal)
name old allocs/op new allocs/op delta
Hash-8 37.0 ± 0% 37.0 ± 0% ~ (all equal)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The struct field names don't change within a single run,
so they are irrelevant. Use the field index instead.
name old time/op new time/op delta
Hash-8 6.52µs ± 0% 6.64µs ± 0% +1.91% (p=0.000 n=6+9)
name old alloc/op new alloc/op delta
Hash-8 1.67kB ± 0% 1.54kB ± 0% -7.66% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
Hash-8 53.0 ± 0% 37.0 ± 0% -30.19% (p=0.000 n=10+10)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
These show up a lot in our data structures.
name old time/op new time/op delta
Hash-8 11.5µs ± 1% 7.8µs ± 1% -32.17% (p=0.000 n=10+10)
name old alloc/op new alloc/op delta
Hash-8 1.98kB ± 0% 1.67kB ± 0% -15.73% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
Hash-8 82.0 ± 0% 53.0 ± 0% -35.37% (p=0.000 n=10+10)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The sha256 hash writer doesn't implement WriteString.
(See https://github.com/golang/go/issues/38776.)
As a consequence, we end up converting many strings to []byte.
Wrapping a bufio.Writer around the hash writer lets us
avoid these conversions by using WriteString.
Using a bufio.Writer is, perhaps surprisingly, almost as cheap as using unsafe.
The reason is that the sha256 writer does internal buffering,
but doesn't do any when handed larger writers.
Using a bufio.Writer merely shifts the data copying from one buffer
to a different one.
Using a concrete type for Print and print cuts 10% off of the execution time.
name old time/op new time/op delta
Hash-8 15.3µs ± 0% 11.5µs ± 0% -24.84% (p=0.000 n=10+10)
name old alloc/op new alloc/op delta
Hash-8 2.82kB ± 0% 1.98kB ± 0% -29.57% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
Hash-8 140 ± 0% 82 ± 0% -41.43% (p=0.000 n=10+10)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
deepprint currently accounts for 15% of allocs in tailscaled.
This is a useful benchmark to have.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
On benchmark completion, we shut down the wgengine.
If we happen to poll for status during shutdown,
we get an "engine closing" error.
It doesn't hurt anything; ignore it.
Fixestailscale/corp#1776
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
interfaces.Tailscale only returns an interface if it has at least one Tailscale
IP assigned to it. In the resolved DNS manager, when we're called upon to tear
down DNS config, the interface no longer has IPs.
Instead, look up the interface index on construction and reuse it throughout
the daemon lifecycle.
Fixes#1892.
Signed-off-by: David Anderson <dave@natulte.net>
If nobody is connected to the IPN bus, don't burn CPU & waste
allocations (causing more GC) by encoding netmaps for nobody.
This will notably help hello.ipn.dev.
Updates tailscale/corp#1773
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Without any synchronization here, the "first packet" callback can
be delayed indefinitely, while other work continues.
Since the callback starts the benchmark timer, this could skew results.
Worse, if the benchmark manages to complete before the benchmark timer begins,
it'll cause a data race with the benchmark shutdown performed by package testing.
That is what is reported in #1881.
This is a bit unfortunate, in that it means that users of TrafficGen have
to be careful to keep this callback speedy and lightweight and to avoid deadlocks.
Fixes#1881
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
It is possible to get multiple status callbacks from an Engine.
We need to wait for at least one from each Engine.
Without limiting to one per Engine,
wait.Wait can exit early or can panic due to a negative counter.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This reduces the speed with which these benchmarks exhaust their supply fds.
Not to zero unfortunately, but it's still helpful when doing long runs.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This function accounted for ~1% of all allocs by tailscaled.
It is trivial to improve, so may as well.
name old time/op new time/op delta
KeyMarshalText-8 197ns ± 0% 47ns ± 0% -76.12% (p=0.016 n=4+5)
name old alloc/op new alloc/op delta
KeyMarshalText-8 200B ± 0% 80B ± 0% -60.00% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
KeyMarshalText-8 5.00 ± 0% 1.00 ± 0% -80.00% (p=0.008 n=5+5)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The old way was way too fragile and had felt like it had more special
cases than normal cases. (see #1874, #1860, #1834, etc) It became very
obvious the old algorithm didn't work when we made the output be
pretty and try to show the user the command they need to run in
5ecc7c7200 for #1746)
The new algorithm is to map the prefs (current and new) back to flags
and then compare flags. This nicely handles the OS-specific flags and
the n:1 and 1:n flag:pref cases.
No change in the existing already-massive test suite, except some ordering
differences (the missing items are now sorted), but some new tests are
added for behavior that was broken before. In particular, it now:
* preserves non-pref boolean flags set to false, and preserves exit
node IPs (mapping them back from the ExitNodeID pref, as well as
ExitNodeIP),
* doesn't ignore --advertise-exit-node when doing an EditPrefs call
(#1880)
* doesn't lose the --operator on the non-EditPrefs paths (e.g. with
--force-reauth, or when the backend was not in state Running).
Fixes#1880
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Needed for the "up checker" to map back from exit node stable IDs (the
ipn.Prefs.ExitNodeID) back to an IP address in error messages.
But also previously requested so people can use it to then make API
calls. The upcoming "tailscale admin" subcommand will probably need it
too.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This reverts commit 7d16c8228b.
I have no idea how I ended up here. The bug I was fixing with this change
fails to reproduce on Ubuntu 18.04 now, and this change definitely does
break 20.04, 20.10, and Debian Buster. So, until we can reliably reproduce
the problem this was meant to fix, reverting.
Part of #1875
Signed-off-by: David Anderson <dave@natulte.net>
The --advertise-routes and --advertise-exit-node flags both mutating
one pref is the gift that keeps on giving.
I need to rewrite the this up warning code to first map prefs back to
flag values and then just compare flags instead of comparing prefs,
but this is the minimal fix for now.
This also includes work on the tests, to make them easier to write
(and more accurate), by letting you write the flag args directly and
have that parse into the upArgs/MaskedPrefs directly, the same as the
code, rather than them being possibly out of sync being written by
hand.
Fixes https://twitter.com/EXPbits/status/1390418145047887877
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Fields rename only.
Part of the general effort to make our code agnostic about endpoint formatting.
It's just a name, but it will soon be a misleading one; be more generic.
Do this as a separate commit because it generates a lot of whitespace changes.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Upstream wireguard-go renamed the interface method
from CreateEndpoint to ParseEndpoint.
I missed some comments. Fix them.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
By using conn.NewDefaultBind, this test requires that our endpoints
be comprehensible to wireguard-go. Instead, use a no-op bind that
treats endpoints as opaque strings.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Instead of calling ParseHex, do the hex.Decode directly.
name old time/op new time/op delta
UnmarshalJSON-8 86.9ns ± 0% 42.6ns ± 0% -50.94% (p=0.000 n=15+14)
name old alloc/op new alloc/op delta
UnmarshalJSON-8 128B ± 0% 0B -100.00% (p=0.000 n=15+15)
name old allocs/op new allocs/op delta
UnmarshalJSON-8 2.00 ± 0% 0.00 -100.00% (p=0.000 n=15+15)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Legacy endpoints (addrSet) currently reconstruct their dst string when requested.
Instead, store the dst string we were given to begin with.
In addition to being simpler and cheaper, this makes less code
aware of how to interpret endpoint strings.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Prefer the error from the actual wireguard-go device method call,
not {To,From}UAPI, as those tend to be less interesting I/O errors.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
When wireguard-go's UAPI interface fails with an error, ReconfigDevice hangs.
Fix that by buffering the channel and closing the writer after the call.
The code now matches the corresponding code in DeviceConfig, where I got it right.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
It is unused, and has been since early Feb 2021 (Tailscale 1.6).
We can't get delete the DeviceOptions entirely yet;
first #1831 and #1839 need to go in, along with some wireguard-go changes.
Deleting this chunk of code now will make the later commits more clearly correct.
Pingers can now go too.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The earlier eb06ec172f fixed
the flaky SSH issue (tailscale/corp#1725) by making sure that packets
addressed to Tailscale IPs in hybrid netstack mode weren't delivered
to netstack, but another issue remained:
All traffic handled by netstack was also potentially being handled by
the host networking stack, as the filter hook returned "Accept", which
made it keep processing. This could lead to various random racey chaos
as a function of OS/firewalls/routes/etc.
Instead, once we inject into netstack, stop our caller's packet
processing.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Whenever we dropped a packet due to ACLs, wireguard-go was logging:
Failed to write packet to TUN device: packet dropped by filter
Instead, just lie to wireguard-go and pretend everything is okay.
Fixes#1229
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Upstream wireguard-go renamed the interface method
from CreateEndpoint to ParseEndpoint.
I updated the log call site but not the allowlist.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
#1817 removed the only place in our CI where we executed our benchmark code.
Fix that by executing it everywhere.
The benchmarks are generally cheap and fast,
so this should add minimal overhead.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
To prevent issues like #1786, run staticcheck on the primary GOOSes:
linux, mac, and windows.
Windows also has a fair amount of GOARCH-specific code.
If we ever have GOARCH staticcheck failures on other GOOSes,
we can expand the test matrix further.
This requires installing the staticcheck binary so that
we can execute it with different GOOSes.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
This is needed because the original opts.Prefs field was at some point
subverted for use in frontend->backend state migration for backward
compatibility on some platforms. We still need that feature, but we
also need the feature of providing the full set of prefs from
`tailscale up`, *not* including overwriting the prefs.Persist keys, so
we can't use the original field from `tailscale up`.
`tailscale up` had attempted to compensate for that by doing SetPrefs()
before Start(), but that violates the ipn.Backend contract, which says
you should call Start() before anything else (that's why it's called
Start()). As a result, doing SetPrefs({ControlURL=...,
WantRunning=true}) would cause a connection to the *previous* control
server (because WantRunning=true), and then connect to the *new*
control server only after running Start().
This problem may have been avoided before, but only by pure luck.
It turned out to be relatively harmless since the connection to the old
control server was immediately closed and replaced anyway, but it
created a race condition that could have caused spurious notifications
or rejected keys if the server responded quickly.
As already covered by existing TODOs, a better fix would be to have
Start() get out of the business of state migration altogether. But
we're approaching a release so I want to make the minimum possible fix.
Fixes#1840.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
We were over-eager in running tailscale in GUI mode.
f42ded7acf fixed that by
checking for a variety of shell-ish env vars and using those
to force us into CLI mode.
However, for reasons I don't understand, those shell env vars
are present when Xcode runs Tailscale.app on my machine.
(I've changed no configs, modified nothing on a brand new machine.)
Work around that by adding an additional "only in GUI mode" check.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
I was going to write a test for this using the tstest/integration test
stuff, but the testcontrol implementation isn't quite there yet (it
always registers nodes and doesn't provide AuthURLs). So, manually
tested for now.
Fixes#1843
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Per discussion, we want to have only one test assertion library,
and we want to start by exploring quicktest.
This was a mostly mechanical translation.
I think we could make this nicer by defining a few helper
closures at the beginning of the test. Later.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
This fixes#1833 in two ways:
* stop setting NoSNAT on non-Linux. It only matters on Linux and the flag
is hidden on non-Linux, but the code was still setting it. Because of
that, the new pref-reverting safety checks were failing when it was
changing.
* Ignore the two Linux-only prefs changing on non-Linux.
Fixes#1833
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
There's no need to warn that it was not provided on the command line
after doing a sequence of up; logout; up --args. If you're asking for
tailscale to be up, you always mean that you prefer LoggedOut to become
false.
Fixes#1828
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Prior to wireguard-go using printf-style logging,
all wireguard-go logging occurred using format string "%s".
We fixed that but continued to use %s when we rewrote
peer identifiers into Tailscale style.
This commit removes that %sl, which makes rate limiting work correctly.
As a happy side-benefit, it should generate less garbage.
Instead of replacing all wireguard-go peer identifiers
that might occur anywhere in a fully formatted log string,
assume that they only come from args.
Check all args for things that look like *device.Peers
and replace them with appropriately reformatted strings.
There is a variety of ways that this could go wrong
(unusual format verbs or modifiers, peer identifiers
occurring as part of a larger printed object, future API changes),
but none of them occur now, are likely to be added,
or would be hard to work around if they did.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
The "stop phrases" we use all occur in wireguard-go in the format string.
We can avoid doing a bunch of fmt.Sprintf work when they appear.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
This removes the NewLocalBackendWithClientGen constructor added in
b4d04a065f and instead adds
LocalBackend.SetControlClientGetterForTesting, mirroring
LocalBackend.SetHTTPTestClient. NewLocalBackendWithClientGen was
weird in being exported but taking an unexported type. This was noted
during code review:
https://github.com/tailscale/tailscale/pull/1818#discussion_r623155669
which ended in:
"I'll leave it for y'all to clean up if you find some way to do it elegantly."
This is more idiomatic.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Without this, macOS would fail to display its menu state correctly if you
started it while !WantRunning. It relies on the netmap in order to show
the logged-in username.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
There was logic that would make a "down" tailscale backend (ie.
!WantRunning) refuse to do any network activity. Unfortunately, this
makes the macOS and iOS UI unable to render correctly if they start
while !WantRunning.
Now that we have Prefs.LoggedOut, use that instead. So `tailscale down`
will still allow the controlclient to connect its authroutine, but
pause the maproutine. `tailscale logout` will entirely stop all
activity.
This new behaviour is not obviously correct; it's a bit annoying that
`tailsale down` doesn't terminate all activity like you might expect.
Maybe we should redesign the UI code to render differently when
disconnected, and then revert this change.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
EditPrefs should be just a wrapper around the action of changing prefs,
but someone had added a side effect of calling Login() sometimes. The
side effect happened *after* running the state machine, which would
sometimes result in us going into NeedsLogin immediately before calling
cc.Login().
This manifested as the macOS app not being able to Connect if you
launched it with LoggedOut=false and WantRunning=false. Trying to
Connect() would sent us to the NeedsLogin state instead.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
- Switch to our own simpler token bucket, since x/time/rate is missing
necessary stuff (can't provide your own time func; can't check the
current bucket contents) and it's overkill anyway.
- Add tests that actually include advancing time.
- Don't remove the rate limit on a message until there's enough room to
print at least two more of them. When we do, we'll also print how
many we dropped, as a contextual reminder that some were previously
lost. (This is more like how the Linux kernel does it.)
- Reformat the [RATE LIMITED] messages to be shorter, and to not
corrupt original message. Instead, we print the message, then print
its format string.
- Use %q instead of \"%s\", for more accurate parsing later, if the
format string contained quotes.
Fixes#1772
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
A very long unit test that verifies the way the controlclient and
ipn.Backend interact.
This is a giant sequential test of the state machine. The test passes,
but only because it's asserting all the wrong behaviour. I marked all
the behaviour I think is wrong with BUG comments, and several
additional test opportunities with TODO.
Note: the new test supercedes TestStartsInNeedsLoginState, which was
checking for incorrect behaviour (although the new test still checks
for the same incorrect behaviour) and assumed .Start() would converge
before returning, which it happens to do, but only for this very
specific case, for the current implementation. You're supposed to wait
for the notifications.
Updates: tailscale/corp#1660
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
With this change, shared node names resolve correctly on split DNS-supporting
operating systems.
Fixestailscale/corp#1706
Signed-off-by: David Anderson <danderson@tailscale.com>
Only minimal tailscale + tailscaled for now.
And a super minimal in-memory logcatcher.
No control ... yet.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Pointer receivers used with MarshalJSON are code rakes.
https://github.com/golang/go/issues/22967https://github.com/dominikh/go-tools/issues/911
I just stepped on one, and it hurt. Turn it over.
While we're here, optimize the code a bit.
name old time/op new time/op delta
MarshalJSON-8 184ns ± 0% 44ns ± 0% -76.03% (p=0.000 n=20+19)
name old alloc/op new alloc/op delta
MarshalJSON-8 184B ± 0% 80B ± 0% -56.52% (p=0.000 n=20+20)
name old allocs/op new allocs/op delta
MarshalJSON-8 4.00 ± 0% 1.00 ± 0% -75.00% (p=0.000 n=20+20)
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
For historical reasons, we ended up with two near-duplicate
copies of curve25519 key types, one in the wireguard-go module
(wgcfg) and one in the tailscale module (types/wgkey).
Then we moved wgcfg to the tailscale module.
We can now remove the wgcfg key type in favor of wgkey.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
One of the consequences of the bind refactoring in 6f23087175
is that attempting to bind an IPv6 socket will always
result in c.pconn6.pconn being non-nil.
If the bind fails, it'll be set to a placeholder packet conn
that blocks forever.
As a result, we can always run ReceiveIPv6 and health check it.
This removes IPv4/IPv6 asymmetry and also will allow health checks
to detect any IPv6 receive func failures.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
It must be an IP address; enforce that at the type level.
Suggested-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
We had two separate code paths for the initial UDP listener bind
and any subsequent rebinds.
IPv6 got left out of the rebind code.
Rather than duplicate it there, unify the two code paths.
Then improve the resulting code:
* Rebind had nested listen attempts to try the user-specified port first,
and then fall back to :0 if that failed. Convert that into a loop.
* Initial bind tried only the user-specified port.
Rebind tried the user-specified port and 0.
But there are actually three ports of interest:
The one the user specified, the most recent port in use, and 0.
We now try all three in order, as appropriate.
* In the extremely rare case in which binding to port 0 fails,
use a dummy net.PacketConn whose reads block until close.
This will keep the wireguard-go receive func goroutine alive.
As a pleasant side-effect of this, if we decide that
we need to resuscitate #1796, it will now be much easier.
Fixes#1799
Co-authored-by: David Anderson <danderson@tailscale.com>
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
Assume it'll stay at 0 forever, so hard-code it
and delete code conditional on it being non-0.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
It was set to context.Background by all callers, for the same reasons.
Set it locally instead, to simplify call sites.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
For when we need to tweak behavior or errors as a function of which of
3 macOS Tailscale variants we're using. (more accessors coming later
as needed)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The old implementation knew too much about how wireguard-go worked.
As a result, it missed genuine problems that occurred due to unrelated bugs.
This fourth attempt to fix the health checks takes a black box approach.
A receive func is healthy if one (or both) of these conditions holds:
* It is currently running and blocked.
* It has been executed recently.
The second condition is required because receive functions
are not continuously executing. wireguard-go calls them and then
processes their results before calling them again.
There is a theoretical false positive if wireguard-go go takes
longer than one minute to process the results of a receive func execution.
If that happens, we have other problems.
Updates #1790
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
They were not doing their job.
They need yet another conceptual re-think.
Start by clearing the decks.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
We had a long-standing bug in which our TUN events channel
was being received from simultaneously in two places.
The first is wireguard-go.
At wgengine/userspace.go:366, we pass e.tundev to wireguard-go,
which starts a goroutine (RoutineTUNEventReader)
that receives from that channel and uses events to adjust the MTU
and bring the device up/down.
At wgengine/userspace.go:374, we launch a goroutine that
receives from e.tundev, logs MTU changes, and triggers
state updates when up/down changes occur.
Events were getting delivered haphazardly between the two of them.
We don't really want wireguard-go to receive the up/down events;
we control the state of the device explicitly by calling device.Up.
And the userspace.go loop MTU logging duplicates logging that
wireguard-go does when it received MTU updates.
So this change splits the single TUN events channel into up/down
and other (aka MTU), and sends them to the parties that ought
to receive them.
I'm actually a bit surprised that this hasn't caused more visible trouble.
If a down event went to wireguard-go but the subsequent up event
went to userspace.go, we could end up with the wireguard-go device disappearing.
I believe that this may also (somewhat accidentally) be a fix for #1790.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
The intention was always that files only get written to *.partial
files and renamed at the end once fully received, but somewhere in the
process that got lost in buffered mode and *.partial files were only
being used in direct receive mode. This fix prevents WaitingFiles
from returning files that are still being transferred.
Updates tailscale/corp#1626
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
If DeleteFile fails on Windows due to another process (anti-virus,
probably) having our file open, instead leave a marker file that the
file is logically deleted, and remove it from API calls and clean it
up lazily later.
Updates tailscale/corp#1626
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The old decay-based one took a while to converge. This new one (based
very loosely on TCP BBR) seems to converge quickly on what seems to be
the best speed.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This tries to generate traffic at a rate that will saturate the
receiver, without overdoing it, even in the event of packet loss. It's
unrealistically more aggressive than TCP (which will back off quickly
in case of packet loss) but less silly than a blind test that just
generates packets as fast as it can (which can cause all the CPU to be
absorbed by the transmitter, giving an incorrect impression of how much
capacity the total system has).
Initial indications are that a syscall about every 10 packets (TCP bulk
delivery) is roughly the same speed as sending every packet through a
channel. A syscall per packet is about 5x-10x slower than that.
The whole tailscale wireguard-go + magicsock + packet filter
combination is about 4x slower again, which is better than I thought
we'd do, but probably has room for improvement.
Note that in "full" tailscale, there is also a tundev read/write for
every packet, effectively doubling the syscall overhead per packet.
Given these numbers, it seems like read/write syscalls are only 25-40%
of the total CPU time used in tailscale proper, so we do have
significant non-syscall optimization work to do too.
Sample output:
$ GOMAXPROCS=2 go test -bench . -benchtime 5s ./cmd/tailbench
goos: linux
goarch: amd64
pkg: tailscale.com/cmd/tailbench
cpu: Intel(R) Core(TM) i7-4785T CPU @ 2.20GHz
BenchmarkTrivialNoAlloc/32-2 56340248 93.85 ns/op 340.98 MB/s 0 %lost 0 B/op 0 allocs/op
BenchmarkTrivialNoAlloc/124-2 57527490 99.27 ns/op 1249.10 MB/s 0 %lost 0 B/op 0 allocs/op
BenchmarkTrivialNoAlloc/1024-2 52537773 111.3 ns/op 9200.39 MB/s 0 %lost 0 B/op 0 allocs/op
BenchmarkTrivial/32-2 41878063 135.6 ns/op 236.04 MB/s 0 %lost 0 B/op 0 allocs/op
BenchmarkTrivial/124-2 41270439 138.4 ns/op 896.02 MB/s 0 %lost 0 B/op 0 allocs/op
BenchmarkTrivial/1024-2 36337252 154.3 ns/op 6635.30 MB/s 0 %lost 0 B/op 0 allocs/op
BenchmarkBlockingChannel/32-2 12171654 494.3 ns/op 64.74 MB/s 0 %lost 1791 B/op 0 allocs/op
BenchmarkBlockingChannel/124-2 12149956 507.8 ns/op 244.17 MB/s 0 %lost 1792 B/op 1 allocs/op
BenchmarkBlockingChannel/1024-2 11034754 528.8 ns/op 1936.42 MB/s 0 %lost 1792 B/op 1 allocs/op
BenchmarkNonlockingChannel/32-2 8960622 2195 ns/op 14.58 MB/s 8.825 %lost 1792 B/op 1 allocs/op
BenchmarkNonlockingChannel/124-2 3014614 2224 ns/op 55.75 MB/s 11.18 %lost 1792 B/op 1 allocs/op
BenchmarkNonlockingChannel/1024-2 3234915 1688 ns/op 606.53 MB/s 3.765 %lost 1792 B/op 1 allocs/op
BenchmarkDoubleChannel/32-2 8457559 764.1 ns/op 41.88 MB/s 5.945 %lost 1792 B/op 1 allocs/op
BenchmarkDoubleChannel/124-2 5497726 1030 ns/op 120.38 MB/s 12.14 %lost 1792 B/op 1 allocs/op
BenchmarkDoubleChannel/1024-2 7985656 1360 ns/op 752.86 MB/s 13.57 %lost 1792 B/op 1 allocs/op
BenchmarkUDP/32-2 1652134 3695 ns/op 8.66 MB/s 0 %lost 176 B/op 3 allocs/op
BenchmarkUDP/124-2 1621024 3765 ns/op 32.94 MB/s 0 %lost 176 B/op 3 allocs/op
BenchmarkUDP/1024-2 1553750 3825 ns/op 267.72 MB/s 0 %lost 176 B/op 3 allocs/op
BenchmarkTCP/32-2 11056336 503.2 ns/op 63.60 MB/s 0 %lost 0 B/op 0 allocs/op
BenchmarkTCP/124-2 11074869 533.7 ns/op 232.32 MB/s 0 %lost 0 B/op 0 allocs/op
BenchmarkTCP/1024-2 8934968 671.4 ns/op 1525.20 MB/s 0 %lost 0 B/op 0 allocs/op
BenchmarkWireGuardTest/32-2 1403702 4547 ns/op 7.04 MB/s 14.37 %lost 467 B/op 3 allocs/op
BenchmarkWireGuardTest/124-2 780645 7927 ns/op 15.64 MB/s 1.537 %lost 420 B/op 3 allocs/op
BenchmarkWireGuardTest/1024-2 512671 11791 ns/op 86.85 MB/s 0.5206 %lost 411 B/op 3 allocs/op
PASS
ok tailscale.com/wgengine/bench 195.724s
Updates #414.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
NetworkManager fixed the bug that forced us to use NetworkManager
if it's programming systemd-resolved, and in the same release also
made NetworkManager ignore DNS settings provided for unmanaged
interfaces... Which breaks what we used to do. So, with versions
1.26.6 and above, we MUST NOT use NetworkManager to indirectly
program systemd-resolved, but thankfully we can talk to resolved
directly and get the right outcome.
Fixes#1788
Signed-off-by: David Anderson <danderson@tailscale.com>
The existing implementation was completely, embarrassingly conceptually broken.
We aren't able to see whether wireguard-go's receive function goroutines
are running or not. All we can do is model that based on what we have done.
This commit fixes that model.
Fixes#1781
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
Avery reported a sub-ms health transition from "receiveIPv4 not running" to "ok".
To avoid these transient false-positives, be more precise about
the expected lifetime of receive funcs. The problematic case is one in which
they were started but exited prior to a call to connBind.Close.
Explicitly represent started vs running state, taking care with the order of updates.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
The connection failure diagnostic code was never updated enough for
exit nodes, so disable its misleading output when the node it picks
(incorrectly) to diagnose is only an exit node.
Fixes#1754
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The new "tailscale up" checks previously didn't protect against
--advertise-exit-node being omitted in the case that
--advertise-routes was also provided. It wasn't done before because
there is no corresponding pref for "--advertise-exit-node"; it's a
helper flag that augments --advertise-routes. But that's an
implementation detail and we can still help users. We just have to
special case that pref and look whether the current routes include
both the v4 and v6 /0 routes.
Fixes#1767
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This doesn't make --operator implicit (which we might do in the
future), but it at least doesn't require repeating it in the future
when it already matches $USER.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
It was getting cleared on notify.
Document that authURL is cleared on notify and add a new field that
isn't, using the new field for the JSON status.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
I've spent two days searching for a theoretical wireguard-go bug
around receive functions exiting early.
I've found many bugs, but none of the flavor we're looking for.
Restore wireguard-go's logging around starting and stopping receive functions,
so that we can definitively rule in or out this particular theory.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
I see a bunch of these in some logs I'm looking at,
separated only by a few seconds.
Log the error so we can tell what's going on here.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
These were getting rate-limited for nodes with many peers.
Consolate the output into single lines, which are nicer anyway.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
With this change, the ipnserver's safesocket.Listen (the localhost
tcp.Listen) happens right away, before any synchronous
TUN/DNS/Engine/etc setup work, which might be slow, especially on
early boot on Windows.
Because the safesocket.Listen starts up early, that means localhost
TCP dials (the safesocket.Connect from the GUI) complete successfully
and thus the GUI avoids the MessageBox error. (I verified that
pacifies it, even without a Listener.Accept; I'd feared that Windows
localhost was maybe special and avoided the normal listener backlog).
Once the GUI can then connect immediately without errors, the various
timeouts then matter less, because the backend is no longer trying to
race against the GUI's timeout. So keep retrying on errors for a
minute, or 10 minutes if the system just booted in the past 10
minutes.
This should fix the problem with Windows 10 desktops auto-logging in
and starting the Tailscale frontend which was then showing a
MessageBox error about failing to connect to tailscaled, which was
slow coming up because the Windows networking stack wasn't up
yet. Fingers crossed.
Fixes#1313 (previously #1187, etc)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This change implements Windows version of install-system-daemon and
uninstall-system-daemon subcommands. When running the commands the
user will install or remove Tailscale Windows service.
Updates #1232
Signed-off-by: Alex Brainman <alex.brainman@gmail.com>
This used to not be necessary, because MagicDNS always did full proxying.
But with split DNS, we need to know which names to route to our resolver,
otherwise reverse lookups break.
This captures the entire CGNAT range, as well as our Tailscale ULA.
Signed-off-by: David Anderson <danderson@tailscale.com>
Otherwise, the existence of authoritative domains forces full
DNS proxying even when no other DNS config is present.
Signed-off-by: David Anderson <danderson@tailscale.com>
Logout used to be a no-op, so the ipnserver previously synthensized a Logout
on disconnect. Now that Logout actually invalidates the node key that was
forcing all GUI closes to log people out.
Instead, add a method to LocalBackend to specifically mean "the
Windows GUI closed, please forget all the state".
Fixestailscale/corp#1591 (ignoring the notification issues, tracked elsewhere)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Let caller (macOS) do it so Finder progress bar can be dismissed
without races.
Updates tailscale/corp#1575
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
We were accidentally logging oldPort -> oldPort.
Log oldPort as well as c.port; if we failed to get the preferred port
in a previous rebind, oldPort might differ from c.port.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
On macOS, we link the CLI into the GUI executable so it can be included in
the Mac App Store build.
You then need to run it like:
/Applications/Tailscale.app/Contents/MacOS/Tailscale <command>
But our old detection of whether you're running that Tailscale binary
in CLI mode wasn't accurate and often bit people. For instance, when
they made a typo, it then launched in GUI mode and broke their
existing GUI connection (starting a new IPNExtension) and took down
their network.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
It used to just store received files URL-escaped on disk, but that was
a half done lazy implementation, and pushed the burden to callers to
validate and write things to disk in an unescaped way.
Instead, do all the validation in the receive handler and only
accept filenames that are UTF-8 and in the intersection of valid
names that all platforms support.
Fixestailscale/corp#1594
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
So the NetworkMap-from-incremental-MapResponses can be tested easily.
And because direct.go was getting too big.
No change in behavior at this point. Just movement.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The ipn.NewPrefs func returns a populated ipn.Prefs for historical
reasons. It's not used or as important as it once was, but it hasn't
yet been removed. Meanwhile, it contains some default values that are
used on some platforms. Notably, for this bug (#1725), Windows/Mac use
its Prefs.RouteAll true value (to accept subnets), but Linux users
have always gotten a "false" value for that, because that's what
cmd/tailscale's CLI default flag is _for all operating systems_. That
meant that "tailscale up" was rightfully reporting that the user was
changing an implicit setting: RouteAll was changing from true with
false with the user explicitly saying so.
An obvious fix might be to change ipn.NewPrefs to return
Prefs.RouteAll == false on some platforms, but the logic is
complicated by darwin: we want RouteAll true on windows, android, ios,
and the GUI mac app, but not the CLI tailscaled-on-macOS mode. But
even if we used build tags (e.g. the "redo" build tag) to determine
what the default is, that then means we have duplicated and differing
"defaults" between both the CLI up flags and ipn.NewPrefs. Furthering
that complication didn't seem like a good idea.
So, changing the NewPrefs defaults is too invasive at this stage of
the release, as is removing the NewPrefs func entirely.
Instead, tweak slightly the semantics of the ipn.Prefs.ControlURL
field. This now defines that a ControlURL of the empty string means
both "we're uninitialized" and also "just use the default".
Then, once we have the "empty-string-means-unintialized" semantics,
use that to suppress "tailscale up"'s recent implicit-setting-revert
checking safety net, if we've never initialized Tailscale yet.
And update/add tests.
Fixes#1725
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Will add more tests later but this locks in all the existing warnings
and errors at least, and some of the existing non-error behavior.
Mostly I want this to exist before I actually fix#1725.
Updates #1725
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
And fix PeerSeenChange bug where it was ignored unless there were
other peer changes.
Updates tailscale/corp#1574
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Track endpoints internally with a new tailcfg.Endpoint type that
includes a typed netaddr.IPPort (instead of just a string) and
includes a type for how that endpoint was discovered (STUN, local,
etc).
Use []tailcfg.Endpoint instead of []string internally.
At the last second, send it to the control server as the existing
[]string for endpoints, but also include a new parallel
MapRequest.EndpointType []tailcfg.EndpointType, so the control server
can start filtering out less-important endpoint changes from
new-enough clients. Notably, STUN-discovered endpoints can be filtered
out from 1.6+ clients, as they can discover them amongst each other
via CallMeMaybe disco exchanges started over DERP. And STUN endpoints
change a lot, causing a lot of MapResposne updates. But portmapped
endpoints are worth keeping for now, as they they work right away
without requiring the firewall traversal extra RTT dance.
End result will be less control->client bandwidth. (despite negligible
increase in client->control bandwidth)
Updates tailscale/corp#1543
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
They were scattered/duplicated in misc places before.
It can't be in the client package itself for circular dep reasons.
This new package is basically tailcfg but for localhost
communications, instead of to control.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This changes the behavior of "tailscale up".
Previously "tailscale up" always did a new Start and reset all the settings.
Now "tailscale up" with no flags just brings the world [back] up.
(The opposite of "tailscale down").
But with flags, "tailscale up" now only is allowed to change
preferences if they're explicitly named in the flags. Otherwise it's
an error. Or you need to use --reset to explicitly nuke everything.
RELNOTE=tailscale up change
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Some paths already didn't. And in the future I hope to shut all the
notify funcs down end-to-end when nothing is connected (as in the
common case in tailscaled). Then we can save some JSON encoding work.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
We've been slowly making Start less special and making IPN a
multi-connection "watch" bus of changes, but this Start specialness
had remained.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Clear LLMNR and mdns flags, update reasoning for our settings,
and set our override priority harder than before when we want
to be primary resolver.
Signed-off-by: David Anderson <danderson@tailscale.com>
Debian resolvconf is not legacy, it's alive and well,
just historically before the other implementations.
Signed-off-by: David Anderson <danderson@tailscale.com>
On FreeBSD, we add the interface IP as a /48 to work around a kernel
bug, so we mustn't then try to add a /48 route to the Tailscale ULA,
since that will fail as a dupe.
Signed-off-by: David Anderson <danderson@tailscale.com>
It was only Linux and BSDs before, but now with netstack mode, it also works on
Windows and darwin. It's not worth limiting it to certain platforms.
Tailscaled itself can complain/fail if it doesn't like the settings
for the mode/OS it's operating under.
Updates #707
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This allows split-DNS configurations to not break clients on OSes that
haven't yet been ported to understand split DNS, by falling back to quad-9
as a global resolver when handed an "impossible to implement"
split-DNS config.
Part of #953. Needs to be removed before shipping 1.8.
Signed-off-by: David Anderson <danderson@tailscale.com>
With this change, all OSes can sort-of do split DNS, except that the
default upstream is hardcoded to 8.8.8.8 pending further plumbing.
Additionally, Windows 8-10 can do split DNS fully correctly, without
the 8.8.8.8 hack.
Part of #953.
Signed-off-by: David Anderson <danderson@tailscale.com>
When searching for the matching client identity, the returned
certificate chain was accidentally set to that of the last identity
returned by the certificate store instead of the one corresponding to
the selected identity.
Also, add some extra error checking for invalid certificate chains, just
in case.
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
We already had SetNotifyCallback elsewhere on controlclient, so use
that name.
Baby steps towards some CLI refactor work.
Updates tailscale/tailscale#1436
It seems that all the setups that support split DNS understand
this distinction, and it's an important one when translating
high-level configuration.
Part of #953.
Signed-off-by: David Anderson <danderson@tailscale.com>
Correctly reports that Win7 cannot do split DNS, and has a helper to
discover the "base" resolvers for the system.
Part of #953
Signed-off-by: David Anderson <danderson@tailscale.com>
OS implementations are going to support split DNS soon.
Until they're all in place, hardcode Primary=true to get
the old behavior.
Signed-off-by: David Anderson <danderson@tailscale.com>
This is usually the same as the requested interface, but on some
unixes can vary based on device number allocation, and on Windows
it's the GUID instead of the pretty name, since everything relating
to configuration wants the GUID.
Signed-off-by: David Anderson <danderson@tailscale.com>
wgengine/router.CallbackRouter needs to support both the Router
and OSConfigurator interfaces, so the setters can't both be called
Set.
Signed-off-by: David Anderson <danderson@tailscale.com>
It existed to work around the frequent opening and closing
of the conn.Bind done by wireguard-go.
The preceding commit removed that behavior,
so we can simply close the connections
when we are done with them.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
We don't use the port that wireguard-go passes to us (via magicsock.connBind.Open).
We ignore it entirely and use the port we selected.
When we tell wireguard-go that we're changing the listen_port,
it calls connBind.Close and then connBind.Open.
And in the meantime, it stops calling the receive functions,
which means that we stop receiving and processing UDP and DERP packets.
And that is Very Bad.
That was never a problem prior to b3ceca1dd7,
because we passed the SkipBindUpdate flag to our wireguard-go fork,
which told wireguard-go not to re-bind on listen_port changes.
That commit eliminated the SkipBindUpdate flag.
We could write a bunch of code to work around the gap.
We could add background readers that process UDP and DERP packets when wireguard-go isn't.
But it's simpler to never create the conditions in which wireguard-go rebinds.
The other scenario in which wireguard-go re-binds is device.Down.
Conveniently, we never call device.Down. We go from device.Up to device.Close,
and the latter only when we're shutting down a magicsock.Conn completely.
Rubber-ducked-by: Avery Pennarun <apenwarr@tailscale.com>
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The shim implements both network and DNS configurators,
and feeds both into a single callback that receives
both configs.
Signed-off-by: David Anderson <danderson@tailscale.com>
Upstream wireguard-go has changed its receive model.
NewDevice now accepts a conn.Bind interface.
The conn.Bind is stateless; magicsock.Conns are stateful.
To work around this, we add a connBind type that supports
cheap teardown and bring-up, backed by a Conn.
The new conn.Bind allows us to specify a set of receive functions,
rather than having to shoehorn everything into ReceiveIPv4 and ReceiveIPv6.
This lets us plumbing DERP messages directly into wireguard-go,
instead of having to mux them via ReceiveIPv4.
One consequence of the new conn.Bind layer is that
closing the wireguard-go device is now indistinguishable
from the routine bring-up and tear-down normally experienced
by a conn.Bind. We thus have to explicitly close the magicsock.Conn
when the close the wireguard-go device.
One downside of this change is that we are reliant on wireguard-go
to call receiveDERP to process DERP messages. This is fine for now,
but is perhaps something we should fix in the future.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The common Linux start-up path (fallback file defined but not
existing) was missing the log print of initializing Prefs. The code
was too twisty. Simplify a bit.
Updates #1573
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
They need some rework to do the right thing, in the meantime the direct
and resolvconf managers will work out.
The resolved implementation was never selected due to control-side settings.
The networkmanager implementation mostly doesn't get selected due to
unforeseen interactions with `resolvconf` on many platforms.
Both implementations also need rework to support the various routing modes
they're capable of.
Signed-off-by: David Anderson <danderson@tailscale.com>
It's only use to skip some optional initialization during cleanup,
but that work is very minor anyway, and about to change drastically.
Signed-off-by: David Anderson <danderson@tailscale.com>
It's currently unused, and no longer makes sense with the upcoming
DNS infrastructure. Keep it in tailcfg for now, since we need protocol
compat for a bit longer.
Signed-off-by: David Anderson <danderson@tailscale.com>
Old macOS clients required we populate this field to a non-null
value so we were unable to remove this field before.
Instead, keep the field but change its type to a custom empty struct
that can marshal/unmarshal JSON. And lock it in with a test.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The bool was already called useNetstack at the caller.
isUserspace (to mean netstack) is confusing next to wgengine.NewUserspaceEngine, as that's
a different type of 'userspace'.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The code is not obviously better or worse, but this makes the little warning
triangle in my editor go away, and the distraction removal is worth it.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Google Cloud Run does not implement NETLINK_ROUTE RTMGRP.
If initialization of the netlink socket or group membership
fails, fall back to a polling implementation.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
The resolver still only supports a single upstream config, and
ipn/wgengine still have to split up the DNS config, but this moves
closer to unifying the DNS configs.
As a handy side-effect of the refactor, IPv6 MagicDNS records exist
now.
Signed-off-by: David Anderson <danderson@tailscale.com>
They're only used internally and in tests, and have surprising
semantics in that they only resolve MagicDNS names, not upstream
resolver queries.
Signed-off-by: David Anderson <danderson@tailscale.com>
This adds a new ipn.MaskedPrefs embedding a ipn.Prefs, along with a
bunch of "has bits", kept in sync with tests & reflect.
Then it adds a Prefs.ApplyEdits(MaskedPrefs) method.
Then the ipn.Backend interface loses its weirdo SetWantRunning(bool)
method (that I added in 483141094c for "tailscale down")
and replaces it with EditPrefs (alongside the existing SetPrefs for now).
Then updates 'tailscale down' to use EditPrefs instead of SetWantRunning.
In the future, we can use this to do more interesting things with the
CLI, reconfiguring only certain properties without the reset-the-world
"tailscale up".
Updates #1436
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
We were going to remove this in Tailscale 1.3 but forgot.
This means Tailscale 1.8 users won't be able to downgrade to Tailscale
1.0, but that's fine.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Adding a subcommand which prints and logs a log marker. This should help
diagnose any issues that users face.
Fixes#1466
Signed-off-by: Maisem Ali <maisem@tailscale.com>
Instead of having the CLI check whether IP forwarding is enabled, ask
tailscaled. It has a better idea. If it's netstack, for instance, the
sysctl values don't matter. And it's possible that only the daemon has
permission to know.
Fixes#1626
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The call to appendEndpoint updates cpeer.Endpoints.
Then it is overwritten in the next line.
The only errors from appendEndpoint occur when
the host/port pair is malformed, but that cannot happen.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
IPv6 Unique Local Addresses are sometimes used with Network
Prefix Translation to reach the Internet. In that respect
their use is similar to the private IPv4 address ranges
10/8, 172.16/12, and 192.168/16.
Treat them as sufficient for AnyInterfaceUp(), but specifically
exclude Tailscale's own IPv6 ULA prefix to avoid mistakenly
trying to bootstrap Tailscale using Tailscale.
This helps in supporting Google Cloud Run, where the addresses
are 169.254.8.1/32 and fddf:3978:feb1:d745::c001/128 on eth1.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
It can end up executing an a new goroutine,
at which point instead of immediately stopping test execution, it hangs.
Since this is unexpected anyway, panic instead.
As a bonus, it makes call sites nicer and removes a kludge comment.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Without this, `tailscale status` ignores the --socket flag on macOS and
always talks to the IPNExtension, even if you wanted it to inspect a
userspace tailscaled.
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
So we have a documented & tested way to check whether we're in
netstack mode. To be used by future commits.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
For discovery when an explicit hostname/IP is known. We'll still
also send it via control for finding peers by a list.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The concrete type being encoded changed from a value to pointer
earlier and this was never adjusted.
(People don't frequently use TS_DEBUG_MAP to see requests, so it went
unnoticed until now.)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
"Fake" doesn't mean a lot any more, given that many components
of the engine can be faked out, including in valid production
configurations like userspace-networking.
Signed-off-by: David Anderson <danderson@tailscale.com>
This makes setup more explicit in prod codepaths, without
requiring a bunch of arguments or helpers for tests and
userspace mode.
Signed-off-by: David Anderson <danderson@tailscale.com>
The Windows CI machine experiences significant random execution delays.
For example, in this code from watchdog.go:
done := make(chan bool)
go func() {
start := time.Now()
mu.Lock()
There was a 500ms delay from initializing done to locking mu.
This test checks that we receive a sufficient number of events quickly enough.
In the face of random 500ms delays, unsurprisingly, the test fails.
There's not much principled we can do about it.
We could build a system of retries or attempt to detect these random delays,
but that game isn't worth the candle.
Skip the test.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This works around the close syscall being slow.
We can revert this if we find a fix or if Apple makes close fast again.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The tstun packagen contains both constructors for generic tun
Devices, and a wrapper that provides additional functionality.
Signed-off-by: David Anderson <danderson@tailscale.com>
IPv4 and IPv6 both work remotely, but IPv6 doesn't yet work from the
machine itself due to routing mysteries.
Untested yet on iOS, but previous prototype worked on iOS, so should
work the same.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Now callers (wgengine/monitor) don't need to mutate the state to remove
boring interfaces before calling State.Equal. Instead, the methods
to remove boring interfaces from the State are removed, as is
the reflect-using Equal method itself, and in their place is
a new EqualFiltered method that takes a func predicate to match
interfaces to compare.
And then the FilterInteresting predicate is added for use
with EqualFiltered to do the job that that wgengine/monitor
previously wanted.
Now wgengine/monitor can keep the full interface state around,
including the "boring" interfaces, which we'll need for peerapi on
macOS/iOS to bind to the interface index of the utunN device.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
We have it already but threw it away. But macOS/iOS code will
be needing the interface index, so hang on to it.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
control/controlclient: sign RegisterRequest
Some customers wish to verify eligibility for devices to join their
tailnets using machine identity certificates. TLS client certs could
potentially fulfill this role but the initial customer for this feature
has technical requirements that prevent their use. Instead, the
certificate is loaded from the Windows local machine certificate store
and uses its RSA public key to sign the RegisterRequest message.
There is room to improve the flexibility of this feature in future and
it is currently only tested on Windows (although Darwin theoretically
works too), but this offers a reasonable starting place for now.
Updates tailscale/coral#6
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
So we can empty import the guts of cmd/tailscaled from another
module for go mod tidy reasons.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This adds an easy and portable way for us to document how to get
your Tailscale IP address.
$ tailscale ip
100.74.70.3
fd7a:115c:a1e0:ab12:4843:cd96:624a:4603
$ tailscale ip -4
100.74.70.3
$ tailscale ip -6
fd7a:115c:a1e0:ab12:4843:cd96:624a:4603
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
e.g.
$ tailscale ping 1.1.1.1
exit node found but not enabled
$ tailscale ping 10.2.200.2
node "tsbfvlan2" found, but not using its 10.2.200.0/24 route
$ sudo tailscale up --accept-routes
$ tailscale ping 10.2.200.2
pong from tsbfvlan2 (100.124.196.94) via 10.2.200.34:41641 in 1ms
$ tailscale ping mon.ts.tailscale.com
pong from monitoring (100.88.178.64) via DERP(sfo) in 83ms
pong from monitoring (100.88.178.64) via DERP(sfo) in 21ms
pong from monitoring (100.88.178.64) via [2604:a880:4:d1::37:d001]:41641 in 22ms
This necessarily moves code up from magicsock to wgengine, so we can
look at the actual wireguard config.
Fixes#1564
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Add proto to flowtrack.Tuple.
Add types/ipproto leaf package to break a cycle.
Server-side ACL work remains.
Updates #1516
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Mash up some code from ffcli and std's flag package to make a default
usage func that's super explicit for those not familiar with the Go
style flags. Only show double hyphens in usage text (but still accept both),
and show default values, and only show the proper usage of boolean flags.
Fixes#1353Fixes#1529
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
"public IP" is defined as an IP address configured on the exit node
itself that isn't in the list of forbidden ranges (RFC1918, CGNAT,
Tailscale).
Fixes#1522.
Signed-off-by: David Anderson <danderson@tailscale.com>
The direct client already logs it in JSON form. Then it's immediately
logged again in an unformatted dump, so this removes that unformatted
one.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This reverts the revert commit 84aba349d9.
And changes us to use inet.af/netstack.
Updates #1518
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
In f45a9e291b (2021-03-04), I tried to bump CurrentMapRequestVersion
to 12 but only documented the meaning of 12 but forgot to actually
increase it from 11.
Mapver 11 was added in ea49b1e811 (2021-03-03).
Fix this in its own commit so we can cherry-pick it to the 1.6 release
branch.
Should help iOS battery life on NEProvider.wake/skip events
with useless route updates that shouldn't cause re-STUNs.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
We strip them control-side anyway, and we already strip IPv4 link
local, so there's no point uploading them. And iOS has a ton of them,
which results in somewhat silly amount of traffic in the MapRequest.
We'll be doing same-LAN-inter-tailscaled link-local traffic a
different way, with same-LAN discovery.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
To atone for 1d7f9d5b4a, the revert of 4224b3f731.
At least it's fast again, even if it's shelling out to cmd.exe (once now).
Updates #1478
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
gVisor fixed their google/gvisor#1446 so we can include gVisor mode
on 32-bit machines.
A few minor upstream API changes, as normal.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
We basically already had the RIB-parsing Go code for this in both
net/interfaces and wgengine/monitor, for other reasons.
Fixes#1426Fixes#1471
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This change makes it impossible to set your own IP address as the exit node for this system.
Fixes#1489
Signed-off-by: Christine Dodrill <xe@tailscale.com>
So a region can be used if needed, but won't be STUN-probed or used as
its home.
This gives us another possible debugging mechanism for #1310, or can
be used as a short-term measure against DERP flip-flops for people
equidistant between regions if our hysteresis still isn't good enough.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
IP forwarding is not required when advertising a machine's local IPs
over Tailscale.
Fixes#1435.
Signed-off-by: David Anderson <danderson@tailscale.com>
This reverts commit 08949d4ef1.
I think this code was aspirational. There's no code that sets up the
appropriate NAT code using pfctl/etc. See #911 and #1475.
Updates #1475
Updates #911
No server support yet, but we want Tailscale 1.6 clients to be able to respond
to them when the server can do it.
Updates #1310
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
There was a logical race where Conn.Rebind could acquire the
RebindingUDPConn mutex, close the connection, fail to rebind, release
the mutex, and then because the mutex was no longer held, ReceiveIPv4
wouldn't retry reads that failed with net.ErrClosed, letting that
error back to wireguard-go, which would then stop running that receive
IP goroutine.
Instead, keep the RebindingUDPConn mutex held for the entirety of the
replacement in all cases.
Updates tailscale/corp#1289
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
interfaces.State.String tries to print a concise summary of the
network state, removing any interfaces that don't have any or any
interesting IP addresses. On macOS and iOS, for instance, there are a
ton of misc things.
But the link monitor based its are-there-changes decision on
interfaces.State.Equal, which just used reflect.DeepEqual, including
comparing all the boring interfaces. On macOS, when turning wifi on or off, there
are a ton of misc boring interface changes, resulting in hitting an earlier
check I'd added on suspicion this was happening:
[unexpected] network state changed, but stringification didn't
This fixes that by instead adding a new
interfaces.State.RemoveUninterestingInterfacesAndAddresses method that
does, uh, that. Then use that in the monitor. So then when Equal is
used later, it's DeepEqualing the already-cleaned version with only
interesting interfaces.
This makes cmd/tailscaled debug --monitor much less noisy.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Windows was only running the localapi on the debug port which was a
stopgap at the time while doing peercreds work. Removed that, and
wired it up correctly, with some more docs.
More clean-up to do after 1.6, moving the localhost TCP auth code into
the peercreds package. But that's too much for now, so the docs will
have to suffice, even if it's at a bit of an awkward stage with the
newly-renamed "NotWindows" field, which still isn't named well, but
it's better than its old name of "Unknown" which hasn't been accurate
since unix sock peercreds work anyway.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
So the control server can test whether a client's actually present.
Most clients are over HTTP/2, so these pings (to the same host) are
super cheap.
This mimics the earlier goroutine dump mechanism.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Previously the CLI could only find the HTTP auth token when running
the CLI outside the sandbox, not like
/Applications/Tailscale.app/Contents/MacOS/Tailscale when that was
from the App Store.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The debub subcommand was moved in
6254efb9ef because the monitor brought
in tons of dependencies to the cmd/tailscale binary, but there wasn't
any need to remove the whole subcommand itself.
Add it back, with a tool to dump the local daemon's goroutines.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Not beautiful, but I'm debugging connectivity problems on
NEProvider.sleep+wake and need more clues.
Updates #1426
Updates tailscale/corp#1289
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This is important because some of those v6 sockets are actually
dual-stacked sockets, so this is our only chance of discovering
some services.
Fixes#1443.
Signed-off-by: David Anderson <danderson@tailscale.com>
And if we have over 10,000 CGNAT routes, just route the entire
CGNAT range. (for the hello test server)
Fixes#1450
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The Engine.LinkChange method was recently removed in
e3df29d488 while misremembering how
Android's link state mechanism worked.
Rather than do some last minute rearchitecting of link state on
Android before Tailscale 1.6, restore the old Engine.LinkChange hook
for now so the Android client doesn't need any changes. But change how
it's implemented to instead inject an event into the link monitor.
Fixes#1427
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This is necessary because either protocol can be disabled globally by a
Windows registry policy, at which point trying to touch that address
family results in "Element not found" errors. This change skips programming
address families that Windows tell us are unavailable.
Fixes#1396.
Signed-off-by: David Anderson <danderson@tailscale.com>
Not great, but lets people working on new ports get going more quickly
without having to do everything up front.
As the link monitor is getting used more, I felt bad having a useless
implementation.
Updates #815
Updates #1427
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
DefaultRouteInterface was previously guarded by build tags such that
it was only accessible to tailscaled-on-macos, but there was no reason
for that. It runs fine in the sandbox and gives better default info,
so merge its file into interfaces_darwin.go.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
We used to allow that, but now it just crashes.
Separately I need to figure out why it got into this path at all,
which is #1416.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Tor has a location-hidden service feature that enables users to host services
from inside the Tor network. Each of these gets a unique DNS name that ends with
.onion. As it stands now, if a misbehaving application somehow manages to make
a .onion DNS request to our DNS server, we will forward that to the DNS server,
which could leak that to malicious third parties. See the recent bug Brave had
with this[1] for more context.
RFC 7686 suggests that name resolution APIs and libraries MUST respond with
NXDOMAIN unless they can actually handle Tor lookups. We can't handle .onion
lookups, so we reject them.
[1]: https://twitter.com/albinowax/status/1362737949872431108Fixestailscale/corp#1351
Signed-off-by: Christine Dodrill <xe@tailscale.com>
Part of overall effort to clean up, unify, use link monitoring more,
and make Tailscale quieter when all networks are down. This is especially
bad on macOS where we can get killed for not being polite it seems.
(But we should be polite in any case)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Don't use os.NewFile or (*os.File).Close on the AF_ROUTE socket. It
apparently does weird things to the fd and at least doesn't seem to
close it. Just use the unix package.
The test doesn't actually fail reliably before the fix, though. It
was an attempt. But this fixes the integration tests.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Prior to e3df29d488, the Engine.SetLinkChangeCallback fired
immediately, even if there was no change. The ipnlocal code apparently
depended on that, and it broke integration tests (which live in
another repo). So mimic the old behavior and call the ipnlocal
callback immediately at init.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This is a fork of wireguard-windows's firewall package, with
the firewall rules adjusted to better line up with tailscale's
needs.
The package was taken from commit 3cc76ed5f222ec82748ef3bd8c41d4b059e28cdb
in our fork of wireguard-go.
Signed-off-by: David Anderson <danderson@tailscale.com>
Gets it out of wgengine so the Engine isn't responsible for being a
callback registration hub for it.
This also removes the Engine.LinkChange method, as it's no longer
necessary. The monitor tells us about changes; it doesn't seem to
need any help. (Currently it was only used by Swift, but as of
14dc790137 we just do the same from Go)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
And add a --socks5-server flag.
And fix a race in SOCKS5 replies where the response header was written
concurrently with the copy from the backend.
Co-authored with Naman Sood.
Updates #707
Updates #504
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Previously tailscaled on macOS was running "/sbin/route monitor" as a
child process, but child processes aren't allowed in the Network
Extension / App Store sandbox. Instead, just do what "/sbin/route monitor"
itself does: unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, 0) and read that.
We also parse it now, but don't do anything with the parsed results yet.
We will over time, as we have with Linux netlink messages over time.
Currently any message is considered a signal to poll and see what changed.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Currently it assumes exactly 1 registered callback. This changes it to
support 0, 1, or more than 1.
This is a step towards plumbing wgengine/monitor into more places (and
moving some of wgengine's interface state fetching into monitor in a
later step)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
For option (d) of #1405.
For an HTTPS request of /bootstrap-dns, this returns e.g.:
{
"log.tailscale.io": [
"2600:1f14:436:d603:342:4c0d:2df9:191b",
"34.210.105.16"
],
"login.tailscale.com": [
"2a05:d014:386:203:f8b4:1d5a:f163:e187",
"3.121.18.47"
]
}
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
UIs need to see the full unedited netmap in order to know what exit nodes they
can offer to the user.
Signed-off-by: David Anderson <danderson@tailscale.com>
* move probing out of netcheck into new net/portmapper package
* use PCP ANNOUNCE op codes for PCP discovery, rather than causing
short-lived (sub-second) side effects with a 1-second-expiring map +
delete.
* track when we heard things from the router so we can be less wasteful
in querying the router's port mapping services in the future
* use portmapper from magicsock to map a public port
Fixes#1298Fixes#1080Fixes#1001
Updates #864
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Importing the non-main package was missing some dependencies that
"go mod tidy" would then cleanup. Also added a non-ignore build tag to
avoid other tools getting upset about importing a main package.
Signed-off-by: Filippo Valsorda <hi@filippo.io>
$ GOOS=openbsd GOARCH=arm64 go install tailscale.com/cmd/...@latest
pkg/mod/github.com/kr/pty@v1.1.4-0.20190131011033-7dc38fb350b1/pty_openbsd.go:24:10: undefined: ptmget
pkg/mod/github.com/kr/pty@v1.1.4-0.20190131011033-7dc38fb350b1/pty_openbsd.go:25:34: undefined: ioctl_PTMGET
"go mod tidy" did some unrelated work in go.sum, maybe because it was
not run with Go 1.16 before.
Signed-off-by: Filippo Valsorda <hi@filippo.io>
This makes cidrDiff do as much as possible before failing, and makes a
delete of an already-deleted rule be a no-op. We should never do this
ourselves, but other things on the system can, and this should help us
recover a bit.
Also adds the start of root-requiring tests.
TODO: hook into wgengine/monitor and notice when routes are changed
behind our back, and invalidate our routes map and re-read from
kernel (via the ip command) at least on the next reconfig call.
Updates tailscale/corp#1338
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
And open up socket permissions like Linux, now that we know who
connections are from.
This uses the new inet.af/peercred that supports Linux and Darwin at
the moment.
Fixes#1347Fixes#1348
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Tangentially related to #987, #177, #594, #925, #505
Motivated by rebooting a launchd-controlled tailscaled and it going
into SetNetworkUp(false) mode immediately because there really is no
network up at system boot, but then it got stuck in that paused state
forever, without a monitor implementation.
The interface.State logging tried to only log interfaces which had
interesting IPs, but the what-is-interesting checks differed between
the code that gathered the interface names to print and the printing
of their addresses.
When a handshake race occurs, a queued data packet can get lost.
TestTwoDevicePing expected that the very first data packet would arrive.
This caused occasional flakes.
Change TestTwoDevicePing to repeatedly re-send packets
and succeed when one of them makes it through.
This is acceptable (vs making WireGuard not drop the packets)
because this only affects communication with extremely old clients.
And those extremely old clients will eventually connect,
because the kernel will retry sends on timeout.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
We modified the standard net package to not allocate a *net.UDPAddr
during a call to (*net.UDPConn).ReadFromUDP if the caller's use
of the *net.UDPAddr does not cause it to escape.
That is https://golang.org/cl/291390.
This is the companion change to magicsock.
There are two changes required.
First, call ReadFromUDP instead of ReadFrom, if possible.
ReadFrom returns a net.Addr, which is an interface, which always allocates.
Second, reduce the lifetime of the returned *net.UDPAddr.
We do this by immediately converting it into a netaddr.IPPort.
We left the existing RebindingUDPConn.ReadFrom method in place,
as it is required to satisfy the net.PacketConn interface.
With the upstream change and both of these fixes in place,
we have removed one large allocation per packet received.
name old time/op new time/op delta
ReceiveFrom-8 16.7µs ± 5% 16.4µs ± 8% ~ (p=0.310 n=5+5)
name old alloc/op new alloc/op delta
ReceiveFrom-8 112B ± 0% 64B ± 0% -42.86% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
ReceiveFrom-8 3.00 ± 0% 2.00 ± 0% -33.33% (p=0.008 n=5+5)
Co-authored-by: Sonia Appasamy <sonia@tailscale.com>
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
addrSet maintained duplicate lists of netaddr.IPPorts and net.UDPAddrs.
Unify to use the netaddr type only.
This makes (*Conn).ReceiveIPvN a bit uglier,
but that'll be cleaned up in a subsequent commit.
This is preparatory work to remove an allocation from ReceiveIPv4.
Co-authored-by: Sonia Appasamy <sonia@tailscale.com>
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
I based my estimation of the required timeout based on locally
observed behavior. But CI machines are worse than my local machine.
16s was enough to reduce flakiness but not eliminate it. Bump it up again.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Build tags have been updated to build native Apple M1 binaries, existing build
tags for ios have been changed from darwin,arm64 to ios,arm64.
With this change, running go build cmd/tailscale{,d}/tailscale{,d}.go on an Apple
machine with the new processor works and resulting binaries show the expected
architecture, e.g. tailscale: Mach-O 64-bit executable arm64.
Tested using go version go1.16beta1 darwin/arm64.
Updates #943
Signed-off-by: moncho <50428+moncho@users.noreply.github.com>
It only affects 'go install ./...', etc, and only on darwin/arm64 (M1 Macs) where
the go-ole package doesn't compile.
No need to build it.
Updates #943
This was in place because retrieved allowed_ips was very expensive.
Upstream changed the data structure to make them cheaper to compute.
This commit is an experiment to find out whether they're now cheap enough.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
We removed the "fast retry" code from our wireguard-go fork.
As a result, pings can take longer to transit when retries are required.
Allow that.
Fixes#1277
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The fix can make this test run unconditionally.
This moves code from 5c619882bc for
testability but doesn't fix it yet. The #1282 problem remains (when I
wrote its wake-up mechanism, I forgot there were N DERP readers
funneling into 1 UDP reader, and the code just isn't correct at all
for that case).
Also factor out some test helper code from BenchmarkReceiveFrom.
The refactoring in magicsock.go for testability should have no
behavior change.
If no exit node is specified, the filter must still run to remove
offered default routes from all peers.
Signed-off-by: David Anderson <danderson@tailscale.com>
This one alone doesn't modify the global dependency map much
(depaware.txt if anything looks slightly worse), but it leave
controlclient as only containing NetworkMap:
bradfitz@tsdev:~/src/tailscale.com/ipn$ grep -F "controlclient." *.go
backend.go: NetMap *controlclient.NetworkMap // new netmap received
fake_test.go: b.notify(Notify{NetMap: &controlclient.NetworkMap{}})
fake_test.go: b.notify(Notify{NetMap: &controlclient.NetworkMap{}})
handle.go: netmapCache *controlclient.NetworkMap
handle.go:func (h *Handle) NetMap() *controlclient.NetworkMap {
Once that goes into a leaf package, then ipn doesn't depend on
controlclient at all, and then the client gets smaller.
Updates #1278
Upstream wireguard-go decided to use errors.Is(err, net.ErrClosed)
instead of checking the error string.
It also provided an unsafe linknamed version of net.ErrClosed
for clients running Go 1.15. Switch to that.
This reduces the time required for the wgengine/magicsock tests
on my machine from ~35s back to the ~13s it was before
456cf8a376.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Magicsock started dropping all traffic internally when Tailscale is
shut down, to avoid spurious wireguard logspam. This made the benchmark
not receive anything. Setting a dummy private key is sufficient to get
magicsock to pass traffic for benchmarking purposes.
Fixes#1270.
Signed-off-by: David Anderson <danderson@tailscale.com>
And move a couple other types down into leafier packages.
Now cmd/tailscale doesn't bring in netlink, magicsock, wgengine, etc.
Fixes#1181
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Unused for now, but I want to backport this commit to 1.4 so 1.6 can
start sending these and then at least 1.4 logs will stringify nicely.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This reverts commit da4ec54756.
Since v6 got disabled for Windows nodes, I need the debug flag back
to figure out why it was broken.
Signed-off-by: David Anderson <danderson@tailscale.com>
Use tb.Cleanup to simplify both the API and the implementation.
One behavior change: When the number of goroutines shrinks, don't log.
I've never found these logs to be useful, and they frequently add noise.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The code was using a C "int", which is a signed 32-bit integer.
That means some valid IP addresses were negative numbers.
(In particular, the default router address handed out by AT&T
fiber: 192.168.1.254. No I don't know why they do that.)
A negative number is < 255, and so was treated by the Go code
as an error.
This fixes the unit test failure:
$ go test -v -run=TestLikelyHomeRouterIPSyscallExec ./net/interfaces
=== RUN TestLikelyHomeRouterIPSyscallExec
interfaces_darwin_cgo_test.go:15: syscall() = invalid IP, false, netstat = 192.168.1.254, true
--- FAIL: TestLikelyHomeRouterIPSyscallExec (0.00s)
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
Previously we disabled v6 support if the disable_policy knob was
missing in /proc, but some kernels support policy routing without
exposing the toggle. So instead, treat disable_policy absence as a
"maybe", and make the direct `ip -6 rule` probing a bit more
elaborate to compensate.
Fixes#1241.
Signed-off-by: David Anderson <danderson@tailscale.com>
This is mostly code movement from the wireguard-go repo.
Most of the new wgcfg package corresponds to the wireguard-go wgcfg package.
wgengine/wgcfg/device{_test}.go was device/config{_test}.go.
There were substantive but simple changes to device_test.go to remove
internal package device references.
The API of device.Config (now wgcfg.DeviceConfig) grew an error return;
we previously logged the error and threw it away.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
We log lines like this:
c.logf("[v1] magicsock: disco: %v->%v (%v, %v) sent %v", c.discoShort, dstDisco.ShortString(), dstKey.ShortString(), derpStr(dst.String()), disco.MessageSummary(m))
The leading [v1] causes it to get unintentionally rate limited.
Until we have a proper fix, work around it.
Fixes#1216
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Signed-off-by: Sonia Appasamy <sonia@tailscale.com>
Consolidates the node display name logic from each of the clients into
tailcfg.Node. UI clients can use these names directly, rather than computing
them independently.
On Windows, configureInterface starts a goroutine reconfiguring the
Windows firewall.
But if configureInterface fails later, that goroutine kept running and
likely failing forever, spamming logs. Make it stop quietly if its
launching goroutine filed.
Rewrite log lines on the fly, based on the set of known peers.
This enables us to use upstream wireguard-go logging,
but maintain the Tailscale-style peer public key identifiers
that the rest of our systems (and people) expect.
Fixes#1183
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Continuation of earlier two umask changes,
5611f290eb and
d6e9fb1df0.
This change mostly affects us, running tailscaled as root by hand (wit
a umask of 0077), not under systemd. End users running tailscaled
under systemd won't have a umask.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Also, don't try to use IPv6 LinkLocalUnicast addresses for now. Like endpoints
exchanged with control, we share them but don't yet use them.
Updates #1172
c8c493f3d9 made it always say
`created=false` which scared me when I saw it, as that would've implied
things were broken much worse. Fortunately the logging was just wrong.
DstToString is used in two places in wireguard-go: Logging and uapi.
We are switching to use uapi for wireguard-go config.
To preserve existing behavior, we need the full set of addrs.
And for logging, having the full set of addrs seems useful.
(The Addrs method itself is slated for removal. When that happens,
the implementation will move to DstToString.)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
To save CPU and wakeups, don't run the DERP cleanup timer regularly
unless there is a non-home DERP connection open.
Also eliminates the goroutine, moving to a time.AfterFunc.
Updates #1034
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This reverts commit 08baa17d9a.
It caused deadlocks due to lock ordering violations.
It was not the right fix, and thus should simply be reverted
while we look for the right fix (if we haven't already found it
in the interim; we've fixed other logging-after-test issues).
Fixes#1161
context.cancelCtx.Done involves a mutex and isn't as cheap as I
previously assumed. Convert the donec method into a struct field and
store the channel value once. Our one magicsock.Conn gets one pointer
larger, but it cuts ~1% of the CPU time of the ReceiveFrom benchmark
and removes a bubble from the --svg output :)
+ add a test for parseAndRemoveLogLevel()
+ add a test for drainPendingMessages()
+ test JSON log encoding including several special cases
Other tests frequently send logs but a) don't check the result and
b) do so by happenstance, such that the code in encode() was not
consistently being exercised and leading to spurious changes in
code coverage. These tests attempt to more systematically test
the logging function.
This is the second attempt to add these tests, the first attempt
(in https://github.com/tailscale/tailscale/pull/1114) had two issues:
1. httptest.NewServer creates multiple goroutine handlers, and
logtail uses goroutines to upload, but the first version had no
locking in the server to guard this.
Moved data handling into channels to get synchronization.
2. The channel to notify the test of the arrival of data had a depth
of 1, in cases where the Logger sent multiple uploads it would
block the server.
This resulted in the first iteration of these tests being flaky,
and we reverted it.
This new version of the tests has passed with
go test -race -count=10000
and seems solid.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
This test serves two purposes:
+ check that Write() returns an error if the tstun has been
closed.
+ ensure that the close-related code in tstun is exercised in
a test case. We were getting spurious code coverage adds/drops
based on timing of when the test case finished.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Windows has a low resolution timer.
Some of the tests assumed that unblock takes effect immediately.
Consider:
t := time.Now()
elapsed := time.Now().After(t)
It seems plausible that elapsed should always be true.
However, with a low resolution timer, that might fail.
Change time.Now().After to !time.Now().Before,
so that unblocking always takes effect immediately.
Fixes#873.
22507adf54 stopped relying on
our fork of wireguard-go's UpdateDst callback.
As a result, we can unwind that code,
and the extra return value of ReceiveIPv{4,6}.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
TwoDevicePing is explicitly testing the behavior of the legacy codepath, everything
else is happy to assume that code no longer exists.
Signed-off-by: David Anderson <danderson@tailscale.com>
Previously, this benchmark relied on behavior of the legacy
receive codepath, which I changed in 22507adf. With this
change, the benchmark instead relies on the new active discovery
path.
Signed-off-by: David Anderson <danderson@tailscale.com>
This prevents us from continuing to do unnecessary work
(including logging) after the connection has closed.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This adds a new IP Protocol type, TSMP on protocol number 99 for
sending inter-tailscale messages over WireGuard, currently just for
why a peer rejects TCP SYNs (ACL rejection, shields up, and in the
future: nothing listening, something listening on that port but wrong
interface, etc)
Updates #1094
Updates tailscale/corp#1185
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This partially reverts d6e9fb1df0, which modified the permissions
on the tailscaled Unix socket and thus required "sudo tailscale" even
for "tailscale status".
Instead, open the permissions back up (on Linux only) but have the
server look at the peer creds and only permit read-only actions unless
you're root.
In the future we'll also have a group that can do mutable actions.
On OpenBSD and FreeBSD, the permissions on the socket remain locked
down to 0600 from d6e9fb1df0.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Commit 68ddf1 removed code that reads
`SOFTWARE\Tailscale IPN\SearchList` registry value. But the commit
left code that writes that value.
So now this package writes and never reads the value.
Remove the code to stop pointless work.
Updates #853
Signed-off-by: Alex Brainman <alex.brainman@gmail.com>
This eliminates a dependency on wgcfg.Endpoint,
as part of the effort to eliminate our wireguard-go fork.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This makes connectivity between ancient and new tailscale nodes slightly
worse in some cases, but only in cases where the ancient version would
likely have failed to get connectivity anyway.
Signed-off-by: David Anderson <danderson@tailscale.com>
Here's an example log line in the new format:
[RATE LIMITED] format string "open-conn-track: timeout opening %v; no associated peer node" (example: "open-conn-track: timeout opening ([ip] => [ip]); no associated peer node")
This should make debugging logging issues a bit easier, and give more
context as to why something was rate limited. This change was proposed
in a comment on #1110.
Signed-off-by: Smitty <me@smitop.com>
This reverts commit e4f53e9b6f.
At least two of these tests are flakey, reverting until they can be
made more robust.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
This is what every other DNS resolver I could find does, so tsdns
should do it to. This also helps avoid weird error messages about
non-existent records being unimplemented, and thus fixes#848.
Signed-off-by: Smitty <me@smitop.com>
* logtail: test parseAndRemoveLogLevel()
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
* logtail: test JSON log encoding.
Expand TestUploadMessages to also exercise the encoding functions
in logtail, like JSON logging and timestamps.
Other tests frequently send logs but a) don't check the result and
b) do so by happenstance, such that the lines in encode() were not
consistently being exercised and leading to spurious changes in
code coverage.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
* logtail: add a test for drainPendingMessages
Make the client buffer some messages before the upload server
becomes available.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
* logtail: use %q, raw strings, and io.WriteString
%q escapes binary characters for us.
raw strings avoid so much backslash escaping
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Right now TestFastShutdown tries to upload logs to localhost:1234,
which will most likely respond with an error. However if one has an
actual service running on port 1234, it would receive a connection
attempting to POST every time the unit test runs.
Start a local server and direct the upload there instead.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
In sendDiscoMessage there is a check of whether the connection is
closed, which is not being reliably exercised by other tests.
This shows up in code coverage reports, the lines of code in
sendDiscoMessage are alternately added and subtracted from
code coverage.
Add a test to specifically exercise and verify this code path.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Start an HTTP server to accept POST requests, and upload some logs to
it. Check that uploaded logs were received.
Code in logtail:drainPending was not being reliably exercised by other
tests. This shows up in code coverage reports, as lines of code in
drainPending are alternately added and subtracted from code coverage.
This test will reliably exercise and verify this code.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
All cases in lessThan are not reliably exercised by other tests.
This shows up in code coverage metrics as lines in lessThan are
alternately added and removed from coverage.
Add a test case to systematically test all conditions.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
In derpWriteChanOfAddr when we call derphttp.NewRegionClient(),
there is a check of whether the connection is already errored and
if so it returns before grabbing the lock. The lock might already
be held and would be a deadlock.
This corner case is not being reliably exercised by other tests.
This shows up in code coverage reports, the lines of code in
derpWriteChanOfAddr are alternately added and subtracted from
code coverage.
Add a test to specifically exercise this code path, and verify that
it doesn't deadlock.
This is the best tradeoff I could come up with:
+ the moment code calls Err() to check if there is an error, we
grab the lock to make sure it would deadlock if it tries to grab
the lock itself.
+ if a new call to Err() is added in this code path, only the
first one will be covered and the rest will not be tested.
+ this test doesn't verify whether code is checking for Err() in
the right place, which ideally I guess it would.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Users in Amsterdam (as one example) were flipping back and forth
between equidistant London & Frankfurt relays too much.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
netaddr.IP no longer allocates, so don't need a cache or all its associated
code/complexity.
This totally removes groupcache/lru from the deps.
Also go mod tidy.
* wengine/netstack: bump gvisor to latest version
Signed-off-by: Naman Sood <naman@tailscale.com>
* update dependencies
Signed-off-by: Naman Sood <naman@tailscale.com>
* Don't change hardcoded IP
Signed-off-by: Naman Sood <naman@tailscale.com>
Not usefully functional yet (mostly a proof of concept), but getting
it submitted for some work @namansood is going to do atop this.
Updates #707
Updates #634
Updates #48
Updates #835
* show DNS name over hostname, removing domain's common MagicDNS suffix.
only show hostname if there's no DNS name.
but still show shared devices' MagicDNS FQDN.
* remove nerdy low-level details by default: endpoints, DERP relay,
public key. They're available in JSON mode still for those who need
them.
* only show endpoint or DERP relay when it's active with the goal of
making debugging easier. (so it's easier for users to understand
what's happening) The asterisks are gone.
* remove Tx/Rx numbers by default for idle peers; only show them when
there's traffic.
* include peers' owner login names
* add CLI option to not show peers (matching --self=true, --peers= also
defaults to true)
* sort by DNS/host name, not public key
* reorder columns
If any goroutine continues to use the logger in TestLocalLogLines
after the test finishes, the test panics.
The culprit for this was wireguard-go; the previous commit fixed that.
This commit adds suspenders: When the test is done, make logging calls
into no-ops.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The log lines that wireguard-go prints as it starts
and stops its worker routines are mostly noise.
They also happen after other work is completed,
which causes failures in some of the log testing packages.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This appears to have been the intent of the previous code,
but in practice, it only returned A records.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
To be honest I'm not fond of Golden Bytes tests like this, but
not so much as to want to rewrite the whole test. The DNS byte
format is essentially immutable at this point, the encoded bytes
aren't going to change. The rest of the test assumptions about
hostnames might, but we can fix that when it comes.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
Previously, any change to endpoints or hostinfo (or hostinfo's
netinfo) would result in the long-running map request HTTP stream
being torn down and restarted, losing all compression context along
with it.
This change makes us instead send a lite map request (OmitPeers: true,
Stream: false) that doesn't subscribe to anything, and then the
coordination server knows to not close other streams for that node
when it recives a lite request.
Fixestailscale/corp#797
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
+ we don't need an exactly accurate count of the number of times each
time ran. Remove -covermode, the default "set" will be fine to just
track whether a given line ran at all.
+ add -benchtime=1x. We only need to run the benchmarks once.
+ -bench=. to match any character.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
We include -bench because some parts of the codebase, like
smallzstd, do not have regular unit tests but do have very
good benchmark tests that covers all functions.
Signed-off-by: Denton Gentry <dgentry@tailscale.com>
eccc167 introduced closeHandle which opened the handle,
but never closed it.
Windows handles should be closed.
Updates #921
Signed-off-by: Alex Brainman <alex.brainman@gmail.com>
Research in issue #1063 uncovered why tailscaled would fail with
ProtectClock enabled (it implicitly enabled DevicePolicy=closed).
This knowledge in turn also opens the door for locking down /dev
further, e.g. explicitly setting DevicePolicy=strict (instead of
closed), and making /dev private for the unit.
Additional possible future (or downstream) lockdown that can be done
is setting `PrivateDevices=true` (with `BindPaths=/dev/net/`), however,
systemd 233 or later is required for this, and tailscaled currently need
to work for systemd down to version 215.
Closes https://github.com/tailscale/tailscale/issues/1063
Signed-off-by: Frederik “Freso” S. Olesen <freso.dk@gmail.com>
Previously the client had heuristics to calculate which DNS search domains
to set, based on the peers' names. Unfortunately that prevented us from
doing some things we wanted to do server-side related to node sharing.
So, bump MapRequest.Version to 9 to signal that the client only uses the
explicitly configured DNS search domains and doesn't augment it with its own
list.
Updates tailscale/corp#1026
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This is a replacement for the key-related parts
of the wireguard-go wgcfg package.
This is almost a straight copy/paste from the wgcfg package.
I have slightly changed some of the exported functions and types
to avoid stutter, added and tweaked some comments,
and removed some now-unused code.
To avoid having wireguard-go depend on this new package,
wgcfg will keep its key types.
We translate into and out of those types at the last minute.
These few remaining uses will be eliminated alongside
the rest of the wgcfg package.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
While not a full capability lockdown of the systemd unit, this still
improves sandboxing and security of the running process a good deal.
Signed-off-by: Frederik “Freso” S. Olesen <freso.dk@gmail.com>
The fallthrough happened to work in controlclient already due to the
/etc/os-release PRETTY_NAME default, but make it explicit so it
doesn't look like an accident.
Also add it to version/distro, even though nothing needs it yet.
The windows key timeout is longer than the wgengine watchdog timeout,
which means we never reach the timeout, instead the process exits.
Reduce the timeout so if we do hit it, at least the process continues.
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
On Win10, there's a hardcoded GUID and this works.
On Win7, this GUID changes and we need to ask the tun for its
LUID and convert that from the GUID.
This commit uses the computed GUID that is placed in InterfaceName.
Diagnosed by Jason Donnenfeld. (Thanks!)
Log levels can now be specified with "[v1] " or "[v2] " substrings
that are then stripped and filtered at the final logger. This follows
our existing "[unexpected]" etc convention and doesn't require a
wholesale reworking of our logging at the moment.
cmd/tailscaled then gets a new --verbose=N flag to take a log level
that controls what gets logged to stderr (and thus systemd, syslog,
etc). Logtail is unaffected by --verbose.
This commit doesn't add annotations to any existing log prints. That
is in the next commit.
Updates #924
Updates #282
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
For now, the server will only send v6 configuration to mapversion 8 clients
as part of an early-adopter program, while we verify that the functionality
is robust.
Signed-off-by: David Anderson <danderson@tailscale.com>
In practice, we already provide IPv6 endpoint addresses via netcheck,
and that address is likely to match a local address anyway (i.e. no NAT66).
The comment at that piece of the code mentions needing to figure out a
good priority ordering, but that only applies to non-active-discovery
clients, who already don't do anything with IPv6 addresses.
Signed-off-by: David Anderson <danderson@tailscale.com>
Lazy wg configuration now triggers if a peer has only endpoint
addresses (/32 for IPv4, /128 for IPv6). Subnet routers still
trigger eager configuration to avoid the need for a CIDR match
in the hot packet path.
Signed-off-by: David Anderson <danderson@tailscale.com>
This caused some confusion in issue #460, since usually raw format
strings aren't printed directly. Hopefully by directly logging that
they are intended to be raw format strings, this will be more clear.
Rate limited format strings now look like:
[RATE LIMITED] format string "control: sendStatus: %s: %v"
Closes#460.
Signed-off-by: Smitty <me@smitop.com>
The previous code used a lot of whole-function variables and shared
behavior that only triggered based on prior action from a single codepath.
Instead of that, move the small amounts of "shared" code into each switch
case.
Signed-off-by: David Anderson <danderson@tailscale.com>
Before, tailscaled would log every 10 seconds when the periodic noteRecvActivity
call happens. This is noisy, but worse it's misleading, because the message
suggests that the disco code is starting a lazy config run for a missing peer,
whereas in fact it's just an internal piece of keepalive logic.
With this change, we still log when going from 0->1 tunnel for the peer, but
not every 10s thereafter.
Signed-off-by: David Anderson <danderson@tailscale.com>
Addresses #964
Still to be done:
- Figure out the correct logging lines in util/systemd
- Figure out if we need to slip the systemd.Status function anywhere
else
- Log util/systemd errors? (most of the errors are of the "you cannot do
anything about this, but it might be a bad idea to crash the program if
it errors" kind)
Assistance in getting this over the finish line would help a lot.
Signed-off-by: Christine Dodrill <me@christine.website>
util/systemd: rename the nonlinux file to appease the magic
Signed-off-by: Christine Dodrill <me@christine.website>
util/systemd: fix package name
Signed-off-by: Christine Dodrill <me@christine.website>
util/systemd: fix review feedback from @mdlayher
Signed-off-by: Christine Dodrill <me@christine.website>
cmd/tailscale{,d}: update depaware manifests
Signed-off-by: Christine Dodrill <me@christine.website>
util/systemd: use sync.Once instead of func init
Signed-off-by: Christine Dodrill <me@christine.website>
control/controlclient: minor review feedback fixes
Signed-off-by: Christine Dodrill <me@christine.website>
{control,ipn,systemd}: fix review feedback
Signed-off-by: Christine Dodrill <me@christine.website>
review feedback fixes
Signed-off-by: Christine Dodrill <me@christine.website>
ipn: fix sprintf call
Signed-off-by: Christine Dodrill <me@christine.website>
ipn: make staticcheck less sad
Signed-off-by: Christine Dodrill <me@christine.website>
ipn: print IP address in connected status
Signed-off-by: Christine Dodrill <me@christine.website>
ipn: review feedback
Signed-off-by: Christine Dodrill <me@christine.website>
final fixups
Signed-off-by: Christine Dodrill <me@christine.website>
Upgrading staticcheck upgraded golang.org/x/sync
(one downside of mixing our tools in with our regular go.mod),
which introduced a new dependency via
https://go-review.googlesource.com/c/sync/+/251677
That CL could and probably should be written without runtime/debug,
but it's not clear to me that that is better at this moment
than simply accepting the additional package as a dependency.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
These ignore built files that don't exist anymore, and just serve
to clutter up the .gitignore file. (I was initially confused when
I saw those lines, since I (correctly) thought that the only
Tailscale binaries were tailscale and tailscaled):
- taillogin was removed in d052586
- relaynode was removed in a56e853
Signed-off-by: Smitty <me@smitop.com>
This is a repeat of commit 3aa68cd397
which was lost in a rework of version.sh.
git worktrees have a .git file rather than a .git directory, so building
in a worktree caused version.sh to generate an error.
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
After mapver 5's incremental netmap updates & user profiles, much of
the remaining bandwidth for streamed MapResponses were redundant,
unchanged PacketFilters. So make MapRequest.Version 6 mean that nil
means unchanged from the previous value.
Noticed these in MapResponses to clients.
MachineAuthorized was set true, but once we fix the coordination server
to zero out that field, then it can be omittted.
Add content length hints to headers.
The server can use these hints to more efficiently select buffers.
Stop attempting to compress tiny requests.
The bandwidth savings are negligible (and sometimes negative!),
and it makes extra work for the server.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
It appears some users have corrupted pref.conf files. Have LoadPrefs
treat these files as non-existent. This way tailscale will make user
login, and not crash.
Fixes#954
Signed-off-by: Alex Brainman <alex.brainman@gmail.com>
The cloner tool adds static checks that the Clone methods are up to
date, so failing to update Clone causes a compiler error.
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
The cornerstone API is a more memory-efficient Unmarshal.
The savings come from re-using a json.Decoder.
BenchmarkUnmarshal-8 4016418 288 ns/op 8 B/op 1 allocs/op
BenchmarkStdUnmarshal-8 4189261 283 ns/op 184 B/op 2 allocs/op
It also includes a Bytes type to reduce allocations
when unmarshalling a non-hex-encoded JSON string into a []byte.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
likelyHomeRouterIPDarwinSyscall iterates through the list of routes,
looking for a private gateway, returning the first one it finds.
likelyHomeRouterIPDarwinExec does the same thing,
except that it returns the last one it finds.
As a result, when there are multiple gateways,
TestLikelyHomeRouterIPSyscallExec fails.
(At least, I think that that is what is happening;
I am going inferring from observed behavior.)
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The compiler is failing to draw the connection between
slice cap and slice len, so is missing some obvious BCE opportunities.
Give it a hint by making the cap equal to the length.
The generated code is smaller and cleaner, and a bit faster.
name old time/op new time/op delta
Decode/tcp4-8 12.2ns ± 1% 11.6ns ± 3% -5.31% (p=0.000 n=28+29)
Decode/tcp6-8 12.5ns ± 2% 11.9ns ± 2% -4.84% (p=0.000 n=30+30)
Decode/udp4-8 11.5ns ± 1% 11.1ns ± 1% -3.11% (p=0.000 n=25+24)
Decode/udp6-8 11.8ns ± 3% 11.4ns ± 1% -3.08% (p=0.000 n=30+26)
Decode/icmp4-8 11.0ns ± 3% 10.6ns ± 1% -3.38% (p=0.000 n=25+30)
Decode/icmp6-8 11.4ns ± 1% 11.1ns ± 2% -2.29% (p=0.000 n=27+30)
Decode/igmp-8 10.3ns ± 0% 10.0ns ± 1% -3.26% (p=0.000 n=19+23)
Decode/unknown-8 8.68ns ± 1% 8.38ns ± 1% -3.55% (p=0.000 n=28+29)
While the code was correct, I broke it during a refactoring and
tests didn't detect it. This fixes that glitch.
Signed-off-by: David Anderson <danderson@tailscale.com>
Doesn't materially affect benchmarks, but shrinks match6 by 30 instructions
and halves memory loads.
Part of #19.
Signed-off-by: David Anderson <danderson@tailscale.com>
Part of #19.
name old time/op new time/op delta
Filter/icmp4-8 32.2ns ± 3% 32.5ns ± 2% ~ (p=0.524 n=10+8)
Filter/icmp6-8 49.7ns ± 6% 43.1ns ± 4% -13.12% (p=0.000 n=9+10)
Signed-off-by: David Anderson <danderson@tailscale.com>
Cache DNS results of earlier login.tailscale.com control dials, and use
them for future dials if DNS is slow or broken.
Fixes various issues with trickier setups with the domain's DNS server
behind a subnet router.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
As documented in the README, tailscale only build with the latest Go
version (Go 1.15). As a result, a handful of undefined errors would pop
up using an older verison.
This patch updates the base image to 1.15, allowing "docker build"
to function correctly once more.
Signed-off-by: Sean Klein <seanmarionklein@gmail.com>
This fixes the problem where, while running `redo version-info.sh`, the
repo would always show up as dirty, because redo creates a temp file
named *.tmp. This caused the version code to always have a -dirty tag,
but not when you run version.sh by hand.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Instead of reverting to 0.0.0, keep the same version number (eg. 1.2.4)
but add an extra suffix with the change count,
eg. 1.2.4-6-tb35d95ad7-gcb8be72e6. This avoids the problem where a
small patch causes the code to report a totally different version to
the server, which might change its behaviour based on version code.
(The server might enable various bug workarounds since it thinks
0.0.0 is very old.)
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This option isn't available on slightly older versions of git. We were
no longer using the real describe functionality anyway, so let's just do
something simpler to detect a dirty worktree.
While we're here, fix up a little bit of sh style.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
These accidentally make the tag syntax more flexible than was intended,
which will create forward compatibility problems later. Let's go back
to the old stricter parser.
Revert "cmd/tailscale/cli: fix double tag: prefix in tailscale up"
Revert "cmd/tailscale/cli, tailcfg: allow tag without "tag:" prefix in 'tailscale up'"
This reverts commit a702921620.
This reverts commit cd07437ade.
Affects #861.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
The packet filter still rejects all IPv6, but decodes enough from v6
packets to do something smarter in a followup.
name time/op
Decode/tcp4-8 28.8ns ± 2%
Decode/tcp6-8 20.6ns ± 1%
Decode/udp4-8 28.2ns ± 1%
Decode/udp6-8 20.0ns ± 6%
Decode/icmp4-8 21.7ns ± 2%
Decode/icmp6-8 14.1ns ± 2%
Decode/unknown-8 9.43ns ± 2%
Signed-off-by: David Anderson <danderson@tailscale.com>
In 1.0, subnet relays were not specially handled when WPAD+PAC was
present on the network.
In 1.2, on Windows, subnet relays were disabled if WPAD+PAC was
present. That was what some users wanted, but not others.
This makes it configurable per domain, reverting back to the 1.0
default state of them not being special. Users who want that behavior
can then enable it.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
In tests, we force binding to localhost to avoid OS firewall warning
dialogs.
But for IPv6, we were trying (and failing) to bind to 127.0.0.1.
You'd think we'd just say "localhost", but that's apparently ill
defined. See
https://tools.ietf.org/html/draft-ietf-dnsop-let-localhost-be-localhost
and golang/go#22826. (It's bitten me in the past, but I can't
remember specific bugs.)
So use "::1" explicitly for "udp6", which makes the test quieter.
This change is to make JSONHandler error handling intuitive, as before there would be two sources of HTTP status code when HTTPErrors were generated: one as the first return value of the handler function, and one nested inside the HTTPError. Previously, it took the first return value as the status code, and ignored the code inside the HTTPError. Now, it should expect the first return value to be 0 if there is an error, and it takes the status code of the HTTPError to set as the response code.
Signed-off-by: Daniel Chung <daniel@tailscale.com>
The goal is to move some of the shenanigans we have elsewhere into the filter
package, so that all the weird things to do with poking at the filter is in
a single place, behind clean APIs.
Signed-off-by: David Anderson <danderson@tailscale.com>
We still use the packet.* alloc-free types in the data path, but
the compilation from netaddr to packet happens within the filter
package.
Signed-off-by: David Anderson <danderson@tailscale.com>
The output of `wc -l` on darwin starts with a tab:
git rev-list 266f6548611ad0de93e7470eb13731db819f184b..HEAD | wc -l
0
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
git worktrees have a .git file rather than a .git directory, so building
in a worktree caused version.sh to generate an error.
Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
Seeing "frontend-provided legacy machine key" was weird (and not quite
accurate) on Linux machines where it comes from the _daemon key's
persist prefs, not the "frontend".
Make the log message distinguish between the cases.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Otherwise log upload HTTP requests generate proxy errrors which
generate logs which generate HTTP requests which generate proxy
errors which generate more logs, etc.
Fixes#879
When the service was running without a client (e.g. after a reboot)
and then the owner logs in and the GUI attaches, the computed state
key changed to "" (driven by frontend prefs), and then it was falling
out of server mode, despite the GUI-provided prefs still saying it
wanted server mode.
Also add some logging. And remove a scary "Access denied" from a
user-visible error, making the two possible already-in-use error
messages consistent with each other.
On Windows, we were previously treating a server used by different
users as a fatal error, which meant the second user (upon starting
Tailscale, explicitly or via Start Up programs) got an invasive error
message dialog.
Instead, give it its own IPN state and change the Notify.ErrMessage to
be details in that state. Then the Windows GUI can be less aggresive
about that happening.
Also,
* wait to close the IPN connection until the server ownership state
changes so the GUI doesn't need to repeatedly reconnect to discover
changes.
* fix a bug discovered during testing: on system reboot, the
ipnserver's serverModeUser was getting cleared while the state
transitioned from Unknown to Running. Instead, track 'inServerMode'
explicitly and remove the old accessor method which was error prone.
* fix a rare bug where the client could start up and set the server
mode prefs in its Start call and we wouldn't persist that to the
StateStore storage's prefs start key. (Previously it was only via a
prefs toggle at runtime)
This makes it easier to integrate this version math into a submodule-ful
world. We'll continue to have regular git tags that parallel the information
in VERSION, so that builds out of this repository behave the same.
Signed-off-by: David Anderson <danderson@tailscale.com>
os.IsNotExist doesn't unwrap errors. errors.Is does.
The ioutil.ReadFile ones happened to be fine but I changed them so
we're consistent with the rule: if the error comes from os, you can
use os.IsNotExist, but from any other package, use errors.Is.
(errors.Is always would also work, but not worth updating all the code)
The motivation here was that we were logging about failure to migrate
legacy relay node prefs file on startup, even though the code tried
to avoid that.
See golang/go#41122
This lets servers using tsweb register expvars
that will track the number of requests ending
in 200s/300s/400s/500s.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Amazingly, there doesn't seem to be a documented way of updating network
configuration programmatically in a way that Windows takes notice of.
The naturopathic remedy for this is to invoke ipconfig /registerdns, which
does a variety of harmless things and also invokes the private API that
tells windows to notice new adapter settings. This makes our DNS config
changes stick within a few seconds of us setting them.
If we're invoking a shell command anyway, why futz with the registry at
all? Because netsh has no command for changing the DNS suffix list, and
its commands for setting resolvers requires parsing its output and
keeping track of which server is in what index. Amazingly, twiddling
the registry directly is the less painful option.
Fixes#853.
Signed-off-by: David Anderson <danderson@tailscale.com>
It was especially bad on our GUI platforms with a frontend that polls it.
No need to log it every few seconds if it's unchanged. Make it slightly
less allocate-y while I'm here.
It's still Windows-only for now but it's easy to de-Windows-ify when needed.
Moving it out of corp repo and into tailscale/tailscale so we can use
it in ipnserver.BabysitProc.
Updates #726
Updating the Windows firewall is usually reasonably fast, but
sometimes blocks for 20 seconds, 4 minutes, etc. Not sure why.
Until we understand that's happening, configure it in the background
without blocking the normal control flow.
Updates #785
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
If we can't find the mapping from SID ("user ID") -> username, don't
treat that as a fatal. Apparently that happens in the wild for Reasons.
Ignore it for now. It's just a nice-to-have for error messages in the
rare multi-user case.
Updates #869
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
When building with redo, also include the git commit hash
from the proprietary repo, so that we have a precise commit
that identifies all build info (including Go toolchain version).
Add a top-level build script demonstrating to downstream distros
how to burn the right information into builds.
Adjust `tailscale version` to print commit hashes when available.
Fixes#841.
Signed-off-by: David Anderson <danderson@tailscale.com>
TestMkversion requires UNIX shell to run mkversion.sh. No such shell
is present on Windows. Just skip the test.
Updates #50
Signed-off-by: Alex Brainman <alex.brainman@gmail.com>
Also replaces the IPv6Overlay bool with use of DebugFlags, since
it's currently an experimental configuration.
Signed-off-by: David Anderson <danderson@tailscale.com>
The RusagePrefixLog is rarely useful, hasn't been useful in a long
time, is rarely the measurement we need, and is pretty spammy (and
syscall-heavy). Disable it by default. We can enable it when we're
debugging memory.
Fix from regression in previous commit
(0e3048d8e0) that was caught by e2e
tests.
In that previous commit, the user's own profile was omitted from the
NetworkMap in the case where the user only had one node.
I was going to make support for this advertised from the client, but
turns out only "tailscale status" even uses the UserProfiles field and
fails gracefully (omits that field) if a user profile for a user is
missing, so I think we can just reuse the DeltaPeers field from the
client to ask the control server to also delta encode the user
profiles.
For the few users running 1.1.x (unstable) versions between DeltaPeers
support (1.1.82) and this (~1.1.541), they'll just sometimes have
missing names in "tailscale status --json" or "tailscale status --web"
(the only places the UserProfile is used).
The previous code read too explicitly like log.Printf("I am here1"),
log.Printf("I am here2"). It still is with this change, but prettier, and
less subject to code rearranging order.
We were creating the controlclient and starting the portpoll concurrently,
which frequently resulted in the first controlclient connection being canceled
by the firsdt portpoll result ~milliseconds later, resulting in another
HTTP request.
Instead, wait a bit for the first portpoll result so it's much less likely to
interrupt our controlclient connection.
Updates tailscale/corp#557
On startup, clients do a MapRequest with empty endpoints while they
learn the DERP map to discover the STUN servers they then query to
learn their endpoints.
Set MapRequest.ReadOnly on those initial queries to not broadcast the
empty endpoints out to peers. The read results will come a half second
later (or less).
Updates tailscale/corp#557
At startup the client doesn't yet have the DERP map so can't do STUN
queries against DERP servers, so it only knows it local interface
addresses, not its STUN-mapped addresses.
We were reporting the interface-local addresses to control, getting
the DERP map, and then immediately reporting the full set of
updates. That was an extra HTTP request to control, but worse: it was
an extra broadcast from control out to all the peers in the network.
Now, skip the initial update if there are no stun results and we don't
have a DERP map.
More work remains optimizing start-up requests/map updates, but this
is a start.
Updates tailscale/corp#557
There was a bug with the lazy wireguard config code where, if the
minimum set of peers to tell wireguard didn't change, we skipped
calling userspaceEngine.updateActivityMapsLocked which updated
the various data structures that matched incoming traffic to later
reconfigure the minimum config.
That meant if an idle peer restarted and changed discovery keys, we
skipped updating our maps of disco keys/IPs that would caused us to
lazily inflate the config for that peer later if/when it did send
traffic.
Use golang.zx2c4.com/wireguard/windows/tunnel/winipcfg
instead of github.com/tailscale/winipcfg-go package.
Updates #760
Signed-off-by: Alex Brainman <alex.brainman@gmail.com>
This partially (but not yet fully) migrates Windows to tailscaled's
StateStore storage system.
This adds a new bool Pref, ForceDaemon, defined as:
// ForceDaemon specifies whether a platform that normally
// operates in "client mode" (that is, requires an active user
// logged in with the GUI app running) should keep running after the
// GUI ends and/or the user logs out.
//
// The only current applicable platform is Windows. This
// forced Windows to go into "server mode" where Tailscale is
// running even with no users logged in. This might also be
// used for macOS in the future. This setting has no effect
// for Linux/etc, which always operate in daemon mode.
Then, when ForceDaemon becomes true, we now write use the StateStore
to track which user started it in server mode, and store their prefs
under that key.
The ipnserver validates the connections/identities and informs that
LocalBackend which userid is currently in charge.
The GUI can then enable/disable server mode at runtime, without using
the CLI.
But the "tailscale up" CLI was also fixed, so Windows users can use
authkeys or ACL tags, etc.
Updates #275
It was previously possible for two different Windows users to connect
to the IPN server at once, but it didn't really work. They mostly
stepped on each other's toes and caused chaos.
Now only one can control it, but it can be active for everybody else.
Necessary dependency step for Windows server/headless mode (#275)
While here, finish wiring up the HTTP status page on Windows, now that
all the dependent pieces are available.
Due to a copy/paste-o, we were monitoring address changes twice, and
not monitoring route changes at all.
Verified with 'tailscale debug --monitor' that this actually works now (while
running 'route add 10.3.0.0 mask 255.255.0.0 10.0.0.1' and 'route delete (same)'
back and forth in cmd.exe)
In practice route changes are accompanied by address changes and this
doesn't fix any known issues. I just noticed this while reading this
code again. But at least the code does what it was trying to do now.
Turns out for the particular error I was chasing, it actually returns
200 and zero data. But this code mirrors the same check in the map
poll, and is the right thing to do in the name of future debugging.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This function is only called in fake mode, which won't do anything more
with the packet after we respond to it anyway, so dropping it in the
prefilter is not necessary. And it's kinda semantically wrong: we did
not reject it, so telling the upper layer that it was rejected produces
an ugly error message.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
At some point faketun got implemented as a loopback (put a packet in
from wireguard, the same packet goes back to wireguard) which is not
useful. It's supposed to be an interface that just sinks all packets,
and then wgengine adds *only* and ICMP Echo responder as a layer on
top.
This caused extremely odd bugs on darwin, where the special case that
reinjects packets from local->local was filling the loopback channel
and creating an infinite loop (which became jammed since the reader and
writer were in the same goroutine).
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
If no interfaces are up, calm down and stop spamming so much. It was
noticed as especially bad on Windows, but probably was bad
everywhere. I just have the best network conditions testing on a
Windows VM.
Updates #604
This makes it easy to compact slices that contain duplicate elements
by sorting and then uniqing.
This is an alternative to constructing an intermediate map
and then extracting elements from it. It also provides
more control over equality than using a map key does.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
So previous routes aren't shadowing resources that the operating
system might need (Windows Domain Controller, DNS server, corp HTTP
proxy, WinHTTP fetching the PAC file itself, etc).
This effectively detects when we're transitioning from, say, public
wifi to corp wifi and makes Tailscale remove all its routes and stops
its TCP connections and tries connecting to everything anew.
Updates tailscale/corp#653
Not used for anything yet (except logging), but populate the current
proxy autoconfig PAC URL in Interfaces.State.
A future change will do things based on it.
Gracefully skips touching the v6 NAT table on systems that don't have
it, and doesn't configure IPv6 at all if IPv6 is globally disabled.
Signed-off-by: David Anderson <danderson@tailscale.com>
When the network link changes, existing UDP sockets fail immediately
and permanently on macOS.
The forwarder set up a single UDP conn and never changed it.
As a result, any time there was a network link change,
all forwarded DNS queries failed.
To fix this, create a new connection when send requests
fail because of network unreachability.
This change is darwin-only, although extended it to other platforms
should be straightforward.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
While we're here, parseQuery into a plain function.
This is helpful for fuzzing. (Which I did a bit of. Didn't find anything.)
And clean up a few minor things.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Part of unforking our winipcfg-go and using upstream (#760), move our
additions into our repo. (We might upstream them later if upstream has
interest)
Originally these were:
@apenwarr: "Add ifc.SyncAddresses() and SyncRoutes()."
609dcf2df5
@bradfitz: "winipcfg: make Interface.AddRoutes do as much as possible, return combined error"
e9f93d53f3
@bradfitz: "prevent unnecessary Interface.SyncAddresses work; normalize IPNets in deltaNets"
decb9ee8e1
Might fix it. I've spent too much time failing to reproduce the issue. This doesn't
seem to make it worse, though (it still runs for me), so I'll include this and
see if it helps others while I still work on a reliable way to reproduce it.
Updates tailscale/corp#474
Otherwise when PAC server is down, we log, and each log entry is a new
HTTP request (from logtail) and a new GetProxyForURL call, which again
logs, non-stop. This is also nicer to the WinHTTP service.
Then also hook up link change notifications to the cache to reset it
if there's a chance the network might work sooner.
We depend on DERP for NAT traversal now[0] so disabling it entirely can't
work.
What we'll do instead in the future is let people specify
alternate/additional DERP servers. And perhaps in the future we could
also add a pref for nodes to say when they expect to never need/want
to use DERP for data (but allow it for NAT traversal communication).
But this isn't the right pref and it doesn't work, so delete it.
Fixes#318
[0] https://tailscale.com/blog/how-nat-traversal-works/
This change is to restore /etc/resolv.conf after tailscale down is called. This is done by setting the dns.Manager before errors occur. Error collection is also added.
Fixes#723
DebugForceDisco was a development & safety knob during the the transition
to discovery. It's no longer needed.
Add MapRequest.ReadOnly to prevent clients needing to do two
peer-spamming MapRequest at start-up.
This only adds the field, not the use of the field. (The control server
needs to support it first.)
Updates tailscale/corp#557
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
There's often some useful piece of information in there not already
repeated in the internal error.
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
It's properly handled later in tsdns.NewMap anyway, but there's work
done in the meantime that can be skipped when a peer lacks a DNS name.
It's also more clear that it's okay for it to be blank.
* wgengine/router/router_linux.go: Switched `cidrDiff("addr")` and `cidrDiff("route")` order
Signed-off-by: Christina Wen <christina@tailscale.com>
Co-authored-by: Christina Wen <christina@tailscale.com>
Also remove rebinding logic from the windows router. Magicsock will
instead rebind based on link change signals.
Signed-off-by: David Anderson <danderson@tailscale.com>
I had to use
go get -u github.com/tailscale/depaware@e09ee10c18249e4bf198e66bbd47babcd502637a
to force it to the correct version; it kept selecting head~1.
Maybe because the branch is called main instead of master?
Maybe because of some delay?
Updates #654. See that issue for a discussion of why
this timeout reduces flakiness, and what next steps are.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
For now. Get it working again so it's not stuck on 0.98.
Subnet relay can come later.
Updates #451
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This will be used in a future change to do localhost connection
authentication. This lets us quickly map a localhost TCP connection to
a PID. (A future change will then map a pid to a user)
TODO: pull portlist's netstat code into this package. Then portlist
will be fast on Windows without requiring shelling out to netstat.exe.
LogHeap no longer logs to os.Stderr and instead uploads
the heap profile by means of an HTTP POST request to the
target URL endpoint.
While here, also ensured that an error from pprof.WriteHeapProfile
isn't ignored and will prevent the HTTP request from being made
if non-nil.
Signed-off-by: Emmanuel T Odeke <emmanuel@orijtech.com>
This Clone function knows how to clone any types
for which it has generated Clone methods.
This allows callers to efficiently clone
an inbound interface{} that might contain one of these types.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This was causing any type to be reported as found,
as long as there were any type decls at all. Oops.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
If you change a struct and don't re-run cloner,
your Cloner method might be inaccurate, leading to bad things.
To prevent this, write out the struct as it is at the moment that
cloner is caller, and attempt a conversion from that type.
If the struct gets changed in any way, this conversion will fail.
This will yield false positives: If you change a non-pointer field,
you will be forced to re-run cloner, even though the actual generated
code won't change. I think this is an acceptable cost: It is a minor
annoyance, which will prevent real bugs.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
The test's LocalBackend was not shut down (Shutdown both releases
resources and waits for its various goroutines to end). This should
fix the test race we were seeing. It definitely fixes the file
descriptor leak that preventing -race -count=500 from passing before.
We currently have a chickend-and-egg situation in some environments
where we can set up routes that WinHTTP's WPAD/PAC resolution service
needs to download the PAC file to evaluate GetProxyForURL, but the PAC
file is behind a route for which we need to call GetProxyForURL to
e.g. dial a DERP server.
As a short-term fix, just assume that the most recently returned proxy
is good enough for such situations.
Running tailscaled on my machine yields lots of entries like:
weird: missing {tcp 6060}
parsePortsNetstat is filtering out loopback addresses as uninteresting.
Then addProcesses is surprised to discover these listening ports,
which results in spurious logging.
Teach addProcesses to also ignore loopback addresses.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Start of making the IPN state machine react to link changes and down
its DNS & routes if necessary to unblock proxy resolution (e.g. for
transitioning from public to corp networks where the corp network has
mandatory proxies and WPAD PAC files that can't be resolved while
using the DNS/routes configured previously)
This change should be a no-op. Just some callback plumbing.
It turns out that otherwise we don't know what exactly was set.
Also remove the now unused RootDomain config option.
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
Previously, a type AAAA query would be answered with an A record
if only an IPv4 address was available. This is irrelevant for us
while we only use IPv4, but it will be a bug one day,
so it's worth being precise about semantics.
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
Rather than consider bigs jumps in last-received-from activity as a
signal to possibly reconfigure the set of wireguard peers to have
configured, instead just track the set of peers that are currently
excluded from the configuration. Easier to reason about.
Also adds a bit more logging.
This might fix an error we saw on a machine running a recent unstable
build:
2020-08-26 17:54:11.528033751 +0000 UTC: 8.6M/92.6M magicsock: [unexpected] lazy endpoint not created for [UcppE], d:42a770f678357249
2020-08-26 17:54:13.691305296 +0000 UTC: 8.7M/92.6M magicsock: DERP packet received from idle peer [UcppE]; created=false
2020-08-26 17:54:13.691383687 +0000 UTC: 8.7M/92.6M magicsock: DERP packet from unknown key: [UcppE]
If it does happen again, though, we'll have more logs.
Seems to break linux CI builder. Cannot reproduce locally,
so attempting a rollback.
This reverts commit cd7bc02ab1.
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
Without this, a freshly started ipn client will be stuck in the
"Starting" state until something triggers a call to RequestStatus.
Usually a UI does this, but until then we can sit in this state
until poked by an external event, as is evidenced by our e2e tests
locking up when DERP is attached.
(This only recently became a problem when we enabled lazy handshaking
everywhere, otherwise the wireugard tunnel creation would also
trigger a RequestStatus.)
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
Fixes regression from e415991256 that
only affected Windows users because Go only on Windows delegates x509
cert validation to the OS and Windows as unhappy with our "metacert"
lacking NotBefore and NotAfter.
Fixes#705
The previous approach modifies name in-place in the request slice to avoid an allocation.
This is incorrect: the question section of a DNS request
must be copied verbatim, without any such modification.
Software may rely on it (we rely on other resolvers doing it it in tsdns/forwarder).
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
It was lost during a copy from wgcfg.NewPresharedKey (which doesn't
clamp) instead of wgcfg.NewPrivateKey (which does).
Fortunately this was only use for discovery messages (not WireGuard)
and only for ephemeral process-lifetime keys.
* advertise server's DERP public key following its ServerHello
* have client look for that DEPR public key in the response
PeerCertificates
* let client advertise it's going into a "fast start" mode
if it finds it
* modify server to support that fast start mode, just not
sending the HTTP response header
Cuts down another round trip, bringing the latency of being able to
write our first DERP frame from SF to Bangalore from ~725ms
(3 RTT) to ~481ms (2 RTT: TCP and TLS).
Fixes#693
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
control/controlclient, wgengine/filter: extract parsePacketFilter to new constructor in wgengine/filter
Signed-off-by: chungdaniel <daniel@tailscale.com>
It just has a version number in it and it's not really needed.
Instead just return it as a normal Recv message type for those
that care (currently only tests).
Updates #150 (in that it shares the same goal: initial DERP latency)
Updates #199 (in that it removes some DERP versioning)
We're beginning to reference DERP region names in the admin UI, so it's
best to consolidate this information in our DERP map.
Signed-off-by: Ross Zurowski <ross@rosszurowski.com>
Consider:
Hard NAT (A) <---> Hard NAT w/ mapped port (B)
If A sends a packet to B's mapped port, A can disco ping B directly,
with low latency, without DERP.
But B couldn't establish a path back to A and needed to use DERP,
despite already logging about A's endpoint and adding a mapping to it
for other purposes (the wireguard conn.Endpoint lookup also needed
it).
This adds the tracking to discoEndpoint too so it'll be used for
finding a path back.
Fixestailscale/corp#556
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Strictly speaking, we don't know that it's a wireguard packet, just that
it doesn't look like a disco packet.
Signed-off-by: David Anderson <danderson@tailscale.com>
These aren't particularly performance critical,
but since I have an optimization pending for them,
it's worth having a corresponding benchmark.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
For example:
$ tailscale ping -h
USAGE
ping <hostname-or-IP>
FLAGS
-c 10 max number of pings to send
-stop-once-direct true stop once a direct path is established
-verbose false verbose output
$ tailscale ping mon.ts.tailscale.com
pong from monitoring (100.88.178.64) via DERP(sfo) in 65ms
pong from monitoring (100.88.178.64) via DERP(sfo) in 252ms
pong from monitoring (100.88.178.64) via [2604:a880:2:d1::36:d001]:41641 in 33ms
Fixes#661
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This benchmark is far from perfect: It mixes together
client and server. Still, it provides a starting point
for easy profiling.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
Also, bit of behavior change: on non-nil err but expired context,
don't reset the consecutive failure count. I don't think the old
behavior was intentional.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This will make it easier for a human to tell what
version is deployed, for (say) correlating line numbers
in profiles or panics to corresponding source code.
It'll also let us observe version changes in prometheus.
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
1) we weren't waking up a discoEndpoint that once existed and
went idle for 5 minutes and then got a disco message again.
2) userspaceEngine.noteReceiveActivity had a buggy check; fixed
and added a test
This removes the atomic bool that tried to track whether we needed to acquire
the lock on a future recursive call back into magicsock. Unfortunately that
hack doesn't work because we also had a lock ordering issue between magicsock
and userspaceEngine (see issue). This documents that too.
Fixes#644
iOS doesn't let you run subprocesses,
which means we can't use netstat to get routing information.
Instead, use syscalls and grub around in the results.
We keep the old netstat version around,
both for use in non-cgo builds,
and for use testing the syscall-based version.
Note that iOS doesn't ship route.h,
so we include a copy here from the macOS 10.15 SDK
(which is itself unchanged from the 10.14 SDK).
I have tested manually that this yields the correct
gateway IP address on my own macOS and iOS devices.
More coverage would be most welcome.
Signed-off-by: Josh Bleecher Snyder <josharian@gmail.com>
If a node is behind a hard NAT and is using an explicit local port
number, assume they might've mapped a port and add their public IPv4
address with the local tailscaled's port number as a candidate endpoint.
NetworkMap text diffs being empty were currently used to short-circuit
calling magicsock's SetNetworkMap (via Engine.SetNetworkMap), but that
went away in c7582dc2 (0.100.0-230)
Prior to c7582dc2 (notably, in 0.100.0-225 and below, down to
0.100.0), a change in only disco key (as when a node restarts) but
without endpoint changes (as would happen for a client not behind a
NAT with random ports) could result in a "netmap diff: (none)" being
printed, as well as Engine.SetNetworkMap being skipped, leading to
broken discovery endpoints.
c7582dc2 fixed the Engine.SetNetworkMap skippage.
This change fixes the "netmap diff: (none)" print so we'll actually see when a peer
restarts with identical endpoints but a new discovery key.
SIGPIPE can be generated when CLIs disconnect from tailscaled. This
should not terminate the process.
Signed-off-by: David Anderson <danderson@tailscale.com>
tailscaled receives a SIGPIPE when CLIs disconnect from it. We shouldn't
shut down in that case.
This reverts commit 43b271cb26.
Signed-off-by: David Anderson <danderson@tailscale.com>
ORder of operations to trigger a problem:
- Start an already authed tailscaled, verify you can ping stuff.
- Run `tailscale up`. Notice you can no longer ping stuff.
The problem is that `tailscale up` stops the IPN state machine before
restarting it, which zeros out the packet filter but _not_ the packet
filter hash. Then, upon restarting IPN, the uncleared hash incorrectly
makes the code conclude that the filter doesn't need updating, and so
we stay with a zero filter (reject everything) for ever.
The fix is simply to update the filterHash correctly in all cases,
so that running -> stopped -> running correctly changes the filter
at every transition.
Signed-off-by: David Anderson <danderson@tailscale.com>
A comparison operator was backwards.
The bad case went:
* device A send packet to B at t=1s
* B gets added to A's wireguard config
* B gets packet
(5 minutes pass)
* some other activity happens, causing B to expire
to be removed from A's network map, since it's
been over 5 minutes since sent or received activity
* device A sends packet to B at t=5m1s
* normally, B would get added back, but the old send
time was not zero (we sent earlier!) and the time
comparison was backwards, so we never regenerated
the wireguard config.
This also refactors the code for legibility and moves constants up
top, with comments.
It appears that systemd has sensible defaults for limiting
crash loops:
DefaultStartLimitIntervalSec=10s
DefaultStartLimitBurst=5
Remove our insta-restart configuration so that it works.
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
f81233524f changed a use of package 'path' to 'filepath'.
Restore it back to 'path', with a comment.
Also, use the os.Executable-based fallback name in the case where the
binary itself doesn't have Go module information. That was overlooked in
the original code.
What I was probably actually hitting was exe caching issues where the
binary was updated on a SMB shared drive and I tried to run it with
the GUI exe still open, so Windows blends the two pages together and
causes all sorts of random corruption. I didn't know about that at the time.
Now, just call tryFixLogStateLocation unconditionally. The func itself will
bail out early on non-applicable OSes. (And rearrange it to return even a bit
earlier.)
We need to emit Prefs when it *has* changed, not when it hasn't.
Test is added in our e2e test, separately.
Fixes: #620
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
We were using the Go 'path' module, which apparently doesn't handle
backslashes correctly. path/filepath does.
However, the main bug turned out to be that we were not calling .Base()
on the path if version.ReadExe() fails, which it seems to do at least
on Windows 7. As a result, our logfile persistence was not working on
Windows, and logids would be regenerated on every restart.
Affects: #620
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
So a backend in server-an-error state (as used by Windows) can try to
create a new Engine again each time somebody re-connects, relaunching
the GUI app.
(The proper fix is actually fixing Windows issues, but this makes things better
in the short term)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The OS (tries) to send these but we drop them. No need to worry the
user with spam that we're dropping it.
Fixes#402
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
Starting with fe68841dc7, some e2e tests
got flaky. Rather than debug them (they're gnarly), just revert to the old
behavior as far as those tests are concerned. The tests were somehow
using magicsock without a private key and expecting it to do ... something.
My goal with fe68841dc7 was to stop log spam
and unnecessary work I saw on the iOS app when when stopping the app.
Instead, only stop doing that work on any transition from
once-had-a-private-key to no-longer-have-a-private-key. That fixes
what I wanted to fix while still making the mysterious e2e tests
happy.
There is a race in natlab where we might start shutdown while natlab is still running
a goroutine or two to deliver packets. This adds a small grace period to try and receive
it before continuing shutdown.
Signed-off-by: David Anderson <danderson@tailscale.com>
The first packet to transit may take several seconds to do so, because
setup rates in wgengine may result in the initial WireGuard handshake
init to get dropped. So, we have to wait at least long enough for a
retransmit to correct the fault.
Signed-off-by: David Anderson <danderson@tailscale.com>
Active discovery lets us introspect the state of the network stack precisely
enough that it's unnecessary, and dropping the initial DERP packets greatly
slows down tests. Additionally, it's unrealistic since our production network
will never deliver _only_ discovery packets, it'll be all or nothing.
Signed-off-by: David Anderson <danderson@tailscale.com>
Uses natlab only, because the point of this active discovery test is going to be
that it should get through a lot of obstacles.
Signed-off-by: David Anderson <danderson@tailscale.com>
LANs are authoritative for their prefixes, so we should not bounce
packets back and forth to the default gateway in that case.
Signed-off-by: David Anderson <danderson@tailscale.com>
The deadlock was:
* Conn.Close was called, which acquired c.mu
* Then this goroutine scheduled:
if firstDerp {
startGate = c.derpStarted
go func() {
dc.Connect(ctx)
close(c.derpStarted)
}()
}
* The getRegion hook for that derphttp.Client then ran, which also
tries to acquire c.mu.
This change makes that hook first see if we're already in a closing
state and then it can pretend that region doesn't exist.
wireguard-go uses 3 goroutines per peer (with reasonably large stacks
& buffers).
Rather than tell wireguard-go about all our peers, only tell it about
peers we're actively communicating with. That means we need hooks into
magicsock's packet receiving path and tstun's packet sending path to
lazily create a wireguard peer on demand from the network map.
This frees up lots of memory for iOS (where we have almost nothing
left for larger domains with many users).
We should ideally do this in wireguard-go itself one day, but that'd
be a pretty big change.
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
sync.Pools should almost always be packate globals, even though in this
case we only have exactly 1 TUN device anyway, so it matters less.
Still, it's unusual to see a Pool that's not a package global, so move it.
We originally picked those numbers somewhat at random, but with the idea
that 8 is a traditionally lucky number in Chinese culture. Unfortunately,
"88" is also neo-nazi shorthand language.
Use 52 instead, because those are the digits above the letters
"TS" (tailscale) on a qwerty keyboard, so we're unlikely to collide with
other users. 5, 2 and 52 are also pleasantly culturally meaningless.
Signed-off-by: David Anderson <danderson@tailscale.com>
This prevents hostname being forced to os.Hostname despite override
when control is contacted for the first time after starting tailscaled.
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
Nameserver IP 10.11.12.13 would otherwise get written to resolv.conf as 13.12.11.10, as was happening on my client.
Signed-off-by: Eduardo Kienetz <eduardo@kienetz.com>
Before this patch, the 250ms sleep would not be interrupted by context cancellation,
which would result in the goroutine sometimes lingering in tests (100ms grace period).
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
Very rarely, cancellation occurs between a successful send on derpRecvCh
and a call to copyBuf on the receiving side.
Without this patch, this situation results in <-copyBuf blocking indefinitely.
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
Peers advertising a discovery key know how to speak the discovery
protocol and do their own heartbeats to get through NATs and keep NATs
open. No need for the pinger except for with legacy peers.
The new interface lets implementors more precisely distinguish
local traffic from forwarded traffic, and applies different
forwarding logic within Machines for each type. This allows
Machines to be packet forwarders, which didn't quite work
with the implementation of Inject.
Signed-off-by: David Anderson <danderson@tailscale.com>
This code is currently racy due to an incorrect assumption
that goal is never modified in-place, so does not require extra locking.
This change makes the assumption correct.
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
This log line looks buggy, even though lacking a filter is expected during bringup.
We already know if we forget to SetFilter: it breaks the magicsock test,
so no useful information is lost.
Resolves#559.
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
The StartLoginInteractive command is for delegating the sign-in flow
to a browser. The Android Gooogle Sign-In SDK inverts the flow by
giving the client ID tokens.
Add a new backend command for accepting such tokens by exposing the existing
controlclient.Client.Login support for OAuth2 tokens. Introduce a custom
TokenType to distinguish ID tokens from other OAuth2 tokens.
Signed-off-by: Elias Naur <mail@eliasnaur.com>
The test demonstrates that magicsock can traverse two stateful
firewalls facing each other, that each require localhost to
initiate connections.
Signed-off-by: David Anderson <danderson@tailscale.com>
HandlePacket and Inject now receive/take Packets. This is a handy
container for the packet, and the attached Trace method can be used
to print traces from custom packet handlers that integrate nicely
with natlab's internal traces.
Signed-off-by: David Anderson <danderson@tailscale.com>
The firewall provides a ProcessPacket handler, and implements an
address-and-port endpoint dependent firewall that allows all
traffic to egress from the trusted interface, and only allows
inbound traffic if corresponding outbound traffic was previously
seen.
Signed-off-by: David Anderson <danderson@tailscale.com>
Requires a bunch of refactoring so that Networks only ever
refer to Interfaces that have been attached to them, and
Interfaces know about both their Network and Machine.
Signed-off-by: David Anderson <danderson@tailscale.com>
I added them earlier while fighting our redo+xcode build which wasn't
picking up these files on incremental builds. It still isn't, but now I've
verified with full builds that no quotes is correct.
We want the macOS Network Extension to share fate with the UI frontend,
so we need the backend to know when the frontend disappears.
One easy way to do that is to reuse the existing TCP server it's
already running (for tailscale status clietns).
We now tell the frontend our ephemeral TCP port number, and then have
the UI connect to it, so the backend can know when it disappears.
There are likely Swift ways of doing this, but I couldn't find them
quickly enough, so I reached for the hammer I knew.
Our primary version format is git describe --long --abbrev=9.
Our Apple scheme is:
(major+100).minor.(patch*10,000+gitDescribeCommits).
This CL gets rid of the third, which was:
major.minor.(patch*10,000+gitDescribeCommits).
Now the "About" box in the macOS app shows the same version that we
show on pkgs.tailscale.com, userz, changelog, etc.
This will be more important once/if we get standalone DMG downloads
for macOS on pkgs.tailscale.com.
Fixestailscale/corp#364
This change adds to tsdns the ability to delegate lookups to upstream nameservers.
This is crucial for setting Magic DNS as the system resolver.
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
Never return "nil, nil" anymore. The caller expected a usable
interface now. I missed some of these earlier.
Also, handle address deletion now.
Updates #532
At least the Apple Airport Extreme doesn't allow hairpin
sends from a private socket until it's seen traffic from
that src IP:port to something else out on the internet.
See https://github.com/tailscale/tailscale/issues/188#issuecomment-600728643
And it seems that even sending to a likely-filtered RFC 5737
documentation-only IPv4 range is enough to set up the mapping.
So do that for now. In the future we might want to classify networks
that do and don't require this separately. But for now help it.
I've confirmed that this is enough to fix the hairpin check on Avery's
home network, even using the RFC 5737 IP.
Fixes#188
There's a lot of confusion around what tailscale status shows, so make it better:
show region names, last write time, and put stars around DERP too if active.
Now stars are always present if activity, and always somewhere.
* fix tailscale status for peers using discovery
* as part of that, pull out disco address selection into reusable
and testable discoEndpoint.addrForSendLocked
* truncate ping/pong logged hex txids in half to eliminate noise
* move a bunch of random time constants into named constants
with docs
* track a history of per-endpoint pong replies for future use &
status display
* add "send" and " got" prefix to discovery message logging
immediately before the frame type so it's easier to read than
searching for the "<-" or "->" arrows earlier in the line; but keep
those as the more reasily machine readable part for later.
Updates #483
This is a prelude to adding more fields, which would otherwise
become more unnamed function params.
Signed-off-by: David Anderson <danderson@tailscale.com>
It's just a config wrapper that passes "use less memory at the
expense of compression" parameters by default, so that we don't
accidentally construct resource-hungry (de)compressors.
Also includes a benchmark that measures the memory cost of the
small variants vs. the stock variants. The savings are significant
on both compressors (~8x less memory) and decompressors (~1.4x less,
not including the savings from the significantly smaller
window on the compression side - with those savings included it's
more like ~140x smaller).
BenchmarkSmallEncoder-8 56174 19354 ns/op 31 B/op 0 allocs/op
BenchmarkSmallEncoderWithBuild-8 2900 382940 ns/op 1746547 B/op 36 allocs/op
BenchmarkStockEncoder-8 48921 25761 ns/op 286 B/op 0 allocs/op
BenchmarkStockEncoderWithBuild-8 426 2630241 ns/op 13843842 B/op 124 allocs/op
BenchmarkSmallDecoder-8 123814 9344 ns/op 0 B/op 0 allocs/op
BenchmarkSmallDecoderWithBuild-8 41547 27455 ns/op 27694 B/op 31 allocs/op
BenchmarkStockDecoder-8 129832 9417 ns/op 1 B/op 0 allocs/op
BenchmarkStockDecoderWithBuild-8 25561 51751 ns/op 39607 B/op 92 allocs/op
Signed-off-by: David Anderson <danderson@tailscale.com>
Update the mapping from ip:port to discokey, so when we retrieve a
packet from the network, we can find the same conn.Endpoint that we
gave to wireguard-go previously, without making it think we've
roamed. (We did, but we're not using its roaming.)
Updates #483
Ping messages now go out somewhat regularly, pong replies are sent,
and pong replies are now partially handled enough to upgrade off DERP
to LAN.
CallMeMaybe packets are sent & received over DERP, but aren't yet
handled. That's next (and regular maintenance timers), and then WAN
should work.
Updates #483
Starting at yesterday's e96f22e560 (convering some UDPAddrs to
IPPorts), Conn.ReceiveIPv4 could return a nil addr, which would make
its way through wireguard-go and blow up later. The DERP read path
wasn't initializing the addr result parameter any more, and wgRecvAddr
wasn't checking it either.
Fixes#515
And while plumbing, a bit of discovery work I'll need: the
endpointOfAddr map to map from validated paths to the discoEndpoint.
Not being populated yet.
Updates #483
This adds a new magicsock endpoint type only used when both sides
support discovery (that is, are advertising a discovery
key). Otherwise the old code is used.
So far the new code only communicates over DERP as proof that the new
code paths are wired up. None of the actually discovery messaging is
implemented yet.
Support for discovery (generating and advertising a key) are still
behind an environment variable for now.
Updates #483
The new deepprint package just walks a Go data structure and writes to
an io.Writer. It's not pretty like go-spew, etc.
We then use it to replace the use of UAPI (which we have a TODO to
remove) to generate signatures of data structures to detect whether
anything changed (without retaining the old copy).
This was necessary because the UAPI conversion ends up trying to do
DNS lookups which an upcoming change depends on not happening.
And track known peers.
Doesn't yet do anything with the messages. (nor does it send any yet)
Start of docs on the message format. More will come in subsequent changes.
Updates #483
The NetworkExtension brings up the interface itself and does not have
access to `ifconfig`, which the underlying BSD userspace router attempts
to use when Up is called.
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
If there's been 5 minutes of inactivity, stop doing STUN lookups. That
means NAT mappings will expire, but they can resume later when there's
activity again.
We'll do this for all platforms later.
Updates tailscale/corp#320
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
As part of disabling background STUN packets when idle, we want an
emergency override switch to turn it back on, in case it interacts
poorly in the wild. We'll send that via control, but we'll want to
plumb it down to magicsock via NetworkMap.
Updates tailscale/corp#320
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
For various reasons (mostly during rollouts or config changes on our
side), nodes may end up connecting to a fallback DERP node in a
region, rather than the primary one we tell them about in the DERP
map.
Connecting to the "wrong" node is fine, but it's in our best interest
for all nodes in a domain to connect to the same node, to reduce
intra-region packet forwarding.
This adds a privileged frame type used by the control system that can
kick off a client connection when they're connected to the wrong node
in a region. Then they hopefully reconnect immediately to the correct
location. (If not, we can leave them alone and stop closing them.)
Updates tailscale/corp#372
The remove hook implementation was copy/pasted from the line above and
I didn't change the body, resulting in packet forwarding routes never
being removed.
Fortunately we weren't using this path yet, but it led to stats being
off, and (very) slow memory growth.
Darwin and FreeBSD are compatible enough to share the userspace router.
The OSX router delegates to the BSD userspace router unless `SetRoutesFunc` is set.
That preserves the mechanism that allows `ipn-go-bridge` to specify its own routing behavior.
Fixes#177
Signed-off-by: Reinaldo de Souza <github@rei.nal.do>
Later we'll want to use the presence of a discovery key as a signal
that the node knows how to participate in discovery. Currently the
code generates keys and sends them to the control server but doesn't
do anything with them, which is a bad state to stay in lest we release
this code and end up with nodes in the future that look like they're
functional with the new discovery protocol but aren't.
So for now, make this opt-in as a debug option for now, until the rest
of it is in.
Updates #483
The magicsock derpReader was holding onto 65KB for each DERP
connection forever, just in case.
Make the derp{,http}.Client be in charge of memory instead. It can
reuse its bufio.Reader buffer space.
- Reuse IP length constants from net package.
- Remove beu16 to make endianness functions consistent.
Signed-off-by: Quoc-Viet Nguyen <afelion@gmail.com>
It existed previously to persuade Go that redo-ful directory was
a Go package prior to the first build. But now we have other Go
files in the directory that will fulfil that function.
Signed-off-by: David Anderson <danderson@tailscale.com>
macOS incorrectly sends packets for the local Tailscale IP
into our tunnel interface. We have to turn the packets around
and send them back to the kernel.
Fixestailscale/corp#189.
Signed-off-by: David Anderson <danderson@tailscale.com>
... it was crashing for some reason, running out of stack while
loading a DLL in goversion. I don't understand Windows (or the Go
runtime for Windows) enough to know why that'd be problematic in that
context.
In any case, don't call it, as tryFixLogStateLocation does nothing on
Windows anyway.
tryFixLogStateLocation should probably just call version.CmdName
itself if/when it needs to, after the GOOS check.
We want to run bo.Backoff() after every upload, regardless. If
upload==true but err!=nil, we weren't backing off, which caused some
very-high-throughput log upload retries in bad network conditions.
Updates #282.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
(The NewMeshClient constructor I added recently was gross in
retrospect at call sites, especially when it wasn't obvious that a
meshKey empty string meant a regular client)
iproute2 3.16.0-2 from Debian Jessie (oldoldstable) doesn't return
exit code 2 when deleting a non-existent IP rule.
Fixes#434
Signed-off-by: David Anderson <danderson@tailscale.com>
This lets a trusted DERP client that knows a pre-shared key subscribe
to the connection list. Upon subscribing, they get the current set
of connected public keys, and then all changes over time.
This lets a set of DERP server peers within a region all stay connected to
each other and know which clients are connected to which nodes.
Updates #388
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
The flags were --no-blah for a brief time, then we switched them to
--blah=true/false with a default of true, but didn't fix the boolean
inversions in the code. So up was down, true was false, etc.
Signed-off-by: David Anderson <danderson@tailscale.com>
We have a filter in tailscaled itself now, which is more robust
against weird network topologies (such as the one Docker creates).
Signed-off-by: David Anderson <danderson@tailscale.com>
The zstd library treats that limit as a hard cap on decompressed
size, in the mode we're using it, rather than a window size.
Signed-off-by: David Anderson <danderson@tailscale.com>
Overriding the hostname is required for Android, where os.Hostname
is often just "localhost".
Updates #409
Signed-off-by: Elias Naur <mail@eliasnaur.com>
It'll be called a bunch, so worth a bit of effort. Could go further, but not yet.
(really, should hook into wgengine/monitor and only re-read on netlink changes?)
name old time/op new time/op delta
DefaultRouteInterface-8 60.8µs ±11% 44.6µs ± 5% -26.65% (p=0.000 n=20+19)
name old alloc/op new alloc/op delta
DefaultRouteInterface-8 3.29kB ± 0% 0.55kB ± 0% -83.21% (p=0.000 n=20+20)
name old allocs/op new allocs/op delta
DefaultRouteInterface-8 9.00 ± 0% 6.00 ± 0% -33.33% (p=0.000 n=20+20)
We'll use SO_BINDTODEVICE instead of fancy policy routing. This has
some limitations: for example, we will route all traffic through the
interface that has the main "default" (0.0.0.0/0) route, so machines
that have multiple physical interfaces might have to go through DERP to
get to some peers. But machines with multiple physical interfaces are
very likely to have policy routing (ip rule) support anyway.
So far, the only OS I know of that needs this feature is ChromeOS
(crostini). Fixes#245.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
* 'master' of github.com:tailscale/tailscale:
tailcfg: remove unused, unimplemented DERPNode.CertFingerprint for now
net/netns: also don't err on tailscaled -fake as a regular user
net/netcheck: fix HTTPS fallback bug from earlier today
net/netns: don't return an error if we're not root and running the tailscale binary
Otherwise iOS/macOS will reconfigure their routing every time anything
minor changes in the netmap (in particular, endpoints and DERP homes),
which is way too often.
Some users reported "network reconfigured" errors from Chrome when this
happens.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
My earlier 3fa58303d0 tried to implement
the net/http.Tranhsport.DialTLSContext hook, but I didn't return a
*tls.Conn, so we ended up sending a plaintext HTTP request to an HTTPS
port. The response ended up being Go telling as such, not the
/derp/latency-check handler's response (which is currently still a
404). But we didn't even get the 404.
This happened to work well enough because Go's built-in error response
was still a valid HTTP response that we can measure for timing
purposes, but it's not a great answer. Notably, it means we wouldn't
be able to get a future handler to run server-side and count those
latency requests.
tailscale netcheck was broken otherwise.
We can fix this a better way later; I'm just fixing a regression in
some way because I'm trying to work on netcheck at the moment.
This allows tailscaled's own traffic to bypass Tailscale-managed routes,
so that things like tailscale-provided default routes don't break
tailscaled itself.
Progress on #144.
Signed-off-by: David Anderson <danderson@tailscale.com>
We canceled the pingers in Close, but didn't wait around for their
goroutines to be cleaned up. This caused the ipn/e2e_test to catch
pingers in its resource leak check.
This commit introduces an object, but also simplifies the semantics
around the pinger's cancel functions. They no longer need to be called
while holding the mutex.
Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
Also:
* add -verbose flag to cmd/tailscale netcheck
* remove some API from the interfaces package
* convert some of the interfaces package to netaddr.IP
* don't even send IPv4 probes on machines with no IPv4 (or only v4
loopback)
* and once three regions have replied, stop waiting for other probes
at 2x the slowest duration.
Updates #376
Specifically, this sequence:
iptables -N ts-forward
iptables -A ts-forward -m mark --mark 0x10000 -j ACCEPT
iptables -A FORWARD -j ts-forward
doesn't work on Debian-9-using-nftables, but this sequence:
iptables -N ts-forward
iptables -A FORWARD -j ts-forward
iptables -A ts-forward -m mark --mark 0x10000 -j ACCEPT
does work.
I'm sure the reason why is totally fascinating, but it's an old version
of iptables and the bug doesn't seem to exist on modern nftables, so
let's refactor our code to add rules in the always-safe order and
pretend this never happened.
Fixes#401.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
On startup, and when switching into =off and =nodivert, we were
deleting netfilter rules even if we weren't the ones that added them.
In order to avoid interfering with rules added by the sysadmin, we have
to be sure to delete rules only in the case that we added them in the
first place.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Instead of retrieving the list of chains, or the list of rules in a
chain, just try deleting the ones we don't want and then adding the
ones we do want. An error in flushing/deleting still means the rule
doesn't exist anymore, so there was no need to check for it first.
This avoids the need to parse iptables output, which avoids the need to
ever call iptables -S, which fixes#403, among other things. It's also
much more future proof in case the iptables command line changes.
Unfortunately the iptables go module doesn't properly pass the iptables
command exit code back up when doing .Delete(), so we can't correctly
check the exit code there. (exit code 1 really means the rule didn't
exist, rather than some other weird problem).
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This removes the use of suppress_ifgroup and fwmark "x/y" notation,
which are, among other things, not available in busybox and centos6.
We also use the return codes from the 'ip' program instead of trying to
parse its output.
I also had to remove the previous hack that routed all of 100.64.0.0/10
by default, because that would add the /10 route into the 'main' route
table instead of the new table 88, which is no good. It was a terrible
hack anyway; if we wanted to capture that route, we should have
captured it explicitly as a subnet route, not as part of the addr. Note
however that this change affects all platforms, so hopefully there
won't be any surprises elsewhere.
Fixes#405
Updates #320, #144
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Let's actually list the file we checked
(/proc/sys/net/ipv4/ip_forward). That gives the admin something
specific to look for when they get this message.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
We would print a message about "nothing more to do", which some people
thought was an error or warning. Let's only print a message after
authenticating if we previously asked for interaction, and let's
shorten that message to just "Success," which is what it means.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Under some conditions, code would try to look things up in the maps
before the first call to updateLatency. I don't see any reason to delay
initialization of the maps, so let's just init them right away when
creating the Report instance.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
It can only be built with corp deps anyway, and having it split
from the control code makes our lives harder.
Signed-off-by: David Anderson <danderson@tailscale.com>
... and thus does not need to worry about when it escapes into
unprovable fmt interface{} land.
Also, add some convenience methods for efficiently writing integers.
Instead of hard-coding the DERP map (except for cmd/tailscale netcheck
for now), get it from the control server at runtime.
And make the DERP map support multiple nodes per region with clients
picking the first one that's available. (The server will balance the
order presented to clients for load balancing)
This deletes the stunner package, merging it into the netcheck package
instead, to minimize all the config hooks that would've been
required.
Also fix some test flakes & races.
Fixes#387 (Don't hard-code the DERP map)
Updates #388 (Add DERP region support)
Fixes#399 (wgengine: flaky tests)
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
- Reformat the warning about a message being rate limited to print the
format string, rather than the formatted message. This helps give a
clue what "type" of message is being limited.
- Change the rate limit warning to be [RATE LIMITED] in all caps. This
uses less space on each line, plus is more noticeable.
- In tailscaled, change the frequency to be less often (once every 5
seconds per format string) but to allow bursts of up to 5 messages.
This greatly reduces the number of messages that are rate limited
during startup, but allows us to tighten the limit even further during
normal runtime.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This cuts RSS from ~30MB to ~20MB on my machine, after the previous fix
to get rid of unnecessary zstd buffers.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
The compressed blobs we send back and forth are small and infrequent,
which doesn't justify the 8MB * GOMAXPROCS memory that was being
allocated. This was the overwhelming majority of memory use in
tailscaled. On my system it goes from ~100M RSS to ~15M RSS (which is
still suspiciously high, but we can worry about that more later).
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This could happen when a process disappeared while we were reading its
file descriptor list.
I was able to replicate the problem by running this in another
terminal:
while :; do for i in $(seq 10); do
/bin/true & done >&/dev/null; wait >&/dev/null;
done
And then running the portlist tests thousands of times.
Fixes#339.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Also stop logging data sent/received from nodes we're not connected to (ie all those `x`s being logged in the `peers: ` line)
Signed-off-by: Wendi <wendi.yu@yahoo.ca>
The comment module is compiled out on several embedded systems (and
also gentoo, because netfilter can't go brrrr with comments holding it
back). Attempting to use comments results in a confusing error, and a
non-functional firewall.
Additionally, make the legacy rule cleanup non-fatal, because we *do*
have to probe for the existence of these -m comment rules, and doing
so will error out on these systems.
Signed-off-by: David Anderson <danderson@tailscale.com>
By default, nothing differentiates errors or fatals from regular logs, so they just
blend into the rest of the logs.
As a bonus, if you run a test using t.Run(), the log messages printed
via the sub-t.Run() are printed at a different time from log messages
printed via the parent t.Run(), making debugging almost impossible.
This doesn't actually fix the test flake I'm looking for, but at least
I can find it in the logs now.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Our new build scripts try to build ipn-go-bridge on more than just
linux and darwin, so let's enable this file so it can be successful on
every platform.
We don't want those extra dependencies on iOS, at least yet.
Especially since there's no way to set the relevant environment
variables so it's just bloat with no benefits. Perhaps we'll need to
do SOCKS on iOS later, but probably differently if/when so.
Updates #227
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This didn't catch anything yet, but it's good practice for detecting
goroutine leaks that we might not find otherwise.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
If a test calls log.Printf, 'go test' horrifyingly rearranges the
output to no longer be in chronological order, which makes debugging
virtually impossible. Let's stop that from happening by making
log.Printf panic if called from any module, no matter how deep, during
tests.
This required us to change the default error handler in at least one
http.Server, as well as plumbing a bunch of logf functions around,
especially in magicsock and wgengine, but also in logtail and backoff.
To add insult to injury, 'go test' also rearranges the output when a
parent test has multiple sub-tests (all the sub-test's t.Logf is always
printed after all the parent tests t.Logf), so we need to screw around
with a special Logf that can point at the "current" t (current_t.Logf)
in some places. Probably our entire way of using subtests is wrong,
since 'go test' would probably like to run them all in parallel if you
called t.Parallel(), but it definitely can't because the're all
manipulating the shared state created by the parent test. They should
probably all be separate toplevel tests instead, with common
setup/teardown logic. But that's a job for another time.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Inclusion of the word "assert" made it seem like a failure, even though
it was supposed to be identifying the name of the function (Assert()).
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Right now, filtering and packet injection in wgengine depend
on a patch to wireguard-go that probably isn't suitable for upstreaming.
This need not be the case: wireguard-go/tun.Device is an interface.
For example, faketun.go implements it to mock a TUN device for testing.
This patch implements the same interface to provide filtering
and packet injection at the tunnel device level,
at which point the wireguard-go patch should no longer be necessary.
This patch has the following performance impact on i7-7500U @ 2.70GHz,
tested in the following namespace configuration:
┌────────────────┐ ┌─────────────────────────────────┐ ┌────────────────┐
│ $ns1 │ │ $ns0 │ │ $ns2 │
│ client0 │ │ tailcontrol, logcatcher │ │ client1 │
│ ┌─────┐ │ │ ┌──────┐ ┌──────┐ │ │ ┌─────┐ │
│ │vethc│───────┼────┼──│vethrc│ │vethrs│──────┼─────┼──│veths│ │
│ ├─────┴─────┐ │ │ ├──────┴────┐ ├──────┴────┐ │ │ ├─────┴─────┐ │
│ │10.0.0.2/24│ │ │ │10.0.0.1/24│ │10.0.1.1/24│ │ │ │10.0.1.2/24│ │
│ └───────────┘ │ │ └───────────┘ └───────────┘ │ │ └───────────┘ │
└────────────────┘ └─────────────────────────────────┘ └────────────────┘
Before:
---------------------------------------------------
| TCP send | UDP send |
|------------------------|------------------------|
| 557.0 (±8.5) Mbits/sec | 3.03 (±0.02) Gbits/sec |
---------------------------------------------------
After:
---------------------------------------------------
| TCP send | UDP send |
|------------------------|------------------------|
| 544.8 (±1.6) Mbits/sec | 3.13 (±0.02) Gbits/sec |
---------------------------------------------------
The impact on receive performance is similar.
Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
This saves a layer of translation, and saves us having to
pass in extra bits and pieces of the netmap and prefs to
wgengine. Now it gets one Wireguard config, and one OS
network stack config.
Signed-off-by: David Anderson <danderson@tailscale.com>
Defensive programming against #368 in environments other than Docker,
e.g. if you try using Tailscale in Alpine Linux directly, sans
container.
Signed-off-by: David Anderson <danderson@tailscale.com>
The iptables package we use doesn't include command output, so we're
left with guessing what went wrong most of the time. This will at
least narrow things down to which operation failed.
Signed-off-by: David Anderson <danderson@tailscale.com>
For "tailscale status" on macOS (from separately downloaded
cmd/tailscale binary against App Store IPNExtension).
(This isn't all of it, but I've had this sitting around uncommitted.)
staticcheck used to fail on macOS (and presumably windows) due to a
variable declared in a common package that was only used by the Linux
build, which would prevent `redo pr` from passing on Mac. Moved variable
declaration from the common file to the Linux-specific one to resolve
the compiler complaint.
Signed-off-by: Wendi Yu <wendi.yu@yahoo.ca>
Implement rate limiting on log messages
Addresses issue #317, where logs can get spammed with the same message
nonstop. Created a rate limiting closure on logging functions, which
limits the number of messages being logged per second based on format
string. To keep memory usage as constant as possible, the previous cache
purging at periodic time intervals has been replaced by an LRU that
discards the oldest string when the capacity of the cache is reached.
Signed-off-by: Wendi Yu <wendi.yu@yahoo.ca>
Instead, pass in only exactly the relevant configuration pieces
that the OS network stack cares about.
Signed-off-by: David Anderson <danderson@tailscale.com>
New logic installs precise filters for subnet routes,
plays nice with other users of netfilter, and lays the
groundwork for fixing routing loops via policy routing.
Signed-off-by: David Anderson <danderson@tailscale.com>
If Australia's far away and not going to be used, it's still going to
be far away a minute later. No need to send backup
just-in-case-UDP-gets-lost STUN packets to the known far away
destinations. Those are the ones most likely to trigger retries due to
delay anyway (in random 50-250ms, currently). But we'll keep sending 1
packet to them, just in case our airplane landed.
Likewise, be less aggressive with IPv6. The main point is just to see
whether IPv6 works. No need to send up to 10 packets every round. Max
two is enough (except for the first round). This does mean our STUN
traffic graphs for IPv4-vs-IPv6 will change shape. Oh well. It was a
weird eyeball metric for IPv6 connectivity anyway and we have better
metrics.
We can tweak this policy over time. It's factored out and has tests
now.
No tidy, because it doesn't work for me:
$ go mod tidy
go: finding module for package tailscale.io/control
go: finding module for package tailscale.io/control/cfgdb
tailscale.com/control/controlclient tested by
tailscale.com/control/controlclient.test imports
tailscale.io/control: cannot find module providing package tailscale.io/control: unrecognized import path "tailscale.io/control": parse https://tailscale.io/control?go-get=1: no go-import meta tags (meta tag tailscale.com did not match import path tailscale.io/control)
tailscale.com/control/controlclient tested by
tailscale.com/control/controlclient.test imports
tailscale.io/control/cfgdb: cannot find module providing package tailscale.io/control/cfgdb: unrecognized import path "tailscale.io/control/cfgdb": parse https://tailscale.io/control/cfgdb?go-get=1: no go-import meta tags (meta tag tailscale.com did not match import path tailscale.io/control/cfgdb)
Signed-off-by: Elias Naur <mail@eliasnaur.com>
These will be used for dynamically changing the identity of a node, so
its ACL rights can be different from your own.
Note: Not all implemented yet on the server side, but we need this so
we can request the tagged rights in the first place.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This depends on improved support from the control server, to send the
new subnet width (Bits) fields. If these are missing, we fall back to
assuming their value is /32.
Conversely, if the server sends Bits fields to an older client, it will
interpret them as /32 addresses. Since the only rules we allow are
"accept" rules, this will be narrower or equal to the intended rule, so
older clients will simply reject hosts on the wider subnet (fail
closed).
With this change, the internal filter.Matches format has diverged
from the wire format used by controlclient, so move the wire format
into tailcfg and convert it to filter.Matches in controlclient.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
We were printing "Shields Up" when the netmap wasn't initialized yet,
which while technically effectively true, turned out to be confusing
when trying to debug things.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Some programs use frequent short-duration backoffs even under non-error
conditions. They can set this to avoid logging short backoffs when
things are operating normally, but still get messages when longer
backoffs kick in.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
When shields are up, no services are available to connect to, so hide
them all. This will also help them disappear from the UI menu on
other nodes.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This sets a default packet filter that blocks all incoming requests,
giving end users more control over who can get into their machine, even
if the admin hasn't set any central ACLs.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
Longer term, we should probably update the packet filter to be fully
stateful, for both TCP and ICMP. That is, only ICMP packets related to
a session *we* initiated should be allowed back in. But this is
reasonably secure for now, since wireguard is already trimming most
traffic. The current code would not protect against eg. Ping-of-Death style
attacks from VPN nodes.
Fixestailscale/tailscale#290.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
- Reset() was not including a Version field, so was getting rejected;
the Logout operation no longer happened when the client got disconnected.
- Don't crash if we can't decode 0-byte messages, which I suspect might
sometimes come through on EOF.
Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
This strictly sequences things such that c1 is fully registered in
the control server before c2 creates its poll. Failure to do this
can cause an inversion where c2's poll finishes establishing
before c1's poll starts, which results in c2 getting disconnected
rather than c1, and the test times out waiting for c1 to get kicked.
Fixes#98.
Signed-off-by: David Anderson <danderson@tailscale.com>
The test is straightforward, but it's a little perplexing if you're
not overly familiar with controlclient.
Signed-off-by: David Anderson <danderson@tailscale.com>
This was the last of the three places that do TLS from clients (logs,
control, derp). With this, iOS should be able to use the
memory-efficient x509 root CertPool.
I removed the HTTPC field in b6fa5a69be but it was apparently still
used in [oss-skipped] tests.
Restore it, but name it so it's more obvious that it's only for
tests. (It currently is, and I'd like to keep it like that for now.)
(from patchset 1, c12c890c64dd6372b3893af1e6f5ab11802c9e81, of
https://go-review.googlesource.com/c/go/+/230025/1, with merges fixes
due to parent commit's differents from its ps1..ps3)
Instead of parsing the PEM files and then storing the *Certificate
values forever, still parse them to see if they're valid and pick out
some fields, but then only store the decoded pem.Block.Bytes until
that cert is first needed.
Saves about 500K of memory on my (Debian stable) machine after doing a
tls.Dial or calling x509.SystemCertPool.
A more aggressive version of this is still possible: we can not keep
the pem.Block.Bytes in memory either, and re-read them from disk when
necessary. But dealing with files disappearing and even large
multi-cert PEM files changing (with offsets sliding around) made this
conservative version attractive. It doesn't change the
slurp-roots-on-startup semantics. It just does so with less memory
retained.
Change-Id: I3aea333f4749ae3b0026042ec3ff7ac015c72204
(from patchset 1, 7cdc3c3e7427c9ef69e19224d6036c09c5ea1723, of
https://go-review.googlesource.com/c/go/+/229917/1)
This will allow building CertPools that consume less memory. (Most
certs are never accessed. Different users/programs access different
ones, but not many.)
This CL only adds the new internal mechanism (and uses it for the
old AddCert) but does not modify any existing root pool behavior.
(That is, the default Unix roots are still all slurped into memory as
of this CL)
Change-Id: Ib3a42e4050627b5e34413c595d8ced839c7bfa14
Snapshotted from Go commit 619c7a48a38b28b521591b490fd14ccb7ea5e821
(https://go-review.googlesource.com/c/go/+/229762,
"crypto/x509: add x509omitbundledroots build tag to not embed roots")
With 975c01342a25899962969833d8b2873dc8856a4f
(https://go-review.googlesource.com/c/go/+/220721) removed, because it
depends on other stuff in Go std that doesn't yet exist in a Go
release.
Also, add a subset fork of Go's internal/testenv, for use by x509's tests.
The Tailscale API is a (mostly) RESTful API. Typically, POST bodies should be JSON encoded and responses will be JSON encoded.
# Authentication
Currently based on {some authentication method}. Visit the [admin panel](https://api.tailscale.com/admin) and navigate to the `Keys` page. Generate an API Key and keep it safe. Provide the key as the user key in basic auth when making calls to Tailscale API endpoints.
# APIs
* **[Devices](#device)**
- [GET device](#device-get)
- [DELETE device](#device-delete)
- Routes
- [GET device routes](#device-routes-get)
- [POST device routes](#device-routes-post)
* **[Tailnets](#tailnet)**
- ACLs
- [GET tailnet ACL](#tailnet-acl-get)
- [POST tailnet ACL](#tailnet-acl-post): set ACL for a tailnet
- [POST tailnet ACL preview](#tailnet-acl-preview-post): preview rule matches on an ACL for a resource
- [Devices](#tailnet-devices)
- [GET tailnet devices](#tailnet-devices-get)
- [DNS](#tailnet-dns)
- [GET tailnet DNS nameservers](#tailnet-dns-nameservers-get)
- [POST tailnet DNS nameservers](#tailnet-dns-nameservers-post)
- [GET tailnet DNS preferences](#tailnet-dns-preferences-get)
- [POST tailnet DNS preferences](#tailnet-dns-preferences-post)
- [GET tailnet DNS searchpaths](#tailnet-dns-searchpaths-get)
- [POST tailnet DNS searchpaths](#tailnet-dns-searchpaths-post)
## Device
<!-- TODO: description about what devices are -->
Each Tailscale-connected device has a globally-unique identifier number which we refer as the "deviceID" or sometimes, just "id".
You can use the deviceID to specify operations on a specific device, like retrieving its subnet routes.
To find the deviceID of a particular device, you can use the ["GET /devices"](#getdevices) API call and generate a list of devices on your network.
Find the device you're looking for and get the "id" field.
This is your deviceID.
<a name=device-get></div>
#### `GET /api/v2/device/:deviceid` - lists the details for a device
Returns the details for the specified device.
Supply the device of interest in the path using its ID.
Use the `fields` query parameter to explicitly indicate which fields are returned.
##### Parameters
##### Query Parameters
`fields` - Controls which fields will be included in the returned response.
Currently, supported options are:
*`all`: returns all fields in the response.
*`default`: return all fields except:
*`enabledRoutes`
*`advertisedRoutes`
*`clientConnectivity` (which contains the following fields: `mappingVariesByDestIP`, `derp`, `endpoints`, `latency`, and `clientSupports`)
Use commas to separate multiple options.
If more than one option is indicated, then the union is used.
For example, for `fields=default,all`, all fields are returned.
If the `fields` parameter is not provided, then the default option is used.
{"message":"cannot delete devices outside of your tailnet"}
```
<a name=device-routes-get></div>
#### `GET /api/v2/device/:deviceID/routes` - fetch subnet routes that are advertised and enabled for a device
Retrieves the list of subnet routes that a device is advertising, as well as those that are enabled for it. Enabled routes are not necessarily advertised (e.g. for pre-enabling), and likewise, advertised routes are not necessarily enabled.
#### `POST /api/v2/device/:deviceID/routes` - set the subnet routes that are enabled for a device
Sets which subnet routes are enabled to be routed by a device by replacing the existing list of subnet routes with the supplied parameters. Routes can be enabled without a device advertising them (e.g. for preauth). Returns a list of enabled subnet routes and a list of advertised subnet routes for a device.
##### Parameters
###### POST Body
`routes` - The new list of enabled subnet routes in JSON.
Tailnets are a top-level resource. ACL is an example of a resource that is tied to a top-level tailnet.
For more information on Tailscale networks/tailnets, click [here](https://tailscale.com/kb/1064/invite-team-members).
### ACL
<a name=tailnet-acl-get></a>
#### `GET /api/v2/tailnet/:tailnet/acl` - fetch ACL for a tailnet
Retrieves the ACL that is currently set for the given tailnet. Supply the tailnet of interest in the path. This endpoint can send back either the HuJSON of the ACL or a parsed JSON, depending on the `Accept` header.
##### Parameters
###### Headers
`Accept` - Response is parsed `JSON` if `application/json` is explicitly named, otherwise HuJSON will be returned.
##### Returns
Returns the ACL HuJSON by default. Returns a parsed JSON of the ACL (sans comments) if the `Accept` type is explicitly set to `application/json`. An `ETag` header is also sent in the response, which can be optionally used in POST requests to avoid missed updates.
<!-- TODO (chungdaniel): define error types and a set of docs for them -->
#### `POST /api/v2/tailnet/:tailnet/acl` - set ACL for a tailnet
Sets the ACL for the given domain.
HuJSON and JSON are both accepted inputs.
An `If-Match` header can be set to avoid missed updates.
Returns the updated ACL in JSON or HuJSON according to the `Accept` header on success. Otherwise, errors are returned for incorrectly defined ACLs, ACLs with failing tests on attempted updates, and mismatched `If-Match` header and ETag.
##### Parameters
###### Headers
`If-Match` - A request header. Set this value to the ETag header provided in an `ACL GET` request to avoid missed updates.
`Accept` - Sets the return type of the updated ACL. Response is parsed `JSON` if `application/json` is explicitly named, otherwise HuJSON will be returned.
###### POST Body
The POST body should be a JSON or [HuJSON](https://github.com/tailscale/hujson#hujson---human-json) formatted JSON object.
An ACL policy may contain the following top-level properties:
*`Groups` - Static groups of users which can be used for ACL rules.
*`Hosts` - Hostname aliases to use in place of IP addresses or subnets.
*`ACLs` - Access control lists.
*`TagOwners` - Defines who is allowed to use which tags.
*`Tests` - Run on ACL updates to check correct functionality of defined ACLs.
See https://tailscale.com/kb/1018/acls for more information on those properties.
@@ -7,11 +7,11 @@ package main // import "tailscale.com/cmd/derper"
import(
"context"
"crypto/tls"
"encoding/json"
"errors"
"expvar"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
@@ -20,18 +20,19 @@ import (
"os"
"path/filepath"
"regexp"
"strings"
"time"
"github.com/tailscale/wireguard-go/wgcfg"
"golang.org/x/crypto/acme/autocert"
"tailscale.com/atomicfile"
"tailscale.com/derp"
"tailscale.com/derp/derphttp"
"tailscale.com/logpolicy"
"tailscale.com/metrics"
"tailscale.com/stun"
"tailscale.com/net/stun"
"tailscale.com/tsweb"
"tailscale.com/types/key"
"tailscale.com/types/wgkey"
)
var(
@@ -42,10 +43,14 @@ var (
hostname=flag.String("hostname","derp.tailscale.com","LetsEncrypt host name, if addr's port is :443")
logCollection=flag.String("logcollection","","If non-empty, logtail collection to log to")
runSTUN=flag.Bool("stun",false,"also run a STUN server")
meshPSKFile=flag.String("mesh-psk-file",defaultMeshPSKFile(),"if non-empty, path to file containing the mesh pre-shared key file. It should contain some hex string; whitespace is trimmed.")
meshWith=flag.String("mesh-with","","optional comma-separated list of hostnames to mesh with; the server's own hostname can be in the list")
bootstrapDNS=flag.String("bootstrap-dns-names","","optional comma-separated list of hostnames to make available at /bootstrap-dns")
verifyClients=flag.Bool("verify-clients",false,"verify clients to this DERP server through a local tailscaled instance.")
)
typeconfigstruct{
PrivateKeywgcfg.PrivateKey
PrivateKeywgkey.Private
}
funcloadConfig()config{
@@ -53,11 +58,16 @@ func loadConfig() config {
returnconfig{PrivateKey:mustNewKey()}
}
if*configPath==""{
log.Fatalf("derper: -c <config path> not specified")
ifos.Getuid()==0{
*configPath="/var/lib/derper/derper.key"
}else{
log.Fatalf("derper: -c <config path> not specified")
}
log.Printf("no config path specified; using %s",*configPath)
upf.BoolVar(&upArgs.reset,"reset",false,"reset unspecified settings to their default values")
upf.StringVar(&upArgs.server,"login-server",ipn.DefaultControlURL,"base URL of control server")
upf.BoolVar(&upArgs.acceptRoutes,"accept-routes",false,"accept routes advertised by other Tailscale nodes")
upf.BoolVar(&upArgs.acceptDNS,"accept-dns",true,"accept DNS configuration from the admin panel")
upf.BoolVar(&upArgs.singleRoutes,"host-routes",true,"install host routes to other Tailscale nodes")
upf.StringVar(&upArgs.exitNodeIP,"exit-node","","Tailscale IP of the exit node for internet traffic, or empty string to not use an exit node")
upf.BoolVar(&upArgs.exitNodeAllowLANAccess,"exit-node-allow-lan-access",false,"Allow direct access to the local network when routing traffic via an exit node")
upf.StringVar(&upArgs.advertiseTags,"advertise-tags","","comma-separated ACL tags to request; each must start with \"tag:\" (e.g. \"tag:eng,tag:montreal,tag:ssh\")")
upf.StringVar(&upArgs.hostname,"hostname","","hostname to use instead of the one provided by the OS")
upf.StringVar(&upArgs.advertiseRoutes,"advertise-routes","","routes to advertise to other nodes (comma-separated, e.g. \"10.0.0.0/8,192.168.0.0/24\") or empty string to not advertise routes")
upf.BoolVar(&upArgs.advertiseDefaultRoute,"advertise-exit-node",false,"offer to be an exit node for internet traffic for the tailnet")
ifsafesocket.GOOSUsesPeerCreds(goos){
upf.StringVar(&upArgs.opUser,"operator","","Unix username to allow to operate on tailscaled without sudo")
}
switchgoos{
case"linux":
upf.BoolVar(&upArgs.snat,"snat-subnet-routes",true,"source NAT traffic to local routes advertised with --advertise-routes")
upf.StringVar(&upArgs.netfilterMode,"netfilter-mode",defaultNetfilterMode(),"netfilter mode (one of on, nodivert, off)")
case"windows":
upf.BoolVar(&upArgs.forceDaemon,"unattended",false,"run in \"Unattended Mode\" where Tailscale keeps running even after the current GUI user logs out (Windows-only)")
returnnil,fmt.Errorf("invalid IP address %q for --exit-node: %v",upArgs.exitNodeIP,err)
}
}elseifupArgs.exitNodeAllowLANAccess{
returnnil,fmt.Errorf("--exit-node-allow-lan-access can only be used with --exit-node")
}
ifupArgs.exitNodeIP!=""{
for_,ip:=rangest.TailscaleIPs{
ifexitNodeIP==ip{
returnnil,fmt.Errorf("cannot use %s as the exit node as it is a local IP address to this machine, did you mean --advertise-exit-node?",upArgs.exitNodeIP)
}
}
}
vartags[]string
ifupArgs.advertiseTags!=""{
tags=strings.Split(upArgs.advertiseTags,",")
for_,tag:=rangetags{
err:=tailcfg.CheckTag(tag)
iferr!=nil{
returnnil,fmt.Errorf("tag: %q: %s",tag,err)
}
}
}
iflen(upArgs.hostname)>256{
returnnil,fmt.Errorf("hostname too long: %d bytes (max 256)",len(upArgs.hostname))
t.Fatalf("client first Recv was unexpected type %T",v)
}
}
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.