Files
SimpleRemoter/server/2015Remote/DateVerify.h
2025-12-17 22:04:35 +01:00

213 lines
5.9 KiB
C++

#pragma once
#include <iostream>
#include <ctime>
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32.lib")
// 中国大陆优化的NTP服务器列表
const char* CN_NTP_SERVERS[] = {
"ntp.aliyun.com",
"time1.aliyun.com",
"ntp1.tencent.com",
"time.edu.cn",
"ntp.tuna.tsinghua.edu.cn",
"cn.ntp.org.cn",
};
const int CN_NTP_COUNT = sizeof(CN_NTP_SERVERS) / sizeof(CN_NTP_SERVERS[0]);
const int NTP_PORT = 123;
const uint64_t NTP_EPOCH_OFFSET = 2208988800ULL;
// 检测程序是否处于试用期
class DateVerify
{
private:
bool m_hasVerified = false;
bool m_lastVerifyResult = true;
time_t m_lastVerifyLocalTime = 0;
time_t m_lastNetworkTime = 0;
static const int VERIFY_INTERVAL = 6 * 3600; // 6小时
// 初始化Winsock
bool initWinsock()
{
WSADATA wsaData;
return WSAStartup(MAKEWORD(2, 2), &wsaData) == 0;
}
// 从指定NTP服务器获取时间
time_t getTimeFromServer(const char* server)
{
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET) return 0;
sockaddr_in serverAddr{};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(NTP_PORT);
// 解析主机名
hostent* host = gethostbyname(server);
if (!host) {
closesocket(sock);
return 0;
}
serverAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr_list[0]);
// 设置超时
DWORD timeout = 2000; // 2秒超时
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
// 准备NTP请求包
char ntpPacket[48] = { 0 };
ntpPacket[0] = 0x1B; // LI=0, VN=3, Mode=3
// 发送请求
if (sendto(sock, ntpPacket, sizeof(ntpPacket), 0,
(sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
closesocket(sock);
return 0;
}
// 接收响应
if (recv(sock, ntpPacket, sizeof(ntpPacket), 0) <= 0) {
closesocket(sock);
return 0;
}
closesocket(sock);
// 解析NTP时间
uint32_t ntpTime = ntohl(*((uint32_t*)(ntpPacket + 40)));
return ntpTime - NTP_EPOCH_OFFSET;
}
// 获取网络时间(尝试多个服务器)
time_t getNetworkTimeInChina()
{
if (!initWinsock()) return 0;
time_t result = 0;
for (int i = 0; i < CN_NTP_COUNT && result == 0; i++) {
result = getTimeFromServer(CN_NTP_SERVERS[i]);
if (result != 0) {
break;
}
}
WSACleanup();
return result;
}
// 将月份缩写转换为数字(1-12)
int monthAbbrevToNumber(const std::string& month)
{
static const std::map<std::string, int> months = {
{"Jan", 1}, {"Feb", 2}, {"Mar", 3}, {"Apr", 4},
{"May", 5}, {"Jun", 6}, {"Jul", 7}, {"Aug", 8},
{"Sep", 9}, {"Oct", 10}, {"Nov", 11}, {"Dec", 12}
};
auto it = months.find(month);
return (it != months.end()) ? it->second : 0;
}
// 解析__DATE__字符串为tm结构
tm parseCompileDate(const char* compileDate)
{
tm tmCompile = { 0 };
std::string monthStr(compileDate, 3);
std::string dayStr(compileDate + 4, 2);
std::string yearStr(compileDate + 7, 4);
tmCompile.tm_year = std::stoi(yearStr) - 1900;
tmCompile.tm_mon = monthAbbrevToNumber(monthStr) - 1;
tmCompile.tm_mday = std::stoi(dayStr);
return tmCompile;
}
// 计算两个日期之间的天数差
int daysBetweenDates(const tm& date1, const tm& date2)
{
auto timeToTimePoint = [](const tm& tmTime) {
std::time_t tt = mktime(const_cast<tm*>(&tmTime));
return std::chrono::system_clock::from_time_t(tt);
};
auto tp1 = timeToTimePoint(date1);
auto tp2 = timeToTimePoint(date2);
auto duration = tp1 > tp2 ? tp1 - tp2 : tp2 - tp1;
return std::chrono::duration_cast<std::chrono::hours>(duration).count() / 24;
}
// 获取当前日期
tm getCurrentDate()
{
std::time_t now = std::time(nullptr);
tm tmNow = *std::localtime(&now);
tmNow.tm_hour = 0;
tmNow.tm_min = 0;
tmNow.tm_sec = 0;
return tmNow;
}
// 验证本地日期是否被修改
bool isLocalDateModified()
{
time_t currentLocalTime = time(nullptr);
// 检查是否可以使用缓存
if (m_hasVerified) {
time_t localElapsed = currentLocalTime - m_lastVerifyLocalTime;
// 本地时间在合理范围内前进,使用缓存推算
if (localElapsed >= 0 && localElapsed < VERIFY_INTERVAL) {
time_t estimatedNetworkTime = m_lastNetworkTime + localElapsed;
double diffDays = difftime(estimatedNetworkTime, currentLocalTime) / 86400.0;
if (fabs(diffDays) <= 1.0) {
return false;
}
}
}
// 执行网络验证
time_t networkTime = getNetworkTimeInChina();
if (networkTime == 0) {
// 网络不可用:如果之前验证通过且本地时间没异常,暂时信任
if (m_hasVerified && !m_lastVerifyResult) {
time_t localElapsed = currentLocalTime - m_lastVerifyLocalTime;
if (localElapsed >= -300 && localElapsed < 24 * 3600) {
return false;
}
}
return true;
}
// 更新缓存
m_hasVerified = true;
m_lastVerifyLocalTime = currentLocalTime;
m_lastNetworkTime = networkTime;
double diffDays = difftime(networkTime, currentLocalTime) / 86400.0;
m_lastVerifyResult = fabs(diffDays) > 1.0;
return m_lastVerifyResult;
}
public:
bool isTrail(int trailDays=7)
{
if (isLocalDateModified())
return false;
tm tmCompile = parseCompileDate(__DATE__), tmCurrent = getCurrentDate();
// 计算天数差
int daysDiff = daysBetweenDates(tmCompile, tmCurrent);
return daysDiff <= trailDays;
}
};