amnezia-vpn / amneziawg-go

AmneziaWG VPN protocol
MIT License
555 stars 69 forks source link

Document AmneziaWG Protocol #42

Closed marek22k closed 1 month ago

marek22k commented 1 month ago

Hello,

AmneziaWG introduces various new parameters in contrast to Vanilla WireGuard. What exactly do these do? How does AmneziaWG work?

leninalive commented 1 month ago

I am closing this issue as we are not interested in providing such documentation publicly. If you wish, you could obtain these docs by researching source code on your own.

marek22k commented 1 month ago

Is there a particular reason for this? (Do you not want to publish documentation because the risk of AmneziaWG being blocked is then higher?) Will there be public documentation on what the parameters (S1, H1, ...) do?

leninalive commented 1 month ago

Do you not want to publish documentation because the risk of AmneziaWG being blocked is then higher?

Exactly.

marek22k commented 1 month ago

I had a look at the code and in the kernel module a netlink message WG_CMD_UNKNOWN_PEER seems to be distributed in case of failed authentication of a peer. However, I cannot find a place where such a message is received. Why does AmneziaWG send it? Is it intended for analysis by third party programs?

Furthermore, the documentation says All parameters should be the same between Client and Server, except Jc - it can vary.. I tried the whole thing once - set Jmin and Jmax to different values for two peers and it still worked. Is the documentation wrong at this point?

marek22k commented 1 month ago

Another question: The README states that the H-values may be a maximum of 2^31-1=2147483647. However, a 32-bit integer is used. Shouldn't the maximum size then be 2^32-1=4294967295?

bobpaul commented 1 day ago

S1, S2, Jc, Jmin, and Jmax are somewhat described on the highlevel Working Principal. But not providing a meaningful description for these values means that someone setting up their own server can't configure smart values for these settings the way the android app "automagically" does if one gives that root access to a VPS.

At a minimum I think users need a list of these extra config values, what their range of allowed values, and how one should generate those values. Honestly, patching wg or wg-quick to randomly generate these would be really good, imho. I think it would also be good for users to know if these values should be periodically cycled or if it's fine to set them once and leave them forever so long as their server config isn't cloned by others.

What we DO NOT want is people to copy/paste a list of pre-set values for H1-H4, S1, S2, etc.

marek22k commented 1 day ago

I took a look at the source code and tried to document the new parameters in my blog entry. However, I could not find any answers to the three questions I asked here. Perhaps someone (maybe @leninalive) else could answer them?

bobpaul commented 1 day ago

@marek22k Which "the readme" are you looking at? I only see one README file in this repo and it doesn't describe the H1-H4 values, but I did figure them out. (They're defined in the template file that's in the android client)

H1-H4 should all be 4bytes, so 0x00000000 - 0xFFFFFFFF. H1-H4 have to exactly match on peers as these are used instead of the 4 message_type identifiers (and 3 reserved 0bytes) that are in all Wireguard packet.

S1 and S2 also have to exactly match. These are used for garbage data injected into first 2 packets (initiator to responder message_type=1 and responder to initiator message_type=2). Otherwise these two messages are always the same length. By setting S1 and S2 randomly, it ensures no two independent AmneziaWG networks have the same packet lengths for these first 2 messages.

Jc, Jmin, and Jmax relate to junk data that's sent by the initiator before the obfuscated initiator packet it sent. Jc is the count (how many junk packets), Jmin and Jmax are the sizes. I think Jc, Jmin, and Jmax can be configured uniquely on every peer. These are sent when a peer is using the endpoint= configuration to initiate a new connection. The other peer (the responder) is just ignoring the junk packets, so it should not need to know the size or number of them. And this is UDP, so it's not even guaranteed all of the junk packets will make it through; I wouldn't expect the responding peer to actually watch for Jc junk packets. The responder just needs to watch for a packet with S1 bytes of garbage data followed by the 4 bytes defined in H1.

Here's an example initiator packet. I have S1 configured to 142 (so the initiator packet has 148+142=290 bytes of payload). And I have H1 configured to 221932096 (0x0d3a6a40). You can see that the 149th byte in the payload is 0x40. This is because H1 is put into the packet little-endian. image.

WG_CMD_UNKNOWN_PEER

This isn't sent on the network. The ENUM where this is defined has only 2 other commands, Get_Device and Set_Device.

enum wg_cmd {
    WG_CMD_GET_DEVICE,
    WG_CMD_SET_DEVICE,
    WG_CMD_UNKNOWN_PEER,
    __WG_CMD_MAX
};

This for notifing a userspace app on the same machine. You can see it used in the notification listener. of the peer-approver tool in amneziawg-tools.

marek22k commented 1 day ago

I meant the README for the Kernel Module. https://github.com/amnezia-vpn/amneziawg-linux-kernel-module?tab=readme-ov-file#configuration Thank you for confirming the value range of H1-H4 and that the J-values may differ on both peers. This is then apparently incorrectly specified in the README. And thanks for explaining what the kernel notifications are sent for! I originally thought it was to detect DPI systems that were actively probing the server.

bobpaul commented 1 day ago

Just to double-check, I've successfully connected with values for H1=0xFFFFFFFF, H2=0xFFFFFFFE, H3=0xFFFFFFFD, and H4=0xFFFFFFFC using both amnezia-go and the amnezia-linux kernel module on linux and wgtunnel on android.

I meant the README for the Kernel Module. https://github.com/amnezia-vpn/amneziawg-linux-kernel-module?tab=readme-ov-file#configuration Thank you for confirming the value range of H1-H4 and that the J-values may differ on both peers. This is then apparently incorrectly specified in the README.

I notice that says "recommended range" rather than "max range". There may be a good reason for recommending lower values even though it's possible to use the full range. But it does smell like a mistake.