Commit graph

455 commits

Author SHA1 Message Date
WofWca
f3e040bbd8
improvement: less scary failed conn logs & metrics
...and adjust the `totalFailedConnections` metric name
and description.

This commit should make the periodic stats log messages
and the relevant metric look less scary to users:
P2P connection failures are relatively frequent and are usually
not indicative of the proxy operator having done something wrong.
So let's tone the wording down.

See the discussion: https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/merge_requests/516#note_3173677.
2025-03-15 11:15:22 -04:00
WofWca
46fdcce5c6
fix: data race warnings of tokens_t
This migrates from using `atomic.LoadInt64` on `int64`
to making the `clients` field itself `atomic.Int64`.
Also `count` now takes `*tokens_t` by reference,
which fixes a linter warning.

It's not clear to me why it warned about this,
but I simplified it anyway.
2025-03-12 09:53:40 -04:00
WofWca
730e400123 fix: periodicProxyStats.connectionCount race
And `failedConnectionCount`.
Convert the `int` / `uint` to `atomic.Int32` / `atomic.Uint32`.
The race was discovered by running a proxy with the `-race` flag.
2025-03-12 00:47:22 +04:00
WofWca
1923803124 fix: potential race conditions with non-local err
Some of the changes do not appear to have a potential race condition,
so there it is purely a refactor,
while in others (e.g. in broker.go and in proxy/lib/snowflake.go)
we do use the same variable from multiple threads / functions.
2025-03-12 00:47:07 +04:00
WofWca
01819eee32
fix(proxy): race condition warning for isClosing
It appears that there is no need for the `isClosing` var at all:
we can just `close(c.sendMoreCh)` to ensure that it doesn't block
any more `Write()`s.

This is a follow-up to
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/merge_requests/144.
Related:
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/merge_requests/524.
2025-03-11 15:50:53 -04:00
WofWca
583178f4f2
feat(proxy): add failed connection count stats
For the summary log and for Prometheus metrics.

Log output example:

> In the last 1h0m0s, there were 7 completed successful connections. 2 connections failed. Traffic Relayed ↓ 321 KB (0.10 KB/s), ↑ 123 KB (0.05 KB/s).
2025-03-11 13:12:44 +00:00
WofWca
50bed1e67a
refactor: docstring for checkIsRelayURLAcceptable
Related: https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40378.
2025-03-03 12:14:15 +00:00
WofWca
6384643109
fix(proxy): improve NAT test reliability
This is a hack, and I'm not entirely sure how it works,
but it appears to work, at least somewhat.
See https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40419#note_3141855.
2025-02-17 11:47:11 +00:00
meskio
e345c3bac9
proxy: add country to prometheus metrics 2025-02-13 12:44:23 +01:00
meskio
b3c734ed63
proxy: webRTCconn gives the remote IP instead of the Address
We only use the IP part of the address.
2025-02-13 12:44:17 +01:00
WofWca
57eefd4b37
Temove outdated comment
As per https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/merge_requests/502#note_3159902.

The comment was added in c28c8ca489,
and got outdated apparently after
83c01565ef.

Signed-off-by: Cecylia Bocovich <cohosh@torproject.org>
2025-02-12 11:50:29 -05:00
WofWca
cb0fb02cd5
fix(proxy): not answering before client timeout
This is related to
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40230.

The initial MR that closed that issue,
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/merge_requests/391,
was not semantically correct, because `DataChannelTimeout`
starts after the client has already received the answer.

After
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/merge_requests/498#note_3156256
the code became not only semantically incorrect,
but also functionally incorrect because now if this timeout is hit
by the proxy, the client is guaranteed to be gone already.
This commit fixes it, by lowering the timeout.

This addresses a suggestion in
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40447.

This also closes
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40381
and supersedes
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/merge_requests/415.
2025-02-12 10:17:08 -05:00
WofWca
e038b68d79 refactor(proxy): simplify tokens.ret() on error 2025-01-04 19:31:44 +04:00
WofWca
85a93c5303 docs: clarify -ports-range is for port forwarding 2024-12-13 17:06:13 +04:00
WofWca
92521b6679 improvement: warn if ports-range is too narrow
...and improve the docstring for the parameter.
2024-12-13 17:06:11 +04:00
WofWca
cb32d008ca docs: improve ephemeral-ports-range description
Clarify that the default range is wide.
2024-12-13 16:09:22 +04:00
Cecylia Bocovich
6ecd5bf6d7
Remove log when offer is nil
After !414, we started returning a nil offer from pollOffer if the proxy
was not matched with a client. It's not longer an indication of failure,
so we should remove the "bad offer from broker" log message.
2024-12-03 15:05:44 -05:00
Cecylia Bocovich
5b479fdb13
Log EventOnCurrentNATTypeDetermined for proxy 2024-12-03 15:05:44 -05:00
WofWca
ae5bd52821
improvement: use SetIPFilter for local addrs
Closes https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40271.
Supersedes https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/merge_requests/417.

