189 lines
4.9 KiB
C
189 lines
4.9 KiB
C
/*
|
|
* Process Hacker Extra Plugins -
|
|
* Network Extras Plugin
|
|
*
|
|
* Copyright (C) 2016 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 "main.h"
|
|
#include "maxminddb.h"
|
|
|
|
BOOLEAN GeoDbLoaded = FALSE;
|
|
static MMDB_s GeoDb = { 0 };
|
|
|
|
// Copied from mstcpip.h (due to PH-SDK conflicts).
|
|
// Note: Ipv6 versions are already available from ws2ipdef.h and did not need copying.
|
|
|
|
#define INADDR_ANY (ULONG)0x00000000
|
|
#define INADDR_LOOPBACK 0x7f000001
|
|
|
|
FORCEINLINE
|
|
BOOLEAN
|
|
IN4_IS_ADDR_UNSPECIFIED(_In_ CONST IN_ADDR *a)
|
|
{
|
|
return (BOOLEAN)(a->s_addr == INADDR_ANY);
|
|
}
|
|
|
|
FORCEINLINE
|
|
BOOLEAN
|
|
IN4_IS_ADDR_LOOPBACK(_In_ CONST IN_ADDR *a)
|
|
{
|
|
return (BOOLEAN)(*((PUCHAR)a) == 0x7f); // 127/8
|
|
}
|
|
// end copy from mstcpip.h
|
|
|
|
|
|
VOID LoadGeoLiteDb(VOID)
|
|
{
|
|
PPH_STRING directory;
|
|
PPH_STRING path;
|
|
|
|
directory = PH_AUTO(PhGetApplicationDirectory());
|
|
path = PhaCreateString(DATABASE_PATH);
|
|
path = PH_AUTO(PhConcatStringRef2(&directory->sr, &path->sr));
|
|
|
|
if (MMDB_open(path->Buffer, MMDB_MODE_MMAP, &GeoDb) == MMDB_SUCCESS)
|
|
{
|
|
time_t systemTime;
|
|
|
|
// Query the current time
|
|
time(&systemTime);
|
|
|
|
// Check if the Geoip database is older than 6 months (182 days = approx. 6 months).
|
|
if ((systemTime - GeoDb.metadata.build_epoch) > (182 * 24 * 60 * 60))
|
|
{
|
|
// TODO: Warn about old database...
|
|
}
|
|
|
|
if (GeoDb.metadata.ip_version == 6)
|
|
{
|
|
// Database includes ipv6 entires.
|
|
}
|
|
|
|
GeoDbLoaded = TRUE;
|
|
}
|
|
}
|
|
|
|
VOID FreeGeoLiteDb(VOID)
|
|
{
|
|
if (GeoDbLoaded)
|
|
{
|
|
MMDB_close(&GeoDb);
|
|
}
|
|
}
|
|
|
|
BOOLEAN LookupCountryCode(
|
|
_In_ PH_IP_ADDRESS RemoteAddress,
|
|
_Out_ PPH_STRING* CountryCode,
|
|
_Out_ PPH_STRING* CountryName
|
|
)
|
|
{
|
|
PPH_STRING countryCode = NULL;
|
|
PPH_STRING countryName = NULL;
|
|
MMDB_entry_data_s mmdb_entry;
|
|
MMDB_lookup_result_s mmdb_lookup;
|
|
INT mmdb_error = 0;
|
|
|
|
if (!GeoDbLoaded)
|
|
return FALSE;
|
|
|
|
if (RemoteAddress.Type == PH_IPV4_NETWORK_TYPE)
|
|
{
|
|
SOCKADDR_IN ipv4SockAddr;
|
|
|
|
if (IN4_IS_ADDR_UNSPECIFIED(&RemoteAddress.InAddr))
|
|
return FALSE;
|
|
|
|
if (IN4_IS_ADDR_LOOPBACK(&RemoteAddress.InAddr))
|
|
return FALSE;
|
|
|
|
memset(&ipv4SockAddr, 0, sizeof(SOCKADDR_IN));
|
|
memset(&mmdb_lookup, 0, sizeof(MMDB_lookup_result_s));
|
|
|
|
ipv4SockAddr.sin_family = AF_INET;
|
|
ipv4SockAddr.sin_addr = RemoteAddress.InAddr;
|
|
|
|
mmdb_lookup = MMDB_lookup_sockaddr(
|
|
&GeoDb,
|
|
(struct sockaddr*)&ipv4SockAddr,
|
|
&mmdb_error
|
|
);
|
|
}
|
|
else
|
|
{
|
|
SOCKADDR_IN6 ipv6SockAddr;
|
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&RemoteAddress.In6Addr))
|
|
return FALSE;
|
|
|
|
if (IN6_IS_ADDR_LOOPBACK(&RemoteAddress.In6Addr))
|
|
return FALSE;
|
|
|
|
memset(&ipv6SockAddr, 0, sizeof(SOCKADDR_IN6));
|
|
memset(&mmdb_lookup, 0, sizeof(MMDB_lookup_result_s));
|
|
|
|
ipv6SockAddr.sin6_family = AF_INET6;
|
|
ipv6SockAddr.sin6_addr = RemoteAddress.In6Addr;
|
|
|
|
mmdb_lookup = MMDB_lookup_sockaddr(
|
|
&GeoDb,
|
|
(struct sockaddr*)&ipv6SockAddr,
|
|
&mmdb_error
|
|
);
|
|
}
|
|
|
|
if (mmdb_error == 0 && mmdb_lookup.found_entry)
|
|
{
|
|
memset(&mmdb_entry, 0, sizeof(MMDB_entry_data_s));
|
|
|
|
if (MMDB_get_value(&mmdb_lookup.entry, &mmdb_entry, "country", "iso_code", NULL) == MMDB_SUCCESS)
|
|
{
|
|
if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING)
|
|
{
|
|
countryCode = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size);
|
|
}
|
|
}
|
|
|
|
if (MMDB_get_value(&mmdb_lookup.entry, &mmdb_entry, "country", "names", "en", NULL) == MMDB_SUCCESS)
|
|
{
|
|
if (mmdb_entry.has_data && mmdb_entry.type == MMDB_DATA_TYPE_UTF8_STRING)
|
|
{
|
|
countryName = PhConvertUtf8ToUtf16Ex((PCHAR)mmdb_entry.utf8_string, mmdb_entry.data_size);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (countryCode && countryName)
|
|
{
|
|
*CountryCode = countryCode;
|
|
*CountryName = countryName;
|
|
return TRUE;
|
|
}
|
|
|
|
if (countryCode)
|
|
{
|
|
PhDereferenceObject(countryCode);
|
|
}
|
|
|
|
if (countryName)
|
|
{
|
|
PhDereferenceObject(countryName);
|
|
}
|
|
|
|
return FALSE;
|
|
} |