iphlpapi stores the address in network byte order inside the memory of the DWORD, it is not a host-order integer. For 192.168.0.55 the DWORD value on x86 is 0x3700A8C0 while its bytes are C0 A8 00 37, so shifting the value by 24/16/8/0 produced 37 00 A8 C0 and the dialog rendered "55.0.168.192" for both the local and remote address. Copy the DWORD with memcpy instead, which preserves the memory layout that inet_ntop and SetTcpEntry both expect. GetAddr4 is changed the same way, otherwise a forced disconnect would rebuild a wrong address and miss the target connection. Co-Authored-By: deepseek-flash
241 lines
8.4 KiB
C++
241 lines
8.4 KiB
C++
// ConnectionsManager.cpp: implementation of the CConnectionsManager class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "ConnectionsManager.h"
|
|
#include "Common.h"
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <iphlpapi.h>
|
|
#include <tcpmib.h>
|
|
#include <udpmib.h>
|
|
#include <vector>
|
|
|
|
#pragma comment(lib, "iphlpapi.lib")
|
|
|
|
#if ENABLE_CONNECTION_MNG
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CConnectionsManager::CConnectionsManager(IOCPClient* ClientObject, int n, void* user):CManager(ClientObject)
|
|
{
|
|
SendConnectionList();
|
|
}
|
|
|
|
CConnectionsManager::~CConnectionsManager()
|
|
{
|
|
}
|
|
|
|
// 把 PID 解析成进程映像名(UTF-8)。进程可能已退出/受保护,失败时填 <unknown>。
|
|
static void ResolveProcName(DWORD pid, char* out, int outLen)
|
|
{
|
|
if (outLen <= 0) return;
|
|
out[0] = 0;
|
|
if (pid == 0) {
|
|
strcpy_s(out, outLen, "System Idle Process");
|
|
return;
|
|
}
|
|
HANDLE h = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
|
|
if (h == NULL) {
|
|
strcpy_s(out, outLen, "<unknown>");
|
|
return;
|
|
}
|
|
wchar_t wpath[MAX_PATH] = { 0 };
|
|
DWORD len = MAX_PATH;
|
|
BOOL ok = QueryFullProcessImageNameW(h, 0, wpath, &len);
|
|
CloseHandle(h);
|
|
if (!ok) {
|
|
strcpy_s(out, outLen, "<unknown>");
|
|
return;
|
|
}
|
|
wchar_t* base = wcsrchr(wpath, L'\\');
|
|
base = base ? base + 1 : wpath;
|
|
if (WideCharToMultiByte(CP_UTF8, 0, base, -1, out, outLen, NULL, NULL) <= 0) {
|
|
strcpy_s(out, outLen, "<unknown>");
|
|
return;
|
|
}
|
|
out[outLen - 1] = 0;
|
|
}
|
|
|
|
// IPv4 地址:iphlpapi 的 dwLocalAddr/dwRemoteAddr 是把网络序地址直接放在 DWORD 的**内存**里,
|
|
// 不是主机序数值(192.168.0.55 在 x86 上 DWORD 数值是 0x3700A8C0、内存字节是 C0 A8 00 37)。
|
|
// 所以只能按内存拷贝:这样得到的正是 inet_ntop 需要的网络序字节,也能原样拼回 SetTcpEntry 的 DWORD。
|
|
// 按数值移位会把字节序弄反(显示成 55.0.168.192)。
|
|
static void PutAddr4(uint8_t* out, DWORD addrNet)
|
|
{
|
|
memcpy(out, &addrNet, 4);
|
|
}
|
|
|
|
static DWORD GetAddr4(const uint8_t* addr)
|
|
{
|
|
DWORD addrNet = 0;
|
|
memcpy(&addrNet, addr, 4);
|
|
return addrNet;
|
|
}
|
|
|
|
static void AppendTcp4(std::vector<ConnectionInfo>& rows)
|
|
{
|
|
PMIB_TCPTABLE_OWNER_PID pTable = NULL;
|
|
DWORD dwSize = 0;
|
|
if (GetExtendedTcpTable(pTable, &dwSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) != ERROR_INSUFFICIENT_BUFFER)
|
|
return;
|
|
pTable = (PMIB_TCPTABLE_OWNER_PID)malloc(dwSize);
|
|
if (pTable == NULL) return;
|
|
if (GetExtendedTcpTable(pTable, &dwSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) == NO_ERROR) {
|
|
for (DWORD i = 0; i < pTable->dwNumEntries; ++i) {
|
|
const MIB_TCPROW_OWNER_PID& r = pTable->table[i];
|
|
ConnectionInfo info = { 0 };
|
|
info.proto = 1;
|
|
info.af = AF_INET;
|
|
info.pid = r.dwOwningPid;
|
|
PutAddr4(info.localAddr, r.dwLocalAddr); // 网络序 DWORD → 网络序字节
|
|
info.localPort = ntohs((uint16_t)r.dwLocalPort); // 端口网络序 → 主机序
|
|
PutAddr4(info.remoteAddr, r.dwRemoteAddr);
|
|
info.remotePort = ntohs((uint16_t)r.dwRemotePort);
|
|
info.state = r.dwState;
|
|
ResolveProcName(info.pid, info.procName, sizeof(info.procName));
|
|
rows.push_back(info);
|
|
}
|
|
}
|
|
free(pTable);
|
|
}
|
|
|
|
static void AppendTcp6(std::vector<ConnectionInfo>& rows)
|
|
{
|
|
PMIB_TCP6TABLE_OWNER_PID pTable = NULL;
|
|
DWORD dwSize = 0;
|
|
if (GetExtendedTcpTable(pTable, &dwSize, FALSE, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0) != ERROR_INSUFFICIENT_BUFFER)
|
|
return;
|
|
pTable = (PMIB_TCP6TABLE_OWNER_PID)malloc(dwSize);
|
|
if (pTable == NULL) return;
|
|
if (GetExtendedTcpTable(pTable, &dwSize, FALSE, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0) == NO_ERROR) {
|
|
for (DWORD i = 0; i < pTable->dwNumEntries; ++i) {
|
|
const MIB_TCP6ROW_OWNER_PID& r = pTable->table[i];
|
|
ConnectionInfo info = { 0 };
|
|
info.proto = 1;
|
|
info.af = AF_INET6;
|
|
info.pid = r.dwOwningPid;
|
|
memcpy(info.localAddr, r.ucLocalAddr, 16);
|
|
info.localPort = ntohs((uint16_t)r.dwLocalPort);
|
|
memcpy(info.remoteAddr, r.ucRemoteAddr, 16);
|
|
info.remotePort = ntohs((uint16_t)r.dwRemotePort);
|
|
info.state = r.dwState;
|
|
ResolveProcName(info.pid, info.procName, sizeof(info.procName));
|
|
rows.push_back(info);
|
|
}
|
|
}
|
|
free(pTable);
|
|
}
|
|
|
|
static void AppendUdp4(std::vector<ConnectionInfo>& rows)
|
|
{
|
|
PMIB_UDPTABLE_OWNER_PID pTable = NULL;
|
|
DWORD dwSize = 0;
|
|
if (GetExtendedUdpTable(pTable, &dwSize, FALSE, AF_INET, UDP_TABLE_OWNER_PID, 0) != ERROR_INSUFFICIENT_BUFFER)
|
|
return;
|
|
pTable = (PMIB_UDPTABLE_OWNER_PID)malloc(dwSize);
|
|
if (pTable == NULL) return;
|
|
if (GetExtendedUdpTable(pTable, &dwSize, FALSE, AF_INET, UDP_TABLE_OWNER_PID, 0) == NO_ERROR) {
|
|
for (DWORD i = 0; i < pTable->dwNumEntries; ++i) {
|
|
const MIB_UDPROW_OWNER_PID& r = pTable->table[i];
|
|
ConnectionInfo info = { 0 };
|
|
info.proto = 2;
|
|
info.af = AF_INET;
|
|
info.pid = r.dwOwningPid;
|
|
PutAddr4(info.localAddr, r.dwLocalAddr);
|
|
info.localPort = ntohs((uint16_t)r.dwLocalPort);
|
|
info.state = 0;
|
|
ResolveProcName(info.pid, info.procName, sizeof(info.procName));
|
|
rows.push_back(info);
|
|
}
|
|
}
|
|
free(pTable);
|
|
}
|
|
|
|
static void AppendUdp6(std::vector<ConnectionInfo>& rows)
|
|
{
|
|
PMIB_UDP6TABLE_OWNER_PID pTable = NULL;
|
|
DWORD dwSize = 0;
|
|
if (GetExtendedUdpTable(pTable, &dwSize, FALSE, AF_INET6, UDP_TABLE_OWNER_PID, 0) != ERROR_INSUFFICIENT_BUFFER)
|
|
return;
|
|
pTable = (PMIB_UDP6TABLE_OWNER_PID)malloc(dwSize);
|
|
if (pTable == NULL) return;
|
|
if (GetExtendedUdpTable(pTable, &dwSize, FALSE, AF_INET6, UDP_TABLE_OWNER_PID, 0) == NO_ERROR) {
|
|
for (DWORD i = 0; i < pTable->dwNumEntries; ++i) {
|
|
const MIB_UDP6ROW_OWNER_PID& r = pTable->table[i];
|
|
ConnectionInfo info = { 0 };
|
|
info.proto = 2;
|
|
info.af = AF_INET6;
|
|
info.pid = r.dwOwningPid;
|
|
memcpy(info.localAddr, r.ucLocalAddr, 16);
|
|
info.localPort = ntohs((uint16_t)r.dwLocalPort);
|
|
info.state = 0;
|
|
ResolveProcName(info.pid, info.procName, sizeof(info.procName));
|
|
rows.push_back(info);
|
|
}
|
|
}
|
|
free(pTable);
|
|
}
|
|
|
|
VOID CConnectionsManager::SendConnectionList()
|
|
{
|
|
std::vector<ConnectionInfo> rows;
|
|
AppendTcp4(rows);
|
|
AppendTcp6(rows);
|
|
AppendUdp4(rows);
|
|
AppendUdp6(rows);
|
|
|
|
size_t count = rows.size();
|
|
if (count > 0xFFFF) count = 0xFFFF;
|
|
ULONG bufLen = 1 + 2 + (ULONG)(count * sizeof(ConnectionInfo));
|
|
LPBYTE szBuffer = (LPBYTE)LocalAlloc(LPTR, bufLen);
|
|
if (szBuffer == NULL) return;
|
|
szBuffer[0] = TOKEN_CONNECTION_LIST;
|
|
uint16_t cnt = (uint16_t)count;
|
|
memcpy(szBuffer + 1, &cnt, 2);
|
|
for (size_t i = 0; i < count; ++i)
|
|
memcpy(szBuffer + 3 + i * sizeof(ConnectionInfo), &rows[i], sizeof(ConnectionInfo));
|
|
|
|
HttpMask mask(DEFAULT_HOST, m_ClientObject->GetClientIPHeader());
|
|
m_ClientObject->Send2Server((char*)szBuffer, bufLen, &mask);
|
|
LocalFree(szBuffer);
|
|
}
|
|
|
|
void CConnectionsManager::KillConnection(const ConnectionInfo& info)
|
|
{
|
|
// 仅 IPv4 TCP 有公开 API 可强制断开(SetTcpEntry + DELETE_TCB)。
|
|
if (info.proto != 1 || info.af != AF_INET) return;
|
|
|
|
MIB_TCPROW row = { 0 };
|
|
row.dwState = MIB_TCP_STATE_DELETE_TCB;
|
|
row.dwLocalAddr = GetAddr4(info.localAddr); // 网络序字节 → 网络序 DWORD
|
|
row.dwLocalPort = (DWORD)htons(info.localPort); // 主机序端口 → 网络序
|
|
row.dwRemoteAddr = GetAddr4(info.remoteAddr);
|
|
row.dwRemotePort = (DWORD)htons(info.remotePort);
|
|
SetTcpEntry(&row);
|
|
}
|
|
|
|
VOID CConnectionsManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
|
|
{
|
|
switch (szBuffer[0]) {
|
|
case COMMAND_CONNECTION: // 刷新
|
|
SendConnectionList();
|
|
break;
|
|
case COMMAND_KILL_CONNECTION: // 强制断开
|
|
if (ulLength >= 1 + sizeof(ConnectionInfo)) {
|
|
ConnectionInfo info;
|
|
memcpy(&info, szBuffer + 1, sizeof(ConnectionInfo));
|
|
KillConnection(info);
|
|
}
|
|
SendConnectionList();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif
|