diff --git a/TunSafe.vcxproj b/TunSafe.vcxproj
index ea793d3..42a9fbb 100644
--- a/TunSafe.vcxproj
+++ b/TunSafe.vcxproj
@@ -197,7 +197,6 @@
-
@@ -221,7 +220,6 @@
-
diff --git a/TunSafe.vcxproj.filters b/TunSafe.vcxproj.filters
index 77805db..3134cb4 100644
--- a/TunSafe.vcxproj.filters
+++ b/TunSafe.vcxproj.filters
@@ -56,9 +56,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -152,9 +149,6 @@
Source Files
-
- Source Files
-
crypto\aesgcm
diff --git a/ipzip2/ipzip2.cpp b/ipzip2/ipzip2.cpp
deleted file mode 100644
index 5ed17a3..0000000
--- a/ipzip2/ipzip2.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "stdafx.h"
-// this is a placeholder for a packet compression algorithm not yet released.
diff --git a/ipzip2/ipzip2.h b/ipzip2/ipzip2.h
deleted file mode 100644
index bfcd94b..0000000
--- a/ipzip2/ipzip2.h
+++ /dev/null
@@ -1 +0,0 @@
-// this is a placeholder for a packet compression algorithm not yet released.
diff --git a/tunsafe_amalgam.cpp b/tunsafe_amalgam.cpp
index 664e79a..9d0c94e 100644
--- a/tunsafe_amalgam.cpp
+++ b/tunsafe_amalgam.cpp
@@ -19,7 +19,7 @@
#include "crypto/blake2s/blake2s.cpp"
#include "crypto/siphash/siphash.cpp"
#include "crypto/aesgcm/aesgcm.cpp"
-#include "ipzip2/ipzip2.cpp"
+#include "network_common.cpp"
#if defined(WITH_NETWORK_BSD)
#include "network_bsd.cpp"
diff --git a/wireguard.cpp b/wireguard.cpp
index 4c64613..f638aba 100644
--- a/wireguard.cpp
+++ b/wireguard.cpp
@@ -12,7 +12,6 @@
#include
#include
#include
-#include "ipzip2/ipzip2.h"
#include "wireguard.h"
#include "wireguard_config.h"
#include "util.h"
@@ -104,31 +103,6 @@ void WireguardProcessor::ResetStats() {
memset(&stats_, 0, sizeof(stats_));
}
-void WireguardProcessor::SetupCompressionHeader(WgPacketCompressionVer01 *c) {
- memset(c, 0, sizeof(WgPacketCompressionVer01));
- // Windows uses a ttl of 128 while other platforms use 64
-#if defined(OS_WIN)
- c->ttl = 128;
-#else // defined(OS_WIN)
- c->ttl = 64;
-#endif // defined(OS_WIN)
- WriteLE16(&c->version, EXT_PACKET_COMPRESSION_VER);
-
- for (auto it = addresses_.begin(); it != addresses_.end(); ++it) {
- if (it->size == 32) {
- memcpy(c->ipv4_addr, it->addr, 4);
- c->flags = ((it->cidr >> 3) & 3);
- break;
- }
- }
- for (auto it = addresses_.begin(); it != addresses_.end(); ++it) {
- if (it->size == 128) {
- memcpy(c->ipv6_addr, it->addr, 16);
- break;
- }
- }
-}
-
static WgCidrAddr WgCidrAddrFromIpAddr(const IpAddr &addr) {
WgCidrAddr r = {0};
if (addr.sin.sin_family == AF_INET) {
@@ -208,8 +182,6 @@ bool WireguardProcessor::ConfigureTun() {
if (!tun_->Configure(std::move(config), &config_out))
return false;
- SetupCompressionHeader(dev_.compression_header());
-
network_discovery_spoofing_ = config_out.enable_neighbor_discovery_spoofing;
memcpy(network_discovery_mac_, config_out.neighbor_discovery_spoofing_mac, 6);
@@ -438,22 +410,18 @@ void WireguardProcessor::WriteAndEncryptPacketToUdp_WillUnlock(WgPeer *peer, Pac
} else {
peer->OnDataSent();
-#if WITH_HANDSHAKE_EXT
- // Attempt to compress the packet headers using ipzip.
- if (keypair->enabled_features[WG_FEATURE_ID_IPZIP]) {
- uint32 rv = IpzipCompress(data, (uint32)size, &keypair->ipzip_state_, 0);
- if (rv == (uint32)-1)
+ // Attempt to compress the packet headers
+ if (WITH_HANDSHAKE_EXT && keypair->compress_handler_) {
+ WgCompressHandler::CompressState st = keypair->compress_handler_->Compress(packet);
+ if (st == WgCompressHandler::COMPRESS_FAIL)
goto getout_discard;
- if (rv == 0)
+ if (st == WgCompressHandler::COMPRESS_NO)
goto add_padding;
- stats_.compression_hdr_saved_out += (int32)(size - rv);
- data += (int32)(size - rv);
- size = rv;
+ stats_.compression_hdr_saved_out += (int32)(size - packet->size);
+ data = packet->data;
+ size = packet->size;
} else {
add_padding:
-#else
- {
-#endif // WITH_HANDSHAKE_EXT
// Pad packet to a multiple of 16 bytes, but no more than the mtu bytes.
unsigned padding = std::min((0 - size) & 15, (unsigned)mtu_ - (unsigned)size);
memset(data + size, 0, padding);
@@ -461,8 +429,7 @@ add_padding:
}
}
-#if WITH_SHORT_HEADERS
- if (keypair->enabled_features[WG_FEATURE_ID_SHORT_HEADER]) {
+ if (WITH_SHORT_HEADERS && keypair->enabled_features[WG_FEATURE_ID_SHORT_HEADER]) {
size_t header_size;
byte *write = data;
uint8 tag = WG_SHORT_HEADER_BIT, inner_tag;
@@ -530,9 +497,6 @@ add_padding:
ad_len = data - write_after_ack_header;
} else {
need_big_packet:
-#else
- {
-#endif // #if WITH_SHORT_HEADERS
packet->size = (int)(size + sizeof(MessageData) + keypair->auth_tag_length);
peer->tx_bytes_ += packet->size;
@@ -859,7 +823,9 @@ void WireguardProcessor::HandleShortHeaderFormatPacket(uint32 tag, Packet *packe
if (tag & WG_SHORT_HEADER_ACK)
keypair->can_use_short_key_for_outgoing = (ack_tag & WG_ACK_HEADER_KEY_MASK) * WG_SHORT_HEADER_KEY_ID;
- HandleAuthenticatedDataPacket_WillUnlock(keypair, packet, data, bytes_left - keypair->auth_tag_length);
+ packet->data = data;
+ packet->size = bytes_left - keypair->auth_tag_length;
+ HandleAuthenticatedDataPacket_WillUnlock(keypair, packet);
return;
getout_unlock:
WG_RELEASE_LOCK(keypair->peer->mutex_);
@@ -881,7 +847,7 @@ void WireguardProcessor::NotifyHandshakeComplete() {
procdel_->OnConnected();
}
-void WireguardProcessor::HandleAuthenticatedDataPacket_WillUnlock(WgKeypair *keypair, Packet *packet, uint8 *data, size_t data_size) {
+void WireguardProcessor::HandleAuthenticatedDataPacket_WillUnlock(WgKeypair *keypair, Packet *packet) {
WgPeer *peer = keypair->peer;
assert(peer->IsPeerLocked());
@@ -901,6 +867,7 @@ void WireguardProcessor::HandleAuthenticatedDataPacket_WillUnlock(WgKeypair *key
peer->ScheduleNewHandshake();
}
+ uint32 data_size = packet->size;
if (data_size == 0) {
peer->OnKeepaliveReceived();
WG_RELEASE_LOCK(peer->mutex_);
@@ -909,22 +876,22 @@ void WireguardProcessor::HandleAuthenticatedDataPacket_WillUnlock(WgKeypair *key
peer->OnDataReceived();
WG_RELEASE_LOCK(peer->mutex_);
-#if WITH_HANDSHAKE_EXT
- // Unpack the packet headers using ipzip
- if (keypair->enabled_features[WG_FEATURE_ID_IPZIP]) {
- uint32 rv = IpzipDecompress(data, (uint32)data_size, &keypair->ipzip_state_, IPZIP_RECV_BY_CLIENT);
- if (rv == (uint32)-1)
+ // Unpack the packet headers?
+ if (WITH_HANDSHAKE_EXT && keypair->compress_handler_) {
+ WgCompressHandler::CompressState st = keypair->compress_handler_->Decompress(packet);
+ if (st == WgCompressHandler::COMPRESS_FAIL)
goto getout;
- stats_.compression_hdr_saved_in += (int64)rv - data_size;
- data -= (int64)rv - data_size, data_size = rv;
+ if (st == WgCompressHandler::COMPRESS_YES)
+ stats_.compression_hdr_saved_in += (int32)(packet->size - exch(data_size, packet->size));
}
-#endif // WITH_HANDSHAKE_EXT
// Verify that the packet is a valid ipv4 or ipv6 packet of proper length,
// with a source address that belongs to the peer.
WgPeer *peer_from_header;
- unsigned int ip_version, size_from_header;
+ uint32 ip_version, size_from_header;
+ uint8 *data;
+ data = packet->data;
ip_version = *data >> 4;
if (ip_version == 4) {
if (data_size < IPV4_HEADER_SIZE)
@@ -951,10 +918,9 @@ void WireguardProcessor::HandleAuthenticatedDataPacket_WillUnlock(WgKeypair *key
if (peer_from_header != peer || size_from_header > data_size)
goto getout_error_header;
- packet->data = data;
packet->size = size_from_header;
- stats_.tun_bytes_out += packet->size;
+ stats_.tun_bytes_out += size_from_header;
stats_.tun_packets_out++;
tun_->WriteTunPacket(packet);
@@ -970,7 +936,7 @@ void WireguardProcessor::HandleDataPacket(Packet *packet) {
assert(dev_.IsMainOrDataThread());
uint8 *data = packet->data;
- size_t data_size = packet->size;
+ uint32 data_size = packet->size;
uint32 key_id = ((MessageData*)data)->receiver_id;
uint64 counter = ToLE64((((MessageData*)data)->counter));
WgKeypair *keypair = dev_.LookupKeypairByKeyId(key_id);
@@ -981,6 +947,9 @@ getout:
return;
}
+ packet->data = data + sizeof(MessageData);
+ packet->size = data_size - sizeof(MessageData) - keypair->auth_tag_length;
+
if (!WgKeypairDecryptPayload(data + sizeof(MessageData), data_size - sizeof(MessageData),
NULL, 0, counter, keypair)) {
stats_.error_mac++;
@@ -1001,7 +970,8 @@ getout:
assert(!keypair->peer->marked_for_delete_);
WgPeer::CopyEndpointToPeer_Locked(keypair, &packet->addr);
- HandleAuthenticatedDataPacket_WillUnlock(keypair, packet, data + sizeof(MessageData), data_size - sizeof(MessageData) - keypair->auth_tag_length);
+
+ HandleAuthenticatedDataPacket_WillUnlock(keypair, packet);
}
}
diff --git a/wireguard.h b/wireguard.h
index 70ccddb..69278ed 100644
--- a/wireguard.h
+++ b/wireguard.h
@@ -115,11 +115,10 @@ private:
void HandleHandshakeCookiePacket(Packet *packet);
void HandleDataPacket(Packet *packet);
- void HandleAuthenticatedDataPacket_WillUnlock(WgKeypair *keypair, Packet *packet, uint8 *data, size_t data_size);
+ void HandleAuthenticatedDataPacket_WillUnlock(WgKeypair *keypair, Packet *packet);
void HandleShortHeaderFormatPacket(uint32 tag, Packet *packet);
bool CheckIncomingHandshakeRateLimit(Packet *packet, bool overload);
bool HandleIcmpv6NeighborSolicitation(const byte *data, size_t data_size);
- void SetupCompressionHeader(WgPacketCompressionVer01 *c);
void NotifyHandshakeComplete();
ProcessorDelegate *procdel_;
diff --git a/wireguard_proto.cpp b/wireguard_proto.cpp
index 214ac4b..5ea0966 100644
--- a/wireguard_proto.cpp
+++ b/wireguard_proto.cpp
@@ -60,7 +60,6 @@ WgDevice::WgDevice() {
next_rng_slot_ = 0;
main_thread_scheduled_ = NULL;
main_thread_scheduled_last_ = &main_thread_scheduled_;
- memset(&compression_header_, 0, sizeof(compression_header_));
low_resolution_timestamp_ = cookie_secret_timestamp_ = OsGetMilliseconds();
OsGetRandomBytes(cookie_secret_, sizeof(cookie_secret_));
@@ -791,6 +790,7 @@ void WgPeer::ParseMessageHandshakeCookie(WgDevice *dev, const MessageHandshakeCo
#if WITH_HANDSHAKE_EXT
size_t WgPeer::WriteHandshakeExtension(uint8 *dst, WgKeypair *keypair) {
+ uint8 *dst_end = dst + MAX_SIZE_OF_HANDSHAKE_EXTENSION;
uint8 *dst_org = dst, value = 0;
// Include the supported features extension
if (!IsOnlyZeros(features_, sizeof(features_))) {
@@ -818,13 +818,10 @@ size_t WgPeer::WriteHandshakeExtension(uint8 *dst, WgKeypair *keypair) {
dst += ciphers;
}
}
- if (features_[WG_FEATURE_ID_IPZIP]) {
- // Include the packet compression extension
- *dst++ = EXT_PACKET_COMPRESSION;
- *dst++ = sizeof(WgPacketCompressionVer01);
- memcpy(dst, &dev_->compression_header_, sizeof(WgPacketCompressionVer01));
- dst += sizeof(WgPacketCompressionVer01);
- }
+ // Packet compression extension?
+ if (features_[WG_FEATURE_ID_IPZIP] && dev_->delegate_)
+ dst += dev_->delegate_->WritePacketCompressionExtension(dst, dst_end - dst);
+
return dst - dst_org;
}
@@ -856,32 +853,7 @@ static uint32 ResolveCipherSuite(int tie, const uint8 *a, size_t a_size, const u
(tie == 0 && cipher_strengths[found_a] > cipher_strengths[found_b])) ? found_a : found_b;
}
-void WgKeypairSetupCompressionExtension(WgKeypair *keypair, const WgPacketCompressionVer01 *remotec) {
- const WgPacketCompressionVer01 *localc = keypair->peer->dev_->compression_header();
- IpzipState *state = &keypair->ipzip_state_;
-
- // Use is_initiator as tie-breaker on who's going to be the client side.
- int flags_xor = 0;
- if ((localc->flags & ~3) + 2 * keypair->is_initiator - 1 <= (remotec->flags & ~3))
- std::swap(localc, remotec), flags_xor = 1;
- state->flags_xor = flags_xor;
-
- memcpy(state->client_addr_v4, localc->ipv4_addr, 4);
- memcpy(state->client_addr_v6, localc->ipv6_addr, 16);
- state->guess_ttl[0] = localc->ttl;
- state->client_addr_v4_subnet_bytes = (localc->flags & 3);
- WriteLE32(&state->client_addr_v4_netmask, 0xffffffff >> ((localc->flags & 3) * 8));
-
- memcpy(state->server_addr_v4, remotec->ipv4_addr, 4);
- memcpy(state->server_addr_v6, remotec->ipv6_addr, 16);
- state->guess_ttl[1] = remotec->ttl;
- state->server_addr_v4_subnet_bytes = (remotec->flags & 3);
- WriteLE32(&state->server_addr_v4_netmask, 0xffffffff >> ((remotec->flags & 3) * 8));
-}
-
-bool WgKeypairParseExtendedHandshake(WgKeypair *keypair, const uint8 *data, size_t data_size) {
- bool did_setup_compression = false;
-
+bool WgPeer::ParseExtendedHandshake(WgKeypair *keypair, const uint8 *data, size_t data_size) {
while (data_size >= 2) {
uint8 type = data[0], size = data[1];
data += 2, data_size -= 2;
@@ -892,7 +864,7 @@ bool WgKeypairParseExtendedHandshake(WgKeypair *keypair, const uint8 *data, size
case EXT_CIPHER_SUITES:
keypair->cipher_suite = ResolveCipherSuite(keypair->peer->cipher_prio_ - (type - EXT_CIPHER_SUITES),
keypair->peer->ciphers_, keypair->peer->num_ciphers_,
- data, data_size);
+ data, size);
break;
case EXT_BOOLEAN_FEATURES:
for (size_t i = 0, j = std::max(WG_FEATURES_COUNT, size * 4); i != j; i++) {
@@ -903,13 +875,8 @@ bool WgKeypairParseExtendedHandshake(WgKeypair *keypair, const uint8 *data, size
}
break;
case EXT_PACKET_COMPRESSION:
- if (size == sizeof(WgPacketCompressionVer01)) {
- WgPacketCompressionVer01 *c = (WgPacketCompressionVer01*)data;
- if (ReadLE16(&c->version) == EXT_PACKET_COMPRESSION_VER) {
- WgKeypairSetupCompressionExtension(keypair, c);
- did_setup_compression = true;
- }
- }
+ if (keypair->enabled_features[WG_FEATURE_ID_IPZIP] && !keypair->compress_handler_ && keypair->peer->dev_->delegate_)
+ keypair->compress_handler_ = keypair->peer->dev_->delegate_->ParsePacketCompressionExtension(keypair, data, size);
break;
}
data += size, data_size -= size;
@@ -917,7 +884,8 @@ bool WgKeypairParseExtendedHandshake(WgKeypair *keypair, const uint8 *data, size
if (data_size != 0)
return false;
- keypair->enabled_features[WG_FEATURE_ID_IPZIP] &= did_setup_compression;
+ if (!keypair->compress_handler_)
+ keypair->enabled_features[WG_FEATURE_ID_IPZIP] = false;
keypair->auth_tag_length = (keypair->enabled_features[WG_FEATURE_ID_SHORT_MAC] ? 8 : CHACHA20POLY1305_AUTHTAGLEN);
// RINFO("Cipher Suite = %d", keypair->cipher_suite);
@@ -965,7 +933,7 @@ WgKeypair *WgPeer::CreateNewKeypair(bool is_initiator, const uint8 chaining_key[
kp->auth_tag_length = CHACHA20POLY1305_AUTHTAGLEN;
#if WITH_HANDSHAKE_EXT
- if (!WgKeypairParseExtendedHandshake(kp, extfield, extfield_size)) {
+ if (!ParseExtendedHandshake(kp, extfield, extfield_size)) {
fail:
delete kp;
return NULL;
diff --git a/wireguard_proto.h b/wireguard_proto.h
index bd16142..b1166be 100644
--- a/wireguard_proto.h
+++ b/wireguard_proto.h
@@ -4,7 +4,6 @@
#include "tunsafe_types.h"
#include "netapi.h"
-#include "ipzip2/ipzip2.h"
#include "tunsafe_config.h"
#include "tunsafe_endian.h"
#include "tunsafe_threading.h"
@@ -201,15 +200,6 @@ enum {
WG_BOOLEAN_FEATURE_ENFORCES = 0x3,
};
-struct WgPacketCompressionVer01 {
- uint16 version; // Packet compressor version
- uint8 ttl; // Guessed TTL
- uint8 flags; // Subnet length and packet direction
- uint8 ipv4_addr[4]; // IPV4 address of endpoint
- uint8 ipv6_addr[16]; // IPV6 address of endpoint
-};
-STATIC_ASSERT(sizeof(WgPacketCompressionVer01) == 24, WgPacketCompressionVer01_wrong_size);
-
struct WgKeypair;
class WgPeer;
@@ -303,6 +293,23 @@ struct WgPublicKeyHasher {
size_t operator()(const WgPublicKey&a) const;
};
+class WgCompressHandler {
+public:
+ virtual ~WgCompressHandler() {}
+
+ enum CompressState {
+ COMPRESS_FAIL = -1,
+ COMPRESS_NO = 0,
+ COMPRESS_YES = 1,
+ };
+
+ // Compress a packet.
+ virtual CompressState Compress(Packet *packet);
+
+ virtual CompressState Decompress(Packet *packet);
+
+};
+
class WgDevice {
friend class WgPeer;
friend class WireguardProcessor;
@@ -316,6 +323,12 @@ public:
// return true to try again or false to fail. The packet can be copied and saved
// to resume a handshake later on.
virtual bool HandleUnknownPeerId(uint8 public_key[WG_PUBLIC_KEY_LEN], Packet *packet) = 0;
+
+ // Write out the compression header
+ virtual size_t WritePacketCompressionExtension(uint8 *data, size_t data_size) = 0;
+
+ // Parse the packet compression extension
+ virtual WgCompressHandler *ParsePacketCompressionExtension(WgKeypair *keypair, const uint8 *data, size_t data_size) = 0;
};
WgDevice();
@@ -346,7 +359,6 @@ public:
WgPeer *first_peer() { return peers_; }
const uint8 *public_key() const { return s_pub_; }
WgRateLimit *rate_limiter() { return &rate_limiter_; }
- WgPacketCompressionVer01 *compression_header() { return &compression_header_; }
bool is_private_key_initialized() { return is_private_key_initialized_; }
bool IsMainThread() { return CurrentThreadIdEquals(main_thread_id_); }
@@ -436,8 +448,6 @@ private:
WgRateLimit rate_limiter_;
- WgPacketCompressionVer01 compression_header_;
-
// For defering deletes until all worker threads are guaranteed not to use an object.
MultithreadedDelayedDelete delayed_delete_;
};
@@ -447,8 +457,6 @@ class WgPeer {
friend class WgDevice;
friend class WireguardProcessor;
friend class WgConfig;
- friend bool WgKeypairParseExtendedHandshake(WgKeypair *keypair, const uint8 *data, size_t data_size);
- friend void WgKeypairSetupCompressionExtension(WgKeypair *keypair, const WgPacketCompressionVer01 *remotec);
public:
explicit WgPeer(WgDevice *dev);
~WgPeer();
@@ -496,6 +504,7 @@ public:
WgPeer *next_peer() { return next_peer_; }
private:
+ static bool ParseExtendedHandshake(WgKeypair *keypair, const uint8 *data, size_t data_size);
static WgKeypair *CreateNewKeypair(bool is_initiator, const uint8 key[WG_HASH_LEN], uint32 send_key_id, const uint8 *extfield, size_t extfield_size);
void WriteMacToPacket(const uint8 *data, MessageMacs *mac);
void CheckAndUpdateTimeOfNextKeyEvent(uint64 now);
@@ -719,14 +728,12 @@ struct WgKeypair {
AesGcm128StaticContext *aes_gcm128_context_;
+ WgCompressHandler *compress_handler_;
+
// -- all up to this point is initialized to zero
// For replay detection of incoming packets
ReplayDetector replay_detector;
-#if WITH_HANDSHAKE_EXT
- // State for packet compressor
- IpzipState ipzip_state_;
-#endif // WITH_HANDSHAKE_EXT
};
void WgKeypairEncryptPayload(uint8 *dst, const size_t src_len,
@@ -737,5 +744,3 @@ bool WgKeypairDecryptPayload(uint8 *dst, const size_t src_len,
const uint8 *ad, const size_t ad_len,
const uint64 nonce, WgKeypair *keypair);
-bool WgKeypairParseExtendedHandshake(WgKeypair *keypair, const uint8 *data, size_t data_size);
-