This simplifies the code and (probably) removes the need for
`StripLocalAddresses`, although makes us more dependent on Pion.

Signed-off-by: Cecylia Bocovich <cohosh@torproject.org>
2024-11-28 10:56:40 -05:00
Cecylia Bocovich
43799819a1
Suppress logs of proxy events by default 2024-11-28 10:42:54 -05:00
WofWca
c5d680342b
refactor: separate function for connectToRelay
This should make the code easier to glance over,
to understand that relay connection is performed from inside
the datachannel handler.
2024-11-21 14:55:28 +00:00
Shelikhoo
239357509f
update snowflake to use pion webrtc v4 2024-11-13 14:58:53 +00:00
Renovate Bot
290be512e3 chore(deps): update module github.com/pion/webrtc/v3 to v4 2024-11-11 18:45:36 +00:00
Cecylia Bocovich
aaf8826560
Add proxy event for when client has connected
This enables the usage of callbacks that will be called when a client
has opened a data channel connection to the proxy.
2024-11-06 10:31:33 -05:00
Waldemar Zimpel
028ff82683 Optionally enable local time for logging
Introduces the option `-log-local-time` which switches to local time
for logging instead of using UTC. Also if this option is applied, a message
is being output to the log on startup about the usage of local time
to draw attention, so the user/operator can take care of anonymity in case
the logs are going to be shared.
2024-10-28 16:23:44 +01:00
Neel Chauhan
f4305180b9
Remove the pollInterval loop from SignalingServer.pollOffer in the standalone proxy
Closes #40210.
2024-10-22 14:50:43 -04:00
Neel Chauhan
8792771cdc
broker and proxy must not reject client offers with no ICE candidates
Fixes #40371. Partially reverts !141.
2024-10-17 15:46:02 -04:00
Neel Chauhan
9ff205dd7f
Probetest/proxy: Set multiple comma-separated default STUN URLs
This adds the BlackBerry STUN server alongside Google's. Closes #40392.
2024-10-17 15:15:02 -04:00
WofWca
d346639eda
improvement(proxy): improve NAT check logging 2024-09-26 18:15:04 +01:00
WofWca
9b04728809
docs: improve proxy CLI param descriptions
Since the proxy component is the most dedicated for public use,
more comprehensive docs are good.
2024-09-25 16:50:18 +01:00
David Fifield
de61d7bb8d Document relayURL return in SignalingServer.pollOffer.
The second return value was added in
863a8296e8.
2024-09-21 18:28:17 +00:00
WofWca
0f0f118827 improvement(proxy): don't panic on invalid relayURL
Though prior to this change the panic could only happen
if the default relayURL set by the proxy is invalid,
since `datachannelHandler` is only called after a succesful
`checkIsRelayURLAcceptable()`, which ensures that it _is_ valid.
But in the case of invalid default relay URL, a warning is printed
already.
2024-09-21 18:20:31 +00:00
David Fifield
f752d2ab0c Spell out EphemeralMinPort and EphemeralMaxPort in comment.
For searching purposes.
2024-09-21 14:30:59 +00:00
WofWca
daff4d8913 refactor(proxy): add comment about packet size 2024-09-19 19:14:04 +00:00
WofWca
51edbbfd26
fix(proxy): maybe memory leak on failed NAT check
Maybe related: https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40243
2024-09-09 15:26:58 +01:00
WofWca
f44aa279fe
refactor(proxy): improve NAT check logging
4ed5da7f2f introduced `OnError` but it did not print
failed periodic NAT type check errors - the error was simply
ignored.
2024-09-09 15:26:55 +01:00
WofWca
7f9fea5797
fix(proxy): send answer even if ICE gathering is not complete
Otherwise the connection is guaranteed to fail, even though
we actually might have gathered enough to make a successful
connection.

Closes https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40230

This is the standalone proxy counterpart of https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake-webext/-/merge_requests/55
2024-09-09 11:58:28 +01:00
WofWca
2bbd4d0643
refactor(proxy): better RelayURL description
It's the case that it's simply "default" after
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/merge_requests/87
Now the broker specifies the relay URL (see `ProxyPollResponse`).
2024-09-05 13:04:42 +01:00
WofWca
94c6089cdd
hardening(proxy): don't proxy private IP addresses
...by default.

This is useful when `RelayDomainNamePattern` is lax (e.g. just "$")
(which is not the case by default, so this is simply
a hardening measure).
2024-09-02 14:59:26 +01:00
WofWca
399bda5257
refactor(proxy): tidy up isRelayURLAcceptable
Add clearer error messages
2024-09-02 14:59:26 +01:00
WofWca
0f2bdffba0
hardening(proxy): only accept ws & wss relays 2024-09-02 14:59:26 +01:00
WofWca
14f4c82ff7
test(proxy): add tests for relayURL check 2024-09-02 14:59:23 +01:00
WofWca
f4db64612c
feat: expose pollInterval in CLI
Closes https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/-/issues/40373
2024-08-22 09:31:37 -04:00
obble
a6d4570c23
Fix log message in CopyLoop 2024-08-21 16:06:41 +01:00
obble
1d6a2580c6 Improving Snowflake Proxy Performance by Adjusting Copy Buffer Size
TL;DR: The current implementation uses a 32K buffer size for a total of 64K of
buffers/connection, but each read/write is less than 2K according to my measurements.

