2025-05-13 19:45:22 +03:00

423 lines
14 KiB
C

/*
* Process Hacker Network Tools -
* output dialog
*
* Copyright (C) 2010-2015 wj32
* Copyright (C) 2012-2015 dmex
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nettools.h"
static RECT MinimumSize = { -1, -1, -1, -1 };
INT_PTR CALLBACK NetworkOutputDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PNETWORK_OUTPUT_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = (PNETWORK_OUTPUT_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PNETWORK_OUTPUT_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
{
PhSaveWindowPlacementToSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg);
PhDeleteLayoutManager(&context->LayoutManager);
if (context->ProcessHandle)
{
// Terminate the child process.
PhTerminateProcess(context->ProcessHandle, STATUS_SUCCESS);
// Close the child process handle.
NtClose(context->ProcessHandle);
}
// Close the pipe handle.
if (context->PipeReadHandle)
NtClose(context->PipeReadHandle);
RemoveProp(hwndDlg, L"Context");
PhFree(context);
PostQuitMessage(0);
}
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
PH_RECTANGLE windowRectangle;
context->WindowHandle = hwndDlg;
context->OutputHandle = GetDlgItem(hwndDlg, IDC_NETOUTPUTEDIT);
PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
PhAddLayoutItem(&context->LayoutManager, context->OutputHandle, NULL, PH_ANCHOR_ALL);
PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_MORE_INFO), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);
PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_RIGHT);
windowRectangle.Position = PhGetIntegerPairSetting(SETTING_NAME_TRACERT_WINDOW_POSITION);
windowRectangle.Size = PhGetScalableIntegerPairSetting(SETTING_NAME_TRACERT_WINDOW_SIZE, TRUE).Pair;
if (MinimumSize.left == -1)
{
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = 190;
rect.bottom = 120;
MapDialogRect(hwndDlg, &rect);
MinimumSize = rect;
MinimumSize.left = 0;
}
// Check for first-run default position.
if (windowRectangle.Position.X == 0 || windowRectangle.Position.Y == 0)
{
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
}
else
{
PhLoadWindowPlacementFromSetting(SETTING_NAME_TRACERT_WINDOW_POSITION, SETTING_NAME_TRACERT_WINDOW_SIZE, hwndDlg);
}
if (context->IpAddress.Type == PH_IPV4_NETWORK_TYPE)
{
RtlIpv4AddressToString(&context->IpAddress.InAddr, context->IpAddressString);
}
else
{
RtlIpv6AddressToString(&context->IpAddress.In6Addr, context->IpAddressString);
}
switch (context->Action)
{
case NETWORK_ACTION_TRACEROUTE:
{
HANDLE dialogThread = INVALID_HANDLE_VALUE;
Static_SetText(context->WindowHandle,
PhaFormatString(L"Tracing route to %s...", context->IpAddressString)->Buffer
);
if (dialogThread = PhCreateThread(0, NetworkTracertThreadStart, (PVOID)context))
NtClose(dialogThread);
}
break;
case NETWORK_ACTION_WHOIS:
{
HANDLE dialogThread = INVALID_HANDLE_VALUE;
Static_SetText(context->WindowHandle,
PhaFormatString(L"Whois %s...", context->IpAddressString)->Buffer
);
ShowWindow(GetDlgItem(hwndDlg, IDC_MORE_INFO), SW_SHOW);
if (dialogThread = PhCreateThread(0, NetworkWhoisThreadStart, (PVOID)context))
NtClose(dialogThread);
}
break;
case NETWORK_ACTION_PATHPING:
{
HANDLE dialogThread = INVALID_HANDLE_VALUE;
Static_SetText(context->WindowHandle,
PhaFormatString(L"Pathing route to %s...", context->IpAddressString)->Buffer
);
if (dialogThread = PhCreateThread(0, NetworkTracertThreadStart, (PVOID)context))
NtClose(dialogThread);
}
break;
}
}
break;
case WM_COMMAND:
{
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDCANCEL:
case IDOK:
DestroyWindow(hwndDlg);
break;
}
}
break;
case WM_SIZE:
PhLayoutManagerLayout(&context->LayoutManager);
break;
case WM_SIZING:
PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);
break;
case WM_CTLCOLORDLG:
case WM_CTLCOLORSTATIC:
{
HDC hDC = (HDC)wParam;
HWND hwndChild = (HWND)lParam;
// Check if old graph colors are enabled.
if (!PhGetIntegerSetting(L"GraphColorMode"))
break;
// Check for our edit control and change the color.
if (hwndChild == context->OutputHandle)
{
// Set a transparent background for the control backcolor.
//SetBkMode(hDC, TRANSPARENT);
// Set the Edit control background.
SetBkColor(hDC, RGB(0x0, 0x0, 0x0));
// Set text color as the Green PH graph text color.
SetTextColor(hDC, RGB(124, 252, 0));
// Set a black control backcolor.
return (INT_PTR)GetStockBrush(BLACK_BRUSH);
}
}
break;
case WM_NOTIFY:
{
switch (((LPNMHDR)lParam)->code)
{
case NM_CLICK:
case NM_RETURN:
{
PNMLINK syslink = (PNMLINK)lParam;
if (syslink->hdr.idFrom == IDC_MORE_INFO)
{
PhShellExecute(
PhMainWndHandle,
PhaConcatStrings2(L"http://wq.apnic.net/apnic-bin/whois.pl?searchtext=", context->IpAddressString)->Buffer,
NULL
);
}
}
break;
}
}
break;
case NTM_RECEIVEDTRACE:
{
OEM_STRING inputString;
UNICODE_STRING convertedString;
PH_STRING_BUILDER receivedString;
if (wParam != 0)
{
inputString.Buffer = (PCHAR)lParam;
inputString.Length = (USHORT)wParam;
if (NT_SUCCESS(RtlOemStringToUnicodeString(&convertedString, &inputString, TRUE)))
{
PPH_STRING windowText = NULL;
PhInitializeStringBuilder(&receivedString, PAGE_SIZE);
// Get the current output text.
windowText = PhGetWindowText(context->OutputHandle);
// Append the current output text to the New string.
if (!PhIsNullOrEmptyString(windowText))
PhAppendStringBuilder(&receivedString, &windowText->sr);
PhAppendFormatStringBuilder(&receivedString, L"%s", convertedString.Buffer);
// Remove leading newlines.
if (receivedString.String->Length >= 2 * 2 &&
receivedString.String->Buffer[0] == '\r' &&
receivedString.String->Buffer[1] == '\n')
{
PhRemoveStringBuilder(&receivedString, 0, 2);
}
SetWindowText(context->OutputHandle, receivedString.String->Buffer);
SendMessage(
context->OutputHandle,
EM_SETSEL,
receivedString.String->Length / 2 - 1,
receivedString.String->Length / 2 - 1
);
SendMessage(context->OutputHandle, WM_VSCROLL, SB_BOTTOM, 0);
PhDereferenceObject(windowText);
PhDeleteStringBuilder(&receivedString);
RtlFreeUnicodeString(&convertedString);
}
}
}
break;
case NTM_RECEIVEDWHOIS:
{
OEM_STRING inputString;
UNICODE_STRING convertedString;
PH_STRING_BUILDER receivedString;
if (lParam != 0)
{
inputString.Buffer = (PCHAR)lParam;
inputString.Length = (USHORT)wParam;
if (NT_SUCCESS(RtlOemStringToUnicodeString(&convertedString, &inputString, TRUE)))
{
USHORT i;
PhInitializeStringBuilder(&receivedString, PAGE_SIZE);
// Convert carriage returns.
for (i = 0; i < convertedString.Length; i++)
{
if (convertedString.Buffer[i] == '\n')
{
PhAppendStringBuilder2(&receivedString, L"\r\n");
}
else
{
PhAppendCharStringBuilder(&receivedString, convertedString.Buffer[i]);
}
}
// Remove leading newlines.
if (receivedString.String->Length >= 2 * 2 &&
receivedString.String->Buffer[0] == '\r' &&
receivedString.String->Buffer[1] == '\n')
{
PhRemoveStringBuilder(&receivedString, 0, 2);
}
SetWindowText(context->OutputHandle, receivedString.String->Buffer);
SendMessage(
context->OutputHandle,
EM_SETSEL,
receivedString.String->Length / 2 - 1,
receivedString.String->Length / 2 - 1
);
SendMessage(context->OutputHandle, WM_VSCROLL, SB_TOP, 0);
PhDeleteStringBuilder(&receivedString);
RtlFreeUnicodeString(&convertedString);
}
PhFree((PVOID)lParam);
}
}
break;
case NTM_RECEIVEDFINISH:
{
PPH_STRING windowText = PhGetWindowText(context->WindowHandle);
if (windowText)
{
Static_SetText(
context->WindowHandle,
PhaFormatString(L"%s Finished.", windowText->Buffer)->Buffer
);
PhDereferenceObject(windowText);
}
}
break;
}
return FALSE;
}
NTSTATUS PhNetworkOutputDialogThreadStart(
_In_ PVOID Parameter
)
{
BOOL result;
MSG message;
HWND windowHandle;
PH_AUTO_POOL autoPool;
PNETWORK_OUTPUT_CONTEXT context = (PNETWORK_OUTPUT_CONTEXT)Parameter;
PhInitializeAutoPool(&autoPool);
windowHandle = CreateDialogParam(
(HINSTANCE)PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_OUTPUT),
PhMainWndHandle,
NetworkOutputDlgProc,
(LPARAM)Parameter
);
ShowWindow(windowHandle, SW_SHOW);
SetForegroundWindow(windowHandle);
while (result = GetMessage(&message, NULL, 0, 0))
{
if (result == -1)
break;
if (!IsDialogMessage(context->WindowHandle, &message))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
PhDrainAutoPool(&autoPool);
}
PhDeleteAutoPool(&autoPool);
return STATUS_SUCCESS;
}
VOID PerformNetworkAction(
_In_ PH_NETWORK_ACTION Action,
_In_ PPH_NETWORK_ITEM NetworkItem
)
{
HANDLE dialogThread = INVALID_HANDLE_VALUE;
PNETWORK_OUTPUT_CONTEXT context;
context = (PNETWORK_OUTPUT_CONTEXT)PhAllocate(sizeof(NETWORK_OUTPUT_CONTEXT));
memset(context, 0, sizeof(NETWORK_OUTPUT_CONTEXT));
context->Action = Action;
context->NetworkItem = NetworkItem;
context->IpAddress = NetworkItem->RemoteEndpoint.Address;
if (context->Action == NETWORK_ACTION_PING)
{
if (dialogThread = PhCreateThread(0, PhNetworkPingDialogThreadStart, (PVOID)context))
NtClose(dialogThread);
}
else
{
if (dialogThread = PhCreateThread(0, PhNetworkOutputDialogThreadStart, (PVOID)context))
NtClose(dialogThread);
}
}