diff --git a/network_win32.cpp b/network_win32.cpp index 389fc38..9c67b0a 100644 --- a/network_win32.cpp +++ b/network_win32.cpp @@ -2072,8 +2072,8 @@ void TunsafeBackendWin32::CollectStats() { stats_ = runner_->wg_proc_.GetStats(); float data[2] = { // unit is megabits/second - stats_.tun_bytes_in_per_second * (1.0f / 125000), - stats_.tun_bytes_out_per_second * (1.0f / 125000), + stats_.data_bytes_out_per_second * (1.0f / 125000), + stats_.data_bytes_in_per_second * (1.0f / 125000), }; stats_collector_.AddSamples(data); stats_mutex_.Release(); diff --git a/tunsafe_win32.cpp b/tunsafe_win32.cpp index a34db5a..21928ba 100644 --- a/tunsafe_win32.cpp +++ b/tunsafe_win32.cpp @@ -163,14 +163,14 @@ public: InvalidatePaintbox(); char buf[64]; - uint32 mbs_in = (uint32)(stats.tun_bytes_out_per_second * (1.0 / 1250)); - uint32 gb_in = (uint32)(stats.tun_bytes_out * (1.0 / (1024 * 1024 * 1024 / 100))); + uint32 mbs_in = (uint32)(stats.data_bytes_in_per_second * (1.0 / 1250)); + uint32 gb_in = (uint32)(stats.data_bytes_in * (1.0 / (1024 * 1024 * 1024 / 100))); snprintf(buf, ARRAYSIZE(buf), "D: %d.%.2d Mbps (%d.%.2d GB)", mbs_in / 100, mbs_in % 100, gb_in / 100, gb_in % 100); SendMessage(hwndStatus, SB_SETTEXT, 1, (LPARAM)buf); - uint32 mbs_out = (uint32)(stats.tun_bytes_in_per_second * (1.0 / 1250)); - uint32 gb_out = (uint32)(stats.tun_bytes_in * (1.0 / (1024 * 1024 * 1024 / 100))); + uint32 mbs_out = (uint32)(stats.data_bytes_out_per_second * (1.0 / 1250)); + uint32 gb_out = (uint32)(stats.data_bytes_out * (1.0 / (1024 * 1024 * 1024 / 100))); snprintf(buf, ARRAYSIZE(buf), "U: %d.%.2d Mbps (%d.%.2d GB)", mbs_out / 100, mbs_out % 100, gb_out / 100, gb_out % 100); SendMessage(hwndStatus, SB_SETTEXT, 2, (LPARAM)buf); @@ -1521,6 +1521,7 @@ static const AdvancedTextInfo ADVANCED_TEXT_INFOS[] = { {Y + 19 * 4, 66, ""}, {Y + 19 * 5, 66, "Overhead:"}, {Y + 19 * 6, 66, "Packet Loss:"}, + {Y + 19 * 7, 66, "Invalid:"}, #undef Y }; @@ -1576,8 +1577,8 @@ static const char *GetAdvancedInfoValue(char buffer[256], int i) { case 2: snprintf(buffer, 256, "%s in (%lld packets), %s out (%lld packets)", - PrintMB(tmp, ps->udp_bytes_in), ps->udp_packets_in, - PrintMB(tmp2, ps->udp_bytes_out), ps->udp_packets_out/*, udp_qsize2 - udp_qsize1, g_tun_reads*/); + PrintMB(tmp, ps->total_bytes_in), ps->packets_in, + PrintMB(tmp2, ps->total_bytes_out), ps->packets_out/*, udp_qsize2 - udp_qsize1, g_tun_reads*/); return buffer; case 3: return PrintLastHandshakeAt(buffer, ps); case 4: { @@ -1587,11 +1588,11 @@ static const char *GetAdvancedInfoValue(char buffer[256], int i) { return buffer; } case 5: { - uint64 overhead_in = ps->udp_bytes_in + ps->udp_packets_in * 40 - ps->tun_bytes_out; - uint32 overhead_in_pct = ps->tun_bytes_out ? (uint32)(overhead_in * 100000 / ps->tun_bytes_out) : 0; + uint64 overhead_in = ps->total_bytes_in + ps->packets_in * 40 - ps->data_bytes_in; + uint32 overhead_in_pct = ps->data_bytes_in ? (uint32)(overhead_in * 100000 / ps->data_bytes_in) : 0; - uint64 overhead_out = ps->udp_bytes_out + ps->udp_packets_out * 40 - ps->tun_bytes_in; - uint32 overhead_out_pct = ps->tun_bytes_in ? (uint32)(overhead_out * 100000 / ps->tun_bytes_in) : 0; + uint64 overhead_out = ps->total_bytes_out + ps->packets_out * 40 - ps->data_bytes_out; + uint32 overhead_out_pct = ps->data_bytes_out ? (uint32)(overhead_out * 100000 / ps->data_bytes_out) : 0; snprintf(buffer, 256, "%d.%.3d%% in, %d.%.3d%% out", overhead_in_pct / 1000, overhead_in_pct % 1000, overhead_out_pct / 1000, overhead_out_pct % 1000); @@ -1603,6 +1604,10 @@ static const char *GetAdvancedInfoValue(char buffer[256], int i) { (int)(ps->lost_packets_tot - ps->lost_packets_valid)); return buffer; } + case 7: { + snprintf(buffer, 256, "%s in (%lld packets)", PrintMB(tmp, ps->invalid_bytes_in), ps->invalid_packets_in); + return buffer; + } default: return ""; } } diff --git a/wireguard.cpp b/wireguard.cpp index 2a8581f..05f0400 100644 --- a/wireguard.cpp +++ b/wireguard.cpp @@ -344,8 +344,6 @@ void WireguardProcessor::HandleTunPacket(Packet *packet) { void WireguardProcessor::HandleUdpPacket(Packet *packet, bool overload) { PacketResult result = HandleUdpPacket2(packet, overload); if (result == kPacketResult_ForwardTun) { - //stats_.tun_bytes_out += size_from_header; - //stats_.tun_packets_out++; tun_->WriteTunPacket(packet); } else if (result == kPacketResult_ForwardUdp) { udp_->WriteUdpPacket(packet); @@ -441,9 +439,6 @@ WireguardProcessor::PacketResult WireguardProcessor::WriteAndEncryptPacketToUdp_ } assert(!peer->marked_for_delete_); - stats_.tun_bytes_in += size; - stats_.tun_packets_in++; - want_handshake = (send_ctr >= REKEY_AFTER_MESSAGES || keypair->send_key_state == WgKeypair::KEY_WANT_REFRESH); keypair->send_ctr = send_ctr + 1; @@ -563,8 +558,9 @@ need_big_packet: if (want_handshake) peer->ScheduleNewHandshake(); - stats_.udp_packets_out++; - stats_.udp_bytes_out += packet->size; + stats_.packets_out++; + stats_.data_bytes_out += orig_size; + stats_.total_bytes_out += packet->size; return kPacketResult_ForwardUdp; @@ -577,8 +573,8 @@ void WireguardProcessor::PrepareOutgoingHandshakePacket(WgPeer *peer, Packet *pa assert(dev_.IsMainThread()); if (dev_.plugin_) dev_.plugin_->OnOutgoingHandshakePacket(peer, packet); - stats_.udp_packets_out++; - stats_.udp_bytes_out += packet->size; + stats_.packets_out++; + stats_.total_bytes_out += packet->size; } void WireguardProcessor::RunAllMainThreadScheduled() { @@ -666,9 +662,6 @@ WireguardProcessor::PacketResult WireguardProcessor::HandleUdpPacket2(Packet *pa uint32 type; assert(packet->protocol != 0xCD && (uint16)packet->addr.sin.sin_family != 0xCDCD); // catch msvc uninit mem - stats_.udp_bytes_in += packet->size; - stats_.udp_packets_in++; - if (packet->size < sizeof(uint32)) goto invalid_size; type = ReadLE32((uint32*)packet->data); @@ -707,6 +700,8 @@ WireguardProcessor::PacketResult WireguardProcessor::HandleUdpPacket2(Packet *pa } else { // unknown packet invalid_size: + stats_.invalid_packets_in++; + stats_.invalid_bytes_in += packet->size; return kPacketResult_Free; } } @@ -819,8 +814,7 @@ WireguardProcessor::PacketResultd WireguardProcessor::HandleShortHeaderFormatPac keypair->can_use_short_key_for_outgoing = (ack_tag & WG_ACK_HEADER_KEY_MASK) * WG_SHORT_HEADER_KEY_ID; packet->data = data; - packet->size = bytes_left - keypair->auth_tag_length; - return HandleAuthenticatedDataPacket_WillUnlock(keypair, packet); + return HandleAuthenticatedDataPacket_WillUnlock(keypair, packet, bytes_left - keypair->auth_tag_length); getout_unlock: WG_RELEASE_LOCK(keypair->peer->mutex_); getout: @@ -840,7 +834,7 @@ void WireguardProcessor::NotifyHandshakeComplete() { procdel_->OnConnected(); } -WireguardProcessor::PacketResult WireguardProcessor::HandleAuthenticatedDataPacket_WillUnlock(WgKeypair *keypair, Packet *packet) { +WireguardProcessor::PacketResult WireguardProcessor::HandleAuthenticatedDataPacket_WillUnlock(WgKeypair *keypair, Packet *packet, uint data_size) { WgPeer *peer = keypair->peer; assert(peer->IsPeerLocked()); assert(packet->addr.sin.sin_family != 0); @@ -865,7 +859,7 @@ WireguardProcessor::PacketResult WireguardProcessor::HandleAuthenticatedDataPack } } - WG_EXTENSION_HOOKS::OnPeerIncomingUdp(peer, packet); + WG_EXTENSION_HOOKS::OnPeerIncomingUdp(peer, packet, data_size); // Remember how many incoming packets we've seen so we can approximate loss keypair->incoming_packet_count++; @@ -886,11 +880,12 @@ WireguardProcessor::PacketResult WireguardProcessor::HandleAuthenticatedDataPack peer->ScheduleNewHandshake(); } - uint32 data_size = packet->size; if (data_size == 0) { peer->OnKeepaliveReceived(); WG_RELEASE_LOCK(peer->mutex_); - goto getout; + stats_.packets_in++; + stats_.total_bytes_in += packet->size; + return kPacketResult_Free; } peer->OnDataReceived(); WG_RELEASE_LOCK(peer->mutex_); @@ -899,7 +894,7 @@ WireguardProcessor::PacketResult WireguardProcessor::HandleAuthenticatedDataPack if (WITH_PACKET_COMPRESSION && keypair->compress_handler_) { WgCompressHandler::CompressState st = keypair->compress_handler_->Decompress(packet); if (st == WgCompressHandler::COMPRESS_FAIL) - goto getout; + goto getout_error_header; if (st == WgCompressHandler::COMPRESS_YES) stats_.compression_hdr_saved_in += (int32)(packet->size - exch(data_size, packet->size)); } @@ -943,13 +938,18 @@ WireguardProcessor::PacketResult WireguardProcessor::HandleAuthenticatedDataPack if (size_from_header > data_size) goto getout_error_header; + stats_.packets_in++; + stats_.data_bytes_in += size_from_header; + stats_.total_bytes_in += packet->size; + packet->size = size_from_header; - + return kPacketResult_ForwardTun; getout_error_header: stats_.error_header++; -getout: + stats_.invalid_packets_in++; + stats_.invalid_bytes_in += packet->size; return kPacketResult_Free; } @@ -963,12 +963,14 @@ WireguardProcessor::PacketResult WireguardProcessor::HandleDataPacket(Packet *pa WgKeypair *keypair = dev_.LookupKeypairByKeyId(key_id); if (keypair == NULL || counter >= REJECT_AFTER_MESSAGES) { stats_.error_key_id++; -getout: + getout: + stats_.invalid_packets_in++; + stats_.invalid_bytes_in += data_size; return kPacketResult_Free; } packet->data = data + sizeof(MessageData); - packet->size = data_size - sizeof(MessageData) - keypair->auth_tag_length; + uint32 data_size_after = data_size - sizeof(MessageData) - keypair->auth_tag_length; if (!WgKeypairDecryptPayload(data + sizeof(MessageData), data_size - sizeof(MessageData), NULL, 0, counter, keypair)) { @@ -988,7 +990,7 @@ getout: goto getout; } else { assert(!keypair->peer->marked_for_delete_); - return HandleAuthenticatedDataPacket_WillUnlock(keypair, packet); + return HandleAuthenticatedDataPacket_WillUnlock(keypair, packet, data_size_after); } } @@ -1003,8 +1005,12 @@ static uint64 GetIpForRateLimit(Packet *packet) { WireguardProcessor::PacketResult WireguardProcessor::CheckIncomingHandshakeRateLimit(Packet *packet, bool overload) { assert(dev_.IsMainThread()); WgRateLimit::RateLimitResult rr = dev_.rate_limiter()->CheckRateLimit(GetIpForRateLimit(packet)); - if ((overload && rr.is_rate_limited()) || !dev_.CheckCookieMac1(packet)) + + if ((overload && rr.is_rate_limited()) || !dev_.CheckCookieMac1(packet)) { + stats_.invalid_packets_in++; + stats_.invalid_bytes_in += packet->size; return kPacketResult_Free; + } dev_.rate_limiter()->CommitResult(rr); if (overload && !rr.is_first_ip() && !dev_.CheckCookieMac2(packet)) { @@ -1021,11 +1027,20 @@ WireguardProcessor::PacketResult WireguardProcessor::CheckIncomingHandshakeRateL // server receives this when client wants to setup a session WireguardProcessor::PacketResult WireguardProcessor::HandleHandshakeInitiationPacket(Packet *packet) { assert(dev_.IsMainThread()); + uint original_size = packet->size; WgPeer *peer = WgPeer::ParseMessageHandshakeInitiation(&dev_, packet); if (peer) { PrepareOutgoingHandshakePacket(peer, packet); + + stats_.packets_in++; + stats_.packets_out++; + stats_.total_bytes_in += original_size; + stats_.total_bytes_out += packet->size; + return kPacketResult_ForwardUdp; } else { + stats_.invalid_packets_in++; + stats_.invalid_bytes_in += original_size; return kPacketResult_Free; } } @@ -1033,14 +1048,21 @@ WireguardProcessor::PacketResult WireguardProcessor::HandleHandshakeInitiationPa // client receives this after session is established WireguardProcessor::PacketResult WireguardProcessor::HandleHandshakeResponsePacket(Packet *packet) { assert(dev_.IsMainThread()); + uint original_size = packet->size; WgPeer *peer = WgPeer::ParseMessageHandshakeResponse(&dev_, packet); if (peer) { + stats_.packets_in++; + stats_.total_bytes_in += original_size; + stats_.handshakes_out_success++; WG_SCOPED_LOCK(peer->mutex_); peer->OnHandshakeAuthComplete(); peer->OnHandshakeFullyComplete(); NotifyHandshakeComplete(); SendKeepalive_Locked(peer); + } else { + stats_.invalid_packets_in++; + stats_.invalid_bytes_in += original_size; } return kPacketResult_Free; } @@ -1093,19 +1115,16 @@ void WireguardProcessor::SecondLoop() { assert(dev_.IsMainThread()); uint64 now = OsGetMilliseconds(); - uint64 bytes_in = stats_.tun_bytes_in - stats_last_bytes_in_; - uint64 bytes_out = stats_.tun_bytes_out - stats_last_bytes_out_; - - stats_last_bytes_in_ = stats_.tun_bytes_in; - stats_last_bytes_out_ = stats_.tun_bytes_out; + uint64 bytes_out = stats_.data_bytes_out - exch(stats_last_bytes_out_, stats_.data_bytes_out); + uint64 bytes_in = stats_.data_bytes_in - exch(stats_last_bytes_in_, stats_.data_bytes_in); uint64 millis = now - stats_last_ts_; stats_last_ts_ = now; double f = 1000.0 / std::max((uint32)millis, 500); - stats_.tun_bytes_in_per_second = (float)(bytes_in * f); - stats_.tun_bytes_out_per_second = (float)(bytes_out * f); + stats_.data_bytes_out_per_second = (float)(bytes_out * f); + stats_.data_bytes_in_per_second = (float)(bytes_in * f); for (WgPeer *peer = dev_.first_peer(); peer; peer = peer->next_peer_) { WgKeypair *keypair = peer->curr_keypair_; diff --git a/wireguard.h b/wireguard.h index 5f16834..cb9b045 100644 --- a/wireguard.h +++ b/wireguard.h @@ -7,14 +7,18 @@ // todo: for multithreaded use case need to use atomic ops. struct WgProcessorStats { - // Number of bytes sent/received over the physical UDP connection - uint64 udp_bytes_in, udp_bytes_out; - uint64 udp_packets_in, udp_packets_out; + // The amount of authenticated data received over the wireguard connection. + uint64 packets_in, data_bytes_in, total_bytes_in; - // Number of valid packets sent/received over the TUN interface - uint64 tun_bytes_in, tun_bytes_out; - uint64 tun_packets_in, tun_packets_out; + // The amount of authenticated data sent across the wireguard connection. + // |data_bytes_out| holds the actual bytes, while |total_bytes_out| + // includes wireguard overhead. + uint64 packets_out, data_bytes_out, total_bytes_out; + // The amount of invalid data received from the network + uint64 invalid_packets_in, invalid_bytes_in; + + // Error types uint32 error_key_id; uint32 error_mac; @@ -22,8 +26,8 @@ struct WgProcessorStats { uint32 error_source_addr; uint32 error_header; - // Current speed of TUN packets - float tun_bytes_in_per_second, tun_bytes_out_per_second; + // Current speed + float data_bytes_out_per_second, data_bytes_in_per_second; // Timestamp of handshakes uint64 first_complete_handshake_timestamp; @@ -143,7 +147,7 @@ private: PacketResult HandleHandshakeCookiePacket(Packet *packet); PacketResult HandleDataPacket(Packet *packet); - PacketResult HandleAuthenticatedDataPacket_WillUnlock(WgKeypair *keypair, Packet *packet); + PacketResult HandleAuthenticatedDataPacket_WillUnlock(WgKeypair *keypair, Packet *packet, uint data_size); PacketResult HandleShortHeaderFormatPacket(uint32 tag, Packet *packet); PacketResult CheckIncomingHandshakeRateLimit(Packet *packet, bool overload); bool HandleIcmpv6NeighborSolicitation(const byte *data, size_t data_size); diff --git a/wireguard_proto.cpp b/wireguard_proto.cpp index 51b37b7..8b6264e 100644 --- a/wireguard_proto.cpp +++ b/wireguard_proto.cpp @@ -794,7 +794,7 @@ WgPeer *WgPeer::ParseMessageHandshakeResponse(WgDevice *dev, const Packet *packe peer->data_endpoint_ = peer->endpoint_; } - WG_EXTENSION_HOOKS::OnPeerIncomingUdp(peer, packet); + WG_EXTENSION_HOOKS::OnPeerIncomingUdp(peer, packet, packet->size); peer->rx_bytes_ += packet->size; peer->InsertKeypairInPeer_Locked(keypair); diff --git a/wireguard_proto.h b/wireguard_proto.h index 5cdd9e1..5b169f3 100644 --- a/wireguard_proto.h +++ b/wireguard_proto.h @@ -819,7 +819,7 @@ bool WgKeypairDecryptPayload(uint8 *dst, const size_t src_len, struct WgExtensionHooksDefault { static uint32 GetIpv4Target(Packet *packet, uint8 *data) { return ReadBE32(data + 16); } - static void OnPeerIncomingUdp(WgPeer *peer, const Packet *packet) { } + static void OnPeerIncomingUdp(WgPeer *peer, const Packet *packet, uint data_size) { } static void OnPeerOutgoingUdp(WgPeer *peer, Packet *packet) { } static bool DisableSourceAddressVerification(WgPeer *peer) { return false; } };