# Background

The Snwoflake proxy uses as particularly hot function `copyLoop`
(proxy/lib/snowflake.go) to proxy data from a Tor relay to a connected client.
This is currently done using the `io.Copy` function to write all incoming data
both ways.

Looking at the `io.Copy` implementation, it internally uses `io.CopyBuffer`,
which in turn defaults to a buffer of size 32K for copying data (I checked and
the current implementation uses 32K every time).

Since `snowflake-proxy` is intended to be run in a very distributed manner, on
as many machines as possible, minimizing the CPU and memory footprint of each
proxied connection would be ideal, as well as maximising throughput for
clients.

# Hypothesis

There might exist a buffer size `X` that is more suitable for usage in `copyLoop` than 32K.

# Testing

## Using tcpdump

Assuming you use `-ephemeral-ports-range 50000:51000` for `snowflake-proxy`,
you can capture the UDP packets being proxied using

```sh
sudo tcpdump  -i <interface> udp portrange 50000-51000
```

which will provide a `length` value for each packet captured. One good start
value for `X` could then be slighly larger than the largest captured packet,
assuming one packet is copied at a time.

Experimentally I found this value to be 1265 bytes, which would make `X = 2K` a
possible starting point.

## Printing actual read

The following snippe was added in `proxy/lib/snowflake.go`:

```go
// Taken straight from standardlib io.copyBuffer
func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) {
	// If the reader has a WriteTo method, use it to do the copy.
	// Avoids an allocation and a copy.
	if wt, ok := src.(io.WriterTo); ok {
		return wt.WriteTo(dst)
	}
	// Similarly, if the writer has a ReadFrom method, use it to do the copy.
	if rt, ok := dst.(io.ReaderFrom); ok {
		return rt.ReadFrom(src)
	}
	if buf == nil {
		size := 32 * 1024
		if l, ok := src.(*io.LimitedReader); ok && int64(size) > l.N {
			if l.N < 1 {
				size = 1
			} else {
				size = int(l.N)
			}
		}
		buf = make([]byte, size)
	}
	for {
		nr, er := src.Read(buf)
		if nr > 0 {
			log.Printf("Read %d", nr) // THIS IS THE ONLY DIFFERENCE FROM io.CopyBuffer
			nw, ew := dst.Write(buf[0:nr])
			if nw < 0 || nr < nw {
				nw = 0
				if ew == nil {
					ew = errors.New("invalid write result")
				}
			}
			written += int64(nw)
			if ew != nil {
				err = ew
				break
			}
			if nr != nw {
				err = io.ErrShortWrite
				break
			}
		}
		if er != nil {
			if er != io.EOF {
				err = er
			}
			break
		}
	}
	return written, err
}
```

and `copyLoop` was amended to use this instead of `io.Copy`.

The `Read: BYTES` was saved to a file using this command

```sh
./proxy -verbose -ephemeral-ports-range 50000:50010 2>&1 >/dev/null  | awk '/Read: / { print $4 }' | tee read_sizes.txt
```

I got the result:

min: 8
max: 1402
median: 1402
average: 910.305

Suggested buffer size: 2K
Current buffer size: 32768 (32K, experimentally verified)

## Using a Snowflake Proxy in Tor browser and use Wireshark

I also used Wireshark, and concluded that all packets sent was < 2K.

# Conclusion

As per the commit I suggest changing the buffer size to 2K. Some things I have not been able to answer:

1. Does this make a big impact on performance?
1. Are there any unforseen consequences? What happens if a packet is > 2K (I
	 think the Go standard libary just splits the packet, but someone please confirm).
2024-08-21 15:02:15 +00:00
David Fifield
ee5f815f60 Cosmetic changes from dev-snowflake-udp-rebase-extradata.
https://gitlab.torproject.org/shelikhoo/snowflake/-/tree/dev-snowflake-udp-rebase-extradata
commit 59b76dc68d2ee0383c2acd91cb0f44edc46af939
2024-08-01 22:12:56 +00:00
itchyonion
4ed5da7f2f
Simplify proxy NAT checking logic 2024-05-28 12:30:44 -07:00
meskio
a9df5dd71a
Use ptutil for safelog and prometheus rounded metrics
* Related: #40354
2024-05-09 16:24:33 +02:00
meskio
01588d99db
Merge remote-tracking branches 'gitlab/mr/289' and 'gitlab/mr/293' 2024-04-04 12:27:14 +02:00
Sky
cec3c2df21 Update README.md to include all available CLI options 2024-04-04 08:21:56 +00:00