shadowsocks-rust icon indicating copy to clipboard operation
shadowsocks-rust copied to clipboard

Need help calculating Shadowsocks UDP packets overhead for correct MTU setting

Open ipinyagin97 opened this issue 6 months ago • 5 comments
trafficstars

I'm setting up a Wireguard-over-Shadowsocks UDP-only connection using 2022-blake3-aes-256-gcm cipher method. In order to set up the Wireguard interface's MTU, I need to accomodate for Shadowsocks overhead.

I found the general structure of a packet which discusses the parts from which Shadowsocks packets are made, but the actual field sizes seem to be largely implementation dependent and/or cipher-dependent (e.g. padding size). Can somebody please help me figure out the exact overhead for these packets? I tried digging through the sources, but apparently it's buried somewhere deep, too deep for me since I'm really not a Rust guy.

Any help would be greatly appreciated!

ipinyagin97 avatar May 01 '25 08:05 ipinyagin97

You might be interested in something like https://github.com/database64128/swgp-go. The zero-overhead mode allows you to proxy WireGuard traffic without lowering the tunnel MTU.

To answer your original question, suppose we use IPv6 as the destination address, the overhead of using 2022-blake3-aes-256-gcm for UDP is roughly:

number_of_identity_headers * size_of_identity_header + size_of_separate_header + size_of_type + size_of_timestamp + size_of_session_id + size_of_padding_length + padding_length + socks5_address_length

Suppose both client and server don't add padding, and we use IPv6 as the destination address, and have an iPSK configured on the server, that would be:

1 * 16 + 16 + 1 + 8 + 8 + 2 + 0 + (1 + 16 + 2) = 70

If your ethernet MTU is 1500, the WireGuard tunnel MTU over Shadowsocks would be (1500 - 40 (IPv6 header) - 8 (UDP header) - 70 (Shadowsocks overhead) - 32 (WireGuard overhead)) & 0xFFF0 (round it down to multiples of 16) = 1344.

database64128 avatar May 01 '25 09:05 database64128

@database64128 Thank you so much for such a prompt response! I did stumble upon that repo of yours, but I don't believe it supports the new 2022 ciphers yet?

As for the calculation itself: I have a habit of disabling IPv6 right at the kernel level on all of my machines, so all connections would be IPv4 only, but that's beside the point, let's assume that I'm ready to sacrifice some MTU to allow for future flexibility in switching between IP versions.

number_of_identity_headers * size_of_identity_header - my understanding is that number_of_identity_headers would only ever be greater than 1 if my password looked like PSK1:PSK2:...:PSK_N? I think I saw something along these lines in the sources.

The biggest mistery here for me is padding_length. Is there a configuration option that I'm not aware of, which allows customizing this? I got the impression that this was either implementation-dependent or method-dependent. Is there a way to know for sure which padding length would be used in my particular setup?

ipinyagin97 avatar May 01 '25 09:05 ipinyagin97

I did stumble upon that repo of yours, but I don't believe it supports the new 2022 ciphers yet?

I wrote swgp-go around the same time I designed Shadowsocks 2022. WireGuard provides stronger security guarantees than Shadowsocks 2022. Proxying WireGuard traffic over Shadowsocks 2022 adds a lot of overhead with no additional benefits. swgp-go uses more lightweight protocols specifically designed for circumventing the blocking of WireGuard.

number_of_identity_headers * size_of_identity_header - my understanding is that number_of_identity_headers would only ever be greater than 1 if my password looked like PSK1:PSK2:...:PSK_N? I think I saw something along these lines in the sources.

Yes. In your example, the number of identity headers would be N - 1. That is, if you only have a single PSK on the server, there won't be any identity headers in the packet.

The biggest mistery here for me is padding_length. Is there a configuration option that I'm not aware of, which allows customizing this? I got the impression that this was either implementation-dependent or method-dependent. Is there a way to know for sure which padding length would be used in my particular setup?

As far as I can remember, shadowsocks-rust does not add padding to packets. @zonyitoo should be able to confirm this.

Indeed, allowing users and server admins to customize padding options was the intention behind the design. My own implementation, for example, pads DNS packets by default: https://github.com/database64128/shadowsocks-go#1-packet-padding-policy

database64128 avatar May 01 '25 10:05 database64128

swgp-go uses more lightweight protocols specifically designed for circumventing the blocking of WireGuard.

Would you be able to elaborate a bit on this? Surely some overhead is still introduced, so the MTU is still affected, albeit to a smaller degree?

I'll be honest, I'm not too familiar with how exactly Shadowsocks helps with censorship circumvention, apart from the fact that, as far as my understanding goes, no patterns have yet been found that would allow DPI equipment to reliably detect traffic as Shadowsocks traffic as long as the new uncompromised 2022 ciphers are used. Does the same hold true for swgp-go implementation, i.e. the traffic it generates also can't be reliably identified by current DPI solutions?

Yes. In your example, the number of identity headers would be N - 1. That is, if you only have a single PSK on the server, there won't be any identity headers in the packet.

Aha. So if I only use a single PSK, the number_of_identity_headers would actually be zero? Is this true for both client->server and server->client traffic?

ipinyagin97 avatar May 01 '25 11:05 ipinyagin97

Would you be able to elaborate a bit on this? Surely some overhead is still introduced, so the MTU is still affected, albeit to a smaller degree?

The project README goes into detail about how this is done. In the zero overhead mode, data packets only have their identifiable parts encrypted using a block cipher, which does not introduce overhead in terms of the packet size.

I'll be honest, I'm not too familiar with how exactly Shadowsocks helps with censorship circumvention, apart from the fact that, as far as my understanding goes, no patterns have yet been found that would allow DPI equipment to reliably detect traffic as Shadowsocks traffic as long as the new uncompromised 2022 ciphers are used. Does the same hold true for swgp-go implementation, i.e. the traffic it generates also can't be reliably identified by current DPI solutions?

Yes, that's the whole point of swgp-go.

Aha. So if I only use a single PSK, the number_of_identity_headers would actually be zero?

That's correct. The single PSK would be the user PSK, and there are no identity PSKs in this setup.

Is this true for both client->server and server->client traffic?

Only packets sent by clients can contain identity headers. Server packets won't ever have identity headers, even if EIH is in use.

database64128 avatar May 01 '25 11:05 database64128