mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-05-08 14:33:23 +00:00
* refactor: move business logic from servers model * refactor: move containersModel initialization * refactor: added protocol ui controller and removed settings class from protocols model * refactor: moved cli management to separate controller * refactor: moved app split to separate controller * refactor: moved site split to separate controller * refactor: moved allowed dns to separate controller * refactor: moved language logic to separate ui controller * refactor: removed Settings from devices model * refactor: moved configs and services api logit to separate core controller * refactor: added a layer with a repository between the storage and controllers * refactor: use child parent system instead of smart pointers for controllers and models initialization * refactor: moved install functions from server controller to install controller * refactor: install controller refactoring * chore: renamed exportController to exportUiController * refactor: separate export controller * refactor: removed VpnConfigurationsController * chore: renamed ServerController to SshSession * refactor: replaced ServerController to SshSession * chore: moved qml controllers to separate folder * chore: include fixes * chore: moved utils from core root to core/utils * chore: include fixes * chore: rename core/utils files to camelCase foramt * chore: include fixes * chore: moved some utils to api and selfhosted folders * chore: include fixes * chore: remove unused file * chore: moved serialization folder to core/utils * chore: include fixes * chore: moved some files from client root to core/utils * chore: include fixes * chore: moved ui utils to ui/utils folder * chore: include fixes * chore: move utils from root to ui/utils * chore: include fixes * chore: moved configurators to core/configurators * chore: include fixes * refactor: moved iap logic from ui controller to core * refactor: moved remaining core logic from ApiConfigsController to SubscriptionController * chore: rename apiNewsController to apiNewsUiController * refactor: moved core logic from news ui controller to core * chore: renamed apiConfigsController to subscriptionUiController * chore: include fixes * refactor: merge ApiSettingsController with SubscriptionUiController * chore: moved ui selfhosted controllers to separate folder * chore: include fixes * chore: rename connectionController to connectiomUiController * refactor: moved core logic from connectionUiController * chore: rename settingsController to settingsUiController * refactor: move core logic from settingsUiController * refactor: moved core controller signal/slot connections to separate class * fix: newsController fixes after refactoring * chore: rename model to camelCase * chore: include fixes * chore: remove unused code * chore: move selfhosted core to separate folder * chore: include fixes * chore: rename importController to importUiController * refactor: move core logic from importUiController * chore: minor fixes * chore: remove prem v1 migration * refactor: remove openvpn over cloak and openvpn over shadowsocks * refactor: removed protocolsForContainer function * refactor: add core models * refactor: replace json with c++ structs for server config * refactor: move getDnsPair to ServerConfigUtils * feat: add admin selfhosted config export test * feat: add multi import test * refactor: use coreController for tests * feat: add few simple tests * chore: qrepos in all core controllers * feat: add test for settings * refactor: remove repo dependency from configurators * chore: moved protocols to core folder * chore: include fixes * refactor: moved containersDefs, defs, apiDefs, protocolsDefs to different places * chore: include fixes * chore: build fixes * chore: build fixes * refactor: remove q repo and interface repo * feat: add test for ui servers model and controller * chore: renamed to camelCase * chore: include fixes * refactor: moved core logic from sites ui controller * fix: fixed api config processing * fix: fixed processed server index processing * refactor: protocol models now use c++ structs instead of json configs * refactor: servers model now use c++ struct instead of json config * fix: fixed default server index processing * fix: fix logs init * fix: fix secure settings load keys * chore: build fixes * fix: fixed clear settings * fix: fixed restore backup * fix: sshSession usage * fix: fixed export functions signatures * fix: return missing part from buildContainerWorker * fix: fixed server description on page home * refactor: add container config helpers functions * refactor: c++ structs instead of json * chore: add dns protocol config struct * refactor: move config utils functions to config structs * feat: add test for selfhosted server setup * refactor: separate resources.qrc * fix: fixed server rename * chore: return nameOverriddenByUser * fix: build fixes * fix: fixed models init * refactor: cleanup models usage * fix: fixed models init * chore: cleanup connections and functions signatures * chore: cleanup updateModel calls * feat: added cache to servers repo * chore: cleanup unused functions * chore: ssxray processing * chore: remove transportProtoWithDefault and portWithDefault functions * chore: removed proto types any and l2tp * refactor: moved some constants * fix: fixed native configs export * refactor: remove json from processConfigWith functions * fix: fixed processed server index usage * fix: qml warning fixes * chore: merge fixes * chore: update tests * fix: fixed xray config processing * fix: fixed split tunneling processing * chore: rename sites controllers and model * chore: rename fixes * chore: minor fixes * chore: remove ability to load backup from "file with connection settings" button * fix: fixed api device revoke * fix: remove full model update when renaming a user * fix: fixed premium/free server rename * fix: fixed selfhosted new server install * fix: fixed updateContainer function * fix: fixed revoke for external premium configs * feat: add native configs qr processing * chore: codestyle fixes * fix: fixed admin config create * chore: again remove ability to load backup from "file with connection settings" button * chore: minor fixes * fix: fixed variables initialization * fix: fixed qml imports * fix: minor fixes * fix: fix vpnConnection function calls * feat: add buckup error handling * fix: fixed admin config revok * fix: fixed selfhosted awg installation * fix: ad visability * feat: add empty check for primary dns * chore: minor fixes
571 lines
18 KiB
C++
571 lines
18 KiB
C++
#include "router_win.h"
|
|
|
|
#include <string>
|
|
#include <tlhelp32.h>
|
|
#include <tchar.h>
|
|
|
|
#include <QProcess>
|
|
#include <QtConcurrent>
|
|
|
|
#include <core/utils/networkUtilities.h>
|
|
|
|
LONG (NTAPI * NtSuspendProcess)(HANDLE ProcessHandle) = NULL;
|
|
LONG (NTAPI * NtResumeProcess)(HANDLE ProcessHandle) = NULL;
|
|
|
|
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
|
|
|
|
QList<QString> RouterWin::kIpv6Subnets = { "fc00::/7", "2000::/4", "3000::/4" };
|
|
|
|
RouterWin &RouterWin::Instance()
|
|
{
|
|
static RouterWin s;
|
|
BOOL ok;
|
|
ok = s.InitNtFunctions();
|
|
if (!ok) qDebug() << "RouterWin::Instance failed to InitNtFunctions";
|
|
|
|
ok = s.EnableDebugPrivilege();
|
|
if (!ok) qDebug() << "RouterWin::Instance failed to EnableDebugPrivilege";
|
|
|
|
return s;
|
|
}
|
|
|
|
int RouterWin::routeAddList(const QString &gw, const QStringList &ips)
|
|
{
|
|
// qDebug().noquote() << QString("ROUTE ADD List: IPs size:%1, GW: %2")
|
|
// .arg(ips.size())
|
|
// .arg(gw);
|
|
|
|
// qDebug().noquote() << QString("ROUTE ADD List: IPs:\n%1")
|
|
// .arg(ips.join("\n"));
|
|
|
|
|
|
if (!NetworkUtilities::checkIPv4Format(gw)) {
|
|
qCritical().noquote() << "Trying to add invalid route, gw: " << gw;
|
|
return 0;
|
|
}
|
|
|
|
PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
|
|
DWORD dwSize = 0;
|
|
BOOL bOrder = FALSE;
|
|
DWORD dwStatus = 0;
|
|
|
|
|
|
// Find out how big our buffer needs to be.
|
|
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
|
if (dwStatus == ERROR_INSUFFICIENT_BUFFER) {
|
|
// Allocate the memory for the table
|
|
if (!(pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc(dwSize))) {
|
|
qDebug() << "Malloc failed. Out of memory.";
|
|
return 0;
|
|
}
|
|
// Now get the table.
|
|
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
|
}
|
|
|
|
if (dwStatus != ERROR_SUCCESS) {
|
|
qDebug() << "getIpForwardTable failed.";
|
|
if (pIpForwardTable)
|
|
free(pIpForwardTable);
|
|
return 0;
|
|
}
|
|
|
|
int success_count = 0;
|
|
MIB_IPFORWARDROW ipfrow;
|
|
|
|
ipfrow.dwForwardPolicy = 0;
|
|
ipfrow.dwForwardAge = INFINITE;
|
|
|
|
ipfrow.dwForwardNextHop = inet_addr(gw.toStdString().c_str());
|
|
ipfrow.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT; /* XXX - next hop != final dest */
|
|
ipfrow.dwForwardProto = MIB_IPPROTO_NETMGMT; /* XXX - MIB_PROTO_NETMGMT */
|
|
|
|
// Set iface for route
|
|
IPAddr dwGwAddr = inet_addr(gw.toStdString().c_str());
|
|
if (GetBestInterface(dwGwAddr, &ipfrow.dwForwardIfIndex) != NO_ERROR) {
|
|
qDebug() << "Router::routeAddList : GetBestInterface failed";
|
|
return false;
|
|
}
|
|
|
|
// Get TAP iface metric to set it for new routes
|
|
MIB_IPINTERFACE_ROW tap_iface;
|
|
InitializeIpInterfaceEntry(&tap_iface);
|
|
tap_iface.InterfaceIndex = ipfrow.dwForwardIfIndex;
|
|
tap_iface.Family = AF_INET;
|
|
dwStatus = GetIpInterfaceEntry(&tap_iface);
|
|
if (dwStatus == NO_ERROR){
|
|
ipfrow.dwForwardMetric1 = tap_iface.Metric + 1;
|
|
}
|
|
else {
|
|
qDebug() << "Router::routeAddList: failed GetIpInterfaceEntry(), Error:" << dwStatus;
|
|
ipfrow.dwForwardMetric1 = 256;
|
|
}
|
|
ipfrow.dwForwardMetric2 = 0;
|
|
ipfrow.dwForwardMetric3 = 0;
|
|
ipfrow.dwForwardMetric4 = 0;
|
|
ipfrow.dwForwardMetric5 = 0;
|
|
|
|
for (int i = 0; i < ips.size(); ++i) {
|
|
QString ipWithMask = ips.at(i);
|
|
QString ip = NetworkUtilities::ipAddressFromIpWithSubnet(ipWithMask);
|
|
|
|
if (!NetworkUtilities::checkIPv4Format(ip)) {
|
|
qCritical().noquote() << "Critical, trying to add invalid route, ip: " << ip;
|
|
continue;
|
|
}
|
|
|
|
QString mask = NetworkUtilities::netMaskFromIpWithSubnet(ipWithMask);
|
|
|
|
// address
|
|
ipfrow.dwForwardDest = inet_addr(ip.toStdString().c_str());
|
|
|
|
// mask
|
|
in_addr maskAddr;
|
|
inet_pton(AF_INET, mask.toStdString().c_str(), &maskAddr);
|
|
ipfrow.dwForwardMask = maskAddr.S_un.S_addr;
|
|
|
|
dwStatus = CreateIpForwardEntry(&ipfrow);
|
|
if (dwStatus == NO_ERROR){
|
|
m_ipForwardRows.insert(ip, ipfrow);
|
|
success_count++;
|
|
}
|
|
else if (dwStatus == ERROR_OBJECT_ALREADY_EXISTS) {
|
|
m_ipForwardRows.insert(ip, ipfrow);
|
|
success_count++;
|
|
qDebug() << "Router::routeAdd: warning, route already exist:" << ip << gw;
|
|
}
|
|
else {
|
|
qDebug() << "Router::routeAdd: failed CreateIpForwardEntry(), Error:" << ip << gw << dwStatus;
|
|
}
|
|
}
|
|
|
|
// Free resources
|
|
if (pIpForwardTable)
|
|
free(pIpForwardTable);
|
|
|
|
qDebug() << "Router::routeAddList finished, success: " << success_count << "/" << ips.size();
|
|
|
|
if (m_ipForwardRows.size() > 500) suspendWcmSvc(true);
|
|
|
|
return success_count;
|
|
}
|
|
|
|
bool RouterWin::clearSavedRoutes()
|
|
{
|
|
if (m_ipForwardRows.isEmpty()) return true;
|
|
|
|
qDebug() << "RouterWin::clearSavedRoutes forward rows size:" << m_ipForwardRows.size();
|
|
|
|
// Declare and initialize variables
|
|
PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
|
|
DWORD dwSize = 0;
|
|
BOOL bOrder = FALSE;
|
|
DWORD dwStatus = 0;
|
|
|
|
// Find out how big our buffer needs to be.
|
|
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
|
if (dwStatus == ERROR_INSUFFICIENT_BUFFER) {
|
|
// Allocate the memory for the table
|
|
if (!(pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc(dwSize))) {
|
|
qDebug() << "Router::clearSavedRoutes : Malloc failed. Out of memory";
|
|
return false;
|
|
}
|
|
// Now get the table.
|
|
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
|
}
|
|
|
|
if (dwStatus != ERROR_SUCCESS) {
|
|
qDebug() << "Router::clearSavedRoutes : getIpForwardTable failed";
|
|
if (pIpForwardTable)
|
|
free(pIpForwardTable);
|
|
|
|
return false;
|
|
}
|
|
|
|
int removed_count = 0;
|
|
for (auto i = m_ipForwardRows.begin(); i != m_ipForwardRows.end(); ++i) {
|
|
dwStatus = DeleteIpForwardEntry(&i.value());
|
|
|
|
if (dwStatus != ERROR_SUCCESS) {
|
|
qDebug() << "Router::clearSavedRoutes : Could not delete old row" << i.key();
|
|
}
|
|
else removed_count++;
|
|
}
|
|
|
|
if (pIpForwardTable)
|
|
free(pIpForwardTable);
|
|
|
|
qDebug() << "Router::clearSavedRoutes : removed routes:" << removed_count << "of" << m_ipForwardRows.size();
|
|
m_ipForwardRows.clear();
|
|
|
|
suspendWcmSvc(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
int RouterWin::routeDeleteList(const QString &gw, const QStringList &ips)
|
|
{
|
|
// qDebug().noquote() << QString("ROUTE DELETE List: IPs size:%1, GW: %2")
|
|
// .arg(ips.size())
|
|
// .arg(gw);
|
|
|
|
// qDebug().noquote() << QString("ROUTE DELETE List: IPs:\n%1")
|
|
// .arg(ips.join("\n"));
|
|
|
|
PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
|
|
DWORD dwSize = 0;
|
|
BOOL bOrder = FALSE;
|
|
DWORD dwStatus = 0;
|
|
ULONG gw_addr = inet_addr(gw.toStdString().c_str());
|
|
|
|
// Find out how big our buffer needs to be.
|
|
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
|
if (dwStatus == ERROR_INSUFFICIENT_BUFFER) {
|
|
// Allocate the memory for the table
|
|
if (!(pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc(dwSize))) {
|
|
qDebug() << "Malloc failed. Out of memory.";
|
|
return 0;
|
|
}
|
|
// Now get the table.
|
|
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
|
}
|
|
|
|
if (dwStatus != ERROR_SUCCESS) {
|
|
qDebug() << "getIpForwardTable failed.";
|
|
if (pIpForwardTable)
|
|
free(pIpForwardTable);
|
|
return 0;
|
|
}
|
|
|
|
int success_count = 0;
|
|
|
|
QMap<ULONG, QPair<QString,ULONG>> ipMap;
|
|
for (int i = 0; i < ips.size(); ++i) {
|
|
QString ipMask = ips.at(i);
|
|
if (ipMask.isEmpty()) continue;
|
|
QString ip = NetworkUtilities::ipAddressFromIpWithSubnet(ipMask);
|
|
QString mask = NetworkUtilities::netMaskFromIpWithSubnet(ipMask);
|
|
|
|
if (ip.isEmpty()) continue;
|
|
|
|
in_addr maskAddr;
|
|
inet_pton(AF_INET, mask.toStdString().c_str(), &maskAddr);
|
|
|
|
ipMap.insert(inet_addr(ip.toStdString().c_str()), qMakePair(ipMask, maskAddr.S_un.S_addr));
|
|
}
|
|
|
|
for (int i = 0; i < (int) pIpForwardTable->dwNumEntries; i++) {
|
|
MIB_IPFORWARDROW ipfrow = pIpForwardTable->table[i];
|
|
|
|
if(ipMap.contains(ipfrow.dwForwardDest) &&
|
|
ipMap.value(ipfrow.dwForwardDest).second == ipfrow.dwForwardMask &&
|
|
ipfrow.dwForwardNextHop == gw_addr) {
|
|
dwStatus = DeleteIpForwardEntry(&pIpForwardTable->table[i]);
|
|
if (dwStatus == ERROR_SUCCESS) {
|
|
m_ipForwardRows.remove(ipMap.value(ipfrow.dwForwardDest).first);
|
|
success_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Free resources
|
|
if (pIpForwardTable)
|
|
free(pIpForwardTable);
|
|
|
|
qDebug() << "Router::routeDeleteList finished, success: " << success_count << "/" << ips.size();
|
|
|
|
return success_count;
|
|
}
|
|
|
|
bool RouterWin::flushDns()
|
|
{
|
|
QProcess p;
|
|
p.setProcessChannelMode(QProcess::MergedChannels);
|
|
QString command = QString("ipconfig /flushdns");
|
|
|
|
p.start(command);
|
|
p.waitForFinished();
|
|
return true;
|
|
//qDebug().noquote() << "OUTPUT ipconfig /flushdns: " + p.readAll();
|
|
}
|
|
|
|
void RouterWin::resetIpStack()
|
|
{
|
|
// {
|
|
// QProcess p;
|
|
// QString command = QString("ipconfig /release");
|
|
// p.start(command);
|
|
// }
|
|
{
|
|
QProcess p;
|
|
QString command = QString("netsh int ip reset");
|
|
p.start(command);
|
|
p.waitForFinished();
|
|
}
|
|
{
|
|
QProcess p;
|
|
QString command = QString("netsh winsock reset");
|
|
p.start(command);
|
|
p.waitForFinished();
|
|
}
|
|
}
|
|
|
|
bool RouterWin::createTun(const QString &dev, const QString &subnet)
|
|
{
|
|
NET_LUID luid;
|
|
DWORD res = ConvertInterfaceAliasToLuid(reinterpret_cast<const wchar_t*>(dev.utf16()), &luid);
|
|
if (res != NO_ERROR) {
|
|
qCritical() << "Failed to convert luid: " << res;
|
|
return false;
|
|
}
|
|
|
|
HANDLE hEvent = CreateEvent(nullptr, true, false, nullptr);
|
|
if (!hEvent) {
|
|
qCritical() << "Failed to allocate event object";
|
|
return false;
|
|
}
|
|
auto _guardEvent = qScopeGuard([hEvent](){ CloseHandle(hEvent); });
|
|
|
|
struct {
|
|
HANDLE hEvent;
|
|
NET_LUID luid;
|
|
const QString &subnet;
|
|
bool found;
|
|
} ctx = { .hEvent = hEvent, .luid = luid, .subnet = subnet, .found = false };
|
|
|
|
auto cb = [](void *priv, MIB_UNICASTIPADDRESS_ROW *row, MIB_NOTIFICATION_TYPE NotificationType) {
|
|
auto* c = reinterpret_cast<decltype(ctx)*>(priv);
|
|
if (row != nullptr && row->InterfaceLuid.Value == c->luid.Value && row->Address.si_family == AF_INET) {
|
|
char ip[INET_ADDRSTRLEN];
|
|
inet_ntop(row->Address.Ipv4.sin_family, &row->Address.Ipv4.sin_addr, ip, INET_ADDRSTRLEN);
|
|
if (c->subnet == ip) {
|
|
c->found = true;
|
|
SetEvent(c->hEvent);
|
|
}
|
|
}
|
|
};
|
|
|
|
HANDLE hNotif;
|
|
res = NotifyUnicastIpAddressChange(AF_INET, cb, &ctx, false, &hNotif);
|
|
if (res != NO_ERROR) {
|
|
qCritical() << "Failed to subscribe to interface change";
|
|
return false;
|
|
}
|
|
auto _guardNotif = qScopeGuard([hNotif](){ CancelMibChangeNotify2(hNotif); });
|
|
|
|
MIB_UNICASTIPADDRESS_ROW row;
|
|
InitializeUnicastIpAddressEntry(&row);
|
|
|
|
row.InterfaceLuid = luid;
|
|
row.Address.si_family = AF_INET;
|
|
|
|
inet_pton(AF_INET, subnet.toStdString().c_str(), &row.Address.Ipv4.sin_addr);
|
|
|
|
row.OnLinkPrefixLength = 32;
|
|
row.ValidLifetime = 0xffffffff;
|
|
row.PreferredLifetime = 0xffffffff;
|
|
row.DadState = IpDadStatePreferred;
|
|
|
|
res = CreateUnicastIpAddressEntry(&row);
|
|
if (res != NO_ERROR && res != ERROR_OBJECT_ALREADY_EXISTS) {
|
|
qDebug() << "Failed to create IP address:" << res;
|
|
return false;
|
|
}
|
|
|
|
res = WaitForSingleObject(hEvent, 10000);
|
|
if (res == WAIT_TIMEOUT) {
|
|
qCritical() << "Timeout of waiting for IP assignment for " << dev << " device";
|
|
return false;
|
|
}
|
|
|
|
return ctx.found;
|
|
}
|
|
|
|
void RouterWin::suspendWcmSvc(bool suspend)
|
|
{
|
|
if (suspend == m_suspended) return;
|
|
|
|
// Solve Windows bug (routes > 1000)
|
|
DWORD wcmSvcPid = GetServicePid(std::wstring(L"wcmSvc").c_str());
|
|
|
|
//ListProcessThreads(wcmSvcPid);
|
|
BOOL ok = SuspendProcess(suspend, wcmSvcPid);
|
|
if (ok) {
|
|
m_suspended = suspend;
|
|
}
|
|
|
|
qDebug() << "RouterWin::routeAddList" <<
|
|
(ok ? "succeed to" : "failed to") <<
|
|
(suspend ? "suspend wcmSvc" : "resume wcmSvc");
|
|
|
|
}
|
|
|
|
DWORD RouterWin::GetServicePid(LPCWSTR serviceName)
|
|
{
|
|
const auto hScm = OpenSCManagerW(nullptr, nullptr, NULL);
|
|
const auto hSc = OpenServiceW(hScm, serviceName, SERVICE_QUERY_STATUS);
|
|
|
|
SERVICE_STATUS_PROCESS ssp = {};
|
|
DWORD bytesNeeded = 0;
|
|
QueryServiceStatusEx(hSc, SC_STATUS_PROCESS_INFO, reinterpret_cast<LPBYTE>(&ssp), sizeof(ssp), &bytesNeeded);
|
|
|
|
CloseServiceHandle(hSc);
|
|
CloseServiceHandle(hScm);
|
|
|
|
return ssp.dwProcessId;
|
|
}
|
|
|
|
BOOL RouterWin::ListProcessThreads( DWORD dwOwnerPID )
|
|
{
|
|
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
|
|
THREADENTRY32 te32;
|
|
|
|
// Take a snapshot of all running threads
|
|
hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
|
|
if( hThreadSnap == INVALID_HANDLE_VALUE )
|
|
return( FALSE );
|
|
|
|
// Fill in the size of the structure before using it.
|
|
te32.dwSize = sizeof(THREADENTRY32);
|
|
|
|
// Retrieve information about the first thread,
|
|
// and exit if unsuccessful
|
|
if( !Thread32First( hThreadSnap, &te32 ) )
|
|
{
|
|
//printError( TEXT("Thread32First") ); // show cause of failure
|
|
CloseHandle( hThreadSnap ); // clean the snapshot object
|
|
return( FALSE );
|
|
}
|
|
|
|
// Now walk the thread list of the system,
|
|
// and display information about each thread
|
|
// associated with the specified process
|
|
//HANDLE threadHandle;
|
|
do
|
|
{
|
|
if( te32.th32OwnerProcessID == dwOwnerPID )
|
|
{
|
|
HANDLE threadHandle = OpenThread (PROCESS_QUERY_INFORMATION, FALSE, te32.th32ThreadID);
|
|
qDebug() << "OpenThread GetLastError:"<< te32.th32ThreadID << GetLastError() << threadHandle;
|
|
ULONG64 cycles = 0;
|
|
BOOL ok = QueryThreadCycleTime(threadHandle, &cycles);
|
|
qDebug() << "QueryThreadCycleTime GetLastError:" << ok << GetLastError();
|
|
|
|
qDebug() << "Thread cycles:" << te32.th32ThreadID << cycles;
|
|
// _tprintf( TEXT("\n\n THREAD ID = 0x%08X"), te32.th32ThreadID );
|
|
// _tprintf( TEXT("\n Base priority = %d"), te32.tpBasePri );
|
|
// _tprintf( TEXT("\n Delta priority = %d"), te32.tpDeltaPri );
|
|
// _tprintf( TEXT("\n"));
|
|
|
|
CloseHandle(threadHandle);
|
|
}
|
|
} while( Thread32Next(hThreadSnap, &te32 ) );
|
|
|
|
CloseHandle( hThreadSnap );
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOL RouterWin::EnableDebugPrivilege(VOID)
|
|
{
|
|
HANDLE hToken = NULL;
|
|
TOKEN_PRIVILEGES priv;
|
|
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
|
|
return FALSE;
|
|
|
|
if (!LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid))
|
|
return FALSE;
|
|
|
|
priv.PrivilegeCount = 1;
|
|
priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
return AdjustTokenPrivileges(hToken, FALSE, &priv, sizeof(priv), NULL, NULL);
|
|
}
|
|
|
|
BOOL RouterWin::InitNtFunctions(VOID)
|
|
{
|
|
HMODULE hModule;
|
|
|
|
hModule = GetModuleHandleW(L"ntdll.dll");
|
|
if (hModule == NULL)
|
|
return FALSE;
|
|
|
|
//NtSuspendProcess = (decltype(NtSuspendProcess))GetProcAddress(hModule, "NtSuspendThread");
|
|
NtSuspendProcess = (decltype(NtSuspendProcess))GetProcAddress(hModule, "NtSuspendProcess");
|
|
if (NtSuspendProcess == NULL)
|
|
return FALSE;
|
|
|
|
//NtResumeProcess = (decltype(NtResumeProcess))GetProcAddress(hModule, "NtResumeThread");
|
|
NtResumeProcess = (decltype(NtResumeProcess))GetProcAddress(hModule, "NtResumeProcess");
|
|
if (NtResumeProcess == NULL)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL RouterWin::SuspendProcess(BOOL fSuspend, DWORD dwProcessId)
|
|
{
|
|
HANDLE pHandle = OpenProcess(PROCESS_SUSPEND_RESUME, FALSE, dwProcessId);
|
|
if (pHandle == NULL) return false;
|
|
|
|
bool ok = ((fSuspend ? NtSuspendProcess : NtResumeProcess)(pHandle) == STATUS_SUCCESS);
|
|
CloseHandle(pHandle);
|
|
|
|
return ok;
|
|
}
|
|
|
|
bool RouterWin::updateResolvers(const QString& ifname, const QList<QHostAddress>& resolvers)
|
|
{
|
|
return m_dnsUtil->updateResolvers(ifname, resolvers);
|
|
}
|
|
|
|
bool RouterWin::restoreResolvers() {
|
|
return m_dnsUtil->restoreResolvers();
|
|
}
|
|
|
|
QNetworkInterface RouterWin::findLoopbackIface()
|
|
{
|
|
for (auto iface : QNetworkInterface::allInterfaces()) {
|
|
if (iface.flags() & QNetworkInterface::IsLoopBack) {
|
|
return iface;
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
bool RouterWin::StopRoutingIpv6()
|
|
{
|
|
qDebug() << "RouterWin::StopRoutingIpv6";
|
|
|
|
if (auto loopback = findLoopbackIface(); loopback.isValid()) {
|
|
QFuture<bool> res = QtConcurrent::mappedReduced(kIpv6Subnets, [loopback](const QString &subnet) -> bool {
|
|
int res = QProcess::execute("netsh", { "interface", "ipv6", "add", "route", subnet, QString("interface=%1").arg(loopback.index()), "metric=0", "store=active" });
|
|
return res == 0;
|
|
},
|
|
[](bool &result, bool success) {
|
|
result = result && success;
|
|
}, true);
|
|
|
|
res.waitForFinished();
|
|
return res.result();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool RouterWin::StartRoutingIpv6()
|
|
{
|
|
qDebug() << "RouterWin::StartRoutingIpv6";
|
|
|
|
if (auto loopback = findLoopbackIface(); loopback.isValid()) {
|
|
QFuture<bool> res = QtConcurrent::mappedReduced(kIpv6Subnets, [loopback](const QString &subnet) -> bool {
|
|
int res = QProcess::execute("netsh", { "interface", "ipv6", "delete", "route", subnet, QString("interface=%1").arg(loopback.index()) });
|
|
return res == 0;
|
|
},
|
|
[](bool &result, bool success) {
|
|
result = result && success;
|
|
}, true);
|
|
}
|
|
|
|
return false;
|
|
}
|