├── .gitignore ├── LICENSE ├── MainForm.gfm ├── MainForm.go ├── MainFormImpl.go ├── README.md ├── Sample └── sample.go ├── build ├── README.md ├── build-darwin32-GUI.sh ├── build-darwin32.sh ├── build-darwin64-GUI.sh ├── build-darwin64.sh ├── build-linux32-GUI.sh ├── build-linux32.sh ├── build-linux64-GUI.sh ├── build-linux64.sh ├── build-win32-GUI.bat ├── build-win32.bat ├── build-win64-GUI.bat ├── build-win64.bat └── rpbuild.go ├── cert ├── README.md ├── ca.der ├── ca.key ├── ca.pem ├── client.key ├── client.pem ├── server.key └── server.pem ├── conf ├── config.cfg └── confighttps.cfg ├── icon_posix.go ├── icon_windows.go ├── imgs ├── README.md ├── cli.jpg ├── rp_linux.jpg ├── rp_macOS.jpg ├── rp_windows.jpg ├── rproxy.icns ├── rproxy.ico ├── rproxy.png └── svr.jpg ├── librp ├── client.go ├── common.go ├── config.go ├── log.go ├── log_posix.go ├── log_windows.go ├── net.go ├── net_test.go └── server.go ├── lzUI ├── build.bat ├── lzUI.ico ├── lzUI.lpi ├── lzUI.lpr ├── lzUI.lps ├── lzUI.res ├── umain.lfm └── umain.pas ├── main_gui.go └── main_nogui.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | .idea 26 | /cmd 27 | /lzUI/backup 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MainForm.gfm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/MainForm.gfm -------------------------------------------------------------------------------- /MainForm.go: -------------------------------------------------------------------------------- 1 | // +build gui 2 | 3 | // 由res2go自动生成,不要编辑。 4 | package main 5 | 6 | import ( 7 | "github.com/ying32/govcl/vcl" 8 | ) 9 | 10 | type TMainForm struct { 11 | *vcl.TForm 12 | StatusBar1 *vcl.TStatusBar 13 | Panel1 *vcl.TPanel 14 | Panel2 *vcl.TPanel 15 | BtnStart *vcl.TButton 16 | BtnStop *vcl.TButton 17 | Label12 *vcl.TLabel 18 | PageControl1 *vcl.TPageControl 19 | TabSheet1 *vcl.TTabSheet 20 | RGMode *vcl.TRadioGroup 21 | GBBase *vcl.TGroupBox 22 | Label1 *vcl.TLabel 23 | Label2 *vcl.TLabel 24 | Label3 *vcl.TLabel 25 | Label7 *vcl.TLabel 26 | SpinTCPPort *vcl.TSpinEdit 27 | SpinCliHTTPPort *vcl.TSpinEdit 28 | ChkIsZip *vcl.TCheckBox 29 | EditVerifyKey *vcl.TEdit 30 | BtnRandKey *vcl.TButton 31 | BtnSaveCfg *vcl.TButton 32 | BtnLoadCfg *vcl.TButton 33 | BtnNewCfg *vcl.TButton 34 | EditSvrAddr *vcl.TEdit 35 | ChkIsHttps *vcl.TCheckBox 36 | Label8 *vcl.TLabel 37 | SpinSvrHTTPPort *vcl.TSpinEdit 38 | GBTLS *vcl.TGroupBox 39 | Panel3 *vcl.TPanel 40 | Label4 *vcl.TLabel 41 | EditTLSCAFile *vcl.TEdit 42 | BtnCAOpen *vcl.TButton 43 | PageControl2 *vcl.TPageControl 44 | TabSheet3 *vcl.TTabSheet 45 | Panel4 *vcl.TPanel 46 | Label6 *vcl.TLabel 47 | EditTLSCliKeyFile *vcl.TEdit 48 | Label5 *vcl.TLabel 49 | EditTLSCliCertFile *vcl.TEdit 50 | BtnCliCertOpen *vcl.TButton 51 | BtnCliKeyOpen *vcl.TButton 52 | TabSheet4 *vcl.TTabSheet 53 | Panel5 *vcl.TPanel 54 | Label10 *vcl.TLabel 55 | EditTLSSvrCertFile *vcl.TEdit 56 | BtnSvrCertOpen *vcl.TButton 57 | BtnSvrKeyOpen *vcl.TButton 58 | EditTLSSvrKeyFile *vcl.TEdit 59 | Label11 *vcl.TLabel 60 | GBAppSettings *vcl.TGroupBox 61 | ChkAutoReconnect *vcl.TCheckBox 62 | Label9 *vcl.TLabel 63 | SpinMaxLogLine *vcl.TSpinEdit 64 | TabSheet2 *vcl.TTabSheet 65 | LstLogs *vcl.TListBox 66 | DlgSaveCfg *vcl.TSaveDialog 67 | DlgOpen *vcl.TOpenDialog 68 | ActionList1 *vcl.TActionList 69 | ActStart *vcl.TAction 70 | ActStop *vcl.TAction 71 | TrayIcon1 *vcl.TTrayIcon 72 | 73 | //::private:: 74 | TMainFormFields 75 | } 76 | 77 | var MainForm *TMainForm 78 | 79 | 80 | 81 | 82 | // 以字节形式加载 83 | // vcl.Application.CreateForm(&MainForm) 84 | 85 | func NewMainForm(owner vcl.IComponent) (root *TMainForm) { 86 | vcl.CreateResForm(owner, &root) 87 | return 88 | } 89 | 90 | var mainFormBytes = []byte("\x54\x50\x46\x30\x09\x54\x4D\x61\x69\x6E\x46\x6F\x72\x6D\x08\x4D\x61\x69\x6E\x46\x6F\x72\x6D\x04\x4C\x65\x66\x74\x03\x89\x03\x06\x48\x65\x69\x67\x68\x74\x03\x46\x02\x03\x54\x6F\x70\x03\x20\x01\x05\x57\x69\x64\x74\x68\x03\xF2\x01\x0B\x42\x6F\x72\x64\x65\x72\x49\x63\x6F\x6E\x73\x0B\x0C\x62\x69\x53\x79\x73\x74\x65\x6D\x4D\x65\x6E\x75\x0A\x62\x69\x4D\x69\x6E\x69\x6D\x69\x7A\x65\x00\x0B\x42\x6F\x72\x64\x65\x72\x53\x74\x79\x6C\x65\x07\x08\x62\x73\x53\x69\x6E\x67\x6C\x65\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x06\x72\x70\x72\x6F\x78\x79\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x03\x46\x02\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xF2\x01\x08\x50\x6F\x73\x69\x74\x69\x6F\x6E\x07\x0E\x70\x6F\x53\x63\x72\x65\x65\x6E\x43\x65\x6E\x74\x65\x72\x0A\x4C\x43\x4C\x56\x65\x72\x73\x69\x6F\x6E\x06\x07\x32\x2E\x30\x2E\x36\x2E\x30\x00\x0A\x54\x53\x74\x61\x74\x75\x73\x42\x61\x72\x0A\x53\x74\x61\x74\x75\x73\x42\x61\x72\x31\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x03\x30\x02\x05\x57\x69\x64\x74\x68\x03\xF2\x01\x06\x50\x61\x6E\x65\x6C\x73\x0E\x00\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x06\x54\x50\x61\x6E\x65\x6C\x06\x50\x61\x6E\x65\x6C\x31\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x03\x30\x02\x03\x54\x6F\x70\x02\x00\x05\x57\x69\x64\x74\x68\x03\xF2\x01\x05\x41\x6C\x69\x67\x6E\x07\x08\x61\x6C\x43\x6C\x69\x65\x6E\x74\x0A\x42\x65\x76\x65\x6C\x4F\x75\x74\x65\x72\x07\x06\x62\x76\x4E\x6F\x6E\x65\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x03\x30\x02\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xF2\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x01\x00\x06\x54\x50\x61\x6E\x65\x6C\x06\x50\x61\x6E\x65\x6C\x32\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x02\x22\x03\x54\x6F\x70\x03\x0E\x02\x05\x57\x69\x64\x74\x68\x03\xF2\x01\x05\x41\x6C\x69\x67\x6E\x07\x08\x61\x6C\x42\x6F\x74\x74\x6F\x6D\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x02\x22\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xF2\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x00\x07\x54\x42\x75\x74\x74\x6F\x6E\x08\x42\x74\x6E\x53\x74\x61\x72\x74\x04\x4C\x65\x66\x74\x03\x46\x01\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x04\x05\x57\x69\x64\x74\x68\x02\x4B\x06\x41\x63\x74\x69\x6F\x6E\x07\x08\x41\x63\x74\x53\x74\x61\x72\x74\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x00\x00\x07\x54\x42\x75\x74\x74\x6F\x6E\x07\x42\x74\x6E\x53\x74\x6F\x70\x04\x4C\x65\x66\x74\x03\x9A\x01\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x04\x05\x57\x69\x64\x74\x68\x02\x4B\x06\x41\x63\x74\x69\x6F\x6E\x07\x07\x41\x63\x74\x53\x74\x6F\x70\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x01\x00\x00\x06\x54\x4C\x61\x62\x65\x6C\x07\x4C\x61\x62\x65\x6C\x31\x32\x04\x4C\x65\x66\x74\x02\x20\x06\x48\x65\x69\x67\x68\x74\x02\x11\x03\x54\x6F\x70\x02\x09\x05\x57\x69\x64\x74\x68\x03\x14\x01\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x45\xE6\xB3\xA8\xEF\xBC\x9A\xE5\xA6\x82\xE6\x9C\x89\xE4\xBF\xAE\xE6\x94\xB9\xE9\x85\x8D\xE7\xBD\xAE\xEF\xBC\x8C\xE9\x9C\x80\xE8\xA6\x81\xE3\x80\x90\xE4\xBF\x9D\xE5\xAD\x98\xE9\x85\x8D\xE7\xBD\xAE\xE3\x80\x91\xE5\x90\x8E\xE6\x96\xB9\xE8\x83\xBD\xE7\x94\x9F\xE6\x95\x88\xE3\x80\x82\x0A\x46\x6F\x6E\x74\x2E\x43\x6F\x6C\x6F\x72\x07\x07\x63\x6C\x47\x72\x65\x65\x6E\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x00\x0C\x54\x50\x61\x67\x65\x43\x6F\x6E\x74\x72\x6F\x6C\x0C\x50\x61\x67\x65\x43\x6F\x6E\x74\x72\x6F\x6C\x31\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x03\x0E\x02\x03\x54\x6F\x70\x02\x00\x05\x57\x69\x64\x74\x68\x03\xF2\x01\x0A\x41\x63\x74\x69\x76\x65\x50\x61\x67\x65\x07\x09\x54\x61\x62\x53\x68\x65\x65\x74\x31\x05\x41\x6C\x69\x67\x6E\x07\x08\x61\x6C\x43\x6C\x69\x65\x6E\x74\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x49\x6E\x64\x65\x78\x02\x00\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x01\x08\x4F\x6E\x43\x68\x61\x6E\x67\x65\x07\x12\x50\x61\x67\x65\x43\x6F\x6E\x74\x72\x6F\x6C\x31\x43\x68\x61\x6E\x67\x65\x00\x09\x54\x54\x61\x62\x53\x68\x65\x65\x74\x09\x54\x61\x62\x53\x68\x65\x65\x74\x31\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x19\xE6\x9C\x8D\xE5\x8A\xA1\xE7\xAB\xAF\x2F\xE5\xAE\xA2\xE6\x88\xB7\xE7\xAB\xAF\xE8\xAE\xBE\xE7\xBD\xAE\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x03\xF0\x01\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xEA\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x0B\x54\x52\x61\x64\x69\x6F\x47\x72\x6F\x75\x70\x06\x52\x47\x4D\x6F\x64\x65\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x02\x3A\x03\x54\x6F\x70\x02\x00\x05\x57\x69\x64\x74\x68\x03\xEA\x01\x05\x41\x6C\x69\x67\x6E\x07\x05\x61\x6C\x54\x6F\x70\x08\x41\x75\x74\x6F\x46\x69\x6C\x6C\x09\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x0C\xE6\xA8\xA1\xE5\xBC\x8F\xE9\x80\x89\xE6\x8B\xA9\x1C\x43\x68\x69\x6C\x64\x53\x69\x7A\x69\x6E\x67\x2E\x4C\x65\x66\x74\x52\x69\x67\x68\x74\x53\x70\x61\x63\x69\x6E\x67\x02\x06\x1D\x43\x68\x69\x6C\x64\x53\x69\x7A\x69\x6E\x67\x2E\x45\x6E\x6C\x61\x72\x67\x65\x48\x6F\x72\x69\x7A\x6F\x6E\x74\x61\x6C\x07\x18\x63\x72\x73\x48\x6F\x6D\x6F\x67\x65\x6E\x6F\x75\x73\x43\x68\x69\x6C\x64\x52\x65\x73\x69\x7A\x65\x1B\x43\x68\x69\x6C\x64\x53\x69\x7A\x69\x6E\x67\x2E\x45\x6E\x6C\x61\x72\x67\x65\x56\x65\x72\x74\x69\x63\x61\x6C\x07\x18\x63\x72\x73\x48\x6F\x6D\x6F\x67\x65\x6E\x6F\x75\x73\x43\x68\x69\x6C\x64\x52\x65\x73\x69\x7A\x65\x1C\x43\x68\x69\x6C\x64\x53\x69\x7A\x69\x6E\x67\x2E\x53\x68\x72\x69\x6E\x6B\x48\x6F\x72\x69\x7A\x6F\x6E\x74\x61\x6C\x07\x0E\x63\x72\x73\x53\x63\x61\x6C\x65\x43\x68\x69\x6C\x64\x73\x1A\x43\x68\x69\x6C\x64\x53\x69\x7A\x69\x6E\x67\x2E\x53\x68\x72\x69\x6E\x6B\x56\x65\x72\x74\x69\x63\x61\x6C\x07\x0E\x63\x72\x73\x53\x63\x61\x6C\x65\x43\x68\x69\x6C\x64\x73\x12\x43\x68\x69\x6C\x64\x53\x69\x7A\x69\x6E\x67\x2E\x4C\x61\x79\x6F\x75\x74\x07\x1D\x63\x63\x6C\x4C\x65\x66\x74\x54\x6F\x52\x69\x67\x68\x74\x54\x68\x65\x6E\x54\x6F\x70\x54\x6F\x42\x6F\x74\x74\x6F\x6D\x1B\x43\x68\x69\x6C\x64\x53\x69\x7A\x69\x6E\x67\x2E\x43\x6F\x6E\x74\x72\x6F\x6C\x73\x50\x65\x72\x4C\x69\x6E\x65\x02\x02\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x02\x24\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xE6\x01\x07\x43\x6F\x6C\x75\x6D\x6E\x73\x02\x02\x09\x49\x74\x65\x6D\x49\x6E\x64\x65\x78\x02\x00\x0D\x49\x74\x65\x6D\x73\x2E\x53\x74\x72\x69\x6E\x67\x73\x01\x06\x09\xE5\xAE\xA2\xE6\x88\xB7\xE7\xAB\xAF\x06\x09\xE6\x9C\x8D\xE5\x8A\xA1\xE7\xAB\xAF\x00\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x00\x00\x09\x54\x47\x72\x6F\x75\x70\x42\x6F\x78\x06\x47\x42\x42\x61\x73\x65\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x03\xDD\x00\x03\x54\x6F\x70\x02\x6D\x05\x57\x69\x64\x74\x68\x03\xEA\x01\x05\x41\x6C\x69\x67\x6E\x07\x08\x61\x6C\x43\x6C\x69\x65\x6E\x74\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x19\xE6\x9C\x8D\xE5\x8A\xA1\xE7\xAB\xAF\x2F\xE5\xAE\xA2\xE6\x88\xB7\xE7\xAB\xAF\xE8\xAE\xBE\xE7\xBD\xAE\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x03\xC7\x00\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xE6\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x01\x00\x06\x54\x4C\x61\x62\x65\x6C\x06\x4C\x61\x62\x65\x6C\x31\x04\x4C\x65\x66\x74\x02\x11\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x06\x05\x57\x69\x64\x74\x68\x03\xA2\x00\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x1E\xE8\xBF\x9E\xE6\x8E\xA5\xE6\x88\x96\xE7\x9B\x91\xE5\x90\xAC\xE7\x9A\x84\x54\x43\x50\xE7\xAB\xAF\xE5\x8F\xA3\xEF\xBC\x9A\x06\x4C\x61\x79\x6F\x75\x74\x07\x08\x74\x6C\x43\x65\x6E\x74\x65\x72\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x06\x54\x4C\x61\x62\x65\x6C\x06\x4C\x61\x62\x65\x6C\x32\x04\x4C\x65\x66\x74\x02\x11\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x46\x05\x57\x69\x64\x74\x68\x03\xA2\x00\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x22\xE5\xAE\xA2\xE6\x88\xB7\xE7\xAB\xAF\xE8\xBD\xAC\xE5\x8F\x91\xE7\x9A\x84\x48\x54\x54\x50\x28\x53\x29\xE7\xAB\xAF\xE5\x8F\xA3\xEF\xBC\x9A\x06\x4C\x61\x79\x6F\x75\x74\x07\x08\x74\x6C\x43\x65\x6E\x74\x65\x72\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x06\x54\x4C\x61\x62\x65\x6C\x06\x4C\x61\x62\x65\x6C\x33\x04\x4C\x65\x66\x74\x02\x13\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x03\x87\x00\x05\x57\x69\x64\x74\x68\x02\x46\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x0C\xE9\xAA\x8C\xE8\xAF\x81\x4B\x45\x59\xEF\xBC\x9A\x06\x4C\x61\x79\x6F\x75\x74\x07\x08\x74\x6C\x43\x65\x6E\x74\x65\x72\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x06\x54\x4C\x61\x62\x65\x6C\x06\x4C\x61\x62\x65\x6C\x37\x04\x4C\x65\x66\x74\x02\x13\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x66\x05\x57\x69\x64\x74\x68\x02\x47\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x12\xE6\x9C\x8D\xE5\x8A\xA1\xE5\x99\xA8\xE5\x9C\xB0\xE5\x9D\x80\xEF\xBC\x9A\x06\x4C\x61\x79\x6F\x75\x74\x07\x08\x74\x6C\x43\x65\x6E\x74\x65\x72\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x09\x54\x53\x70\x69\x6E\x45\x64\x69\x74\x0B\x53\x70\x69\x6E\x54\x43\x50\x50\x6F\x72\x74\x04\x4C\x65\x66\x74\x03\xCE\x00\x06\x48\x65\x69\x67\x68\x74\x02\x16\x04\x48\x69\x6E\x74\x06\x10\xE5\x8F\xAF\xE8\xBE\x93\xE5\x85\xA5\x31\x2D\x36\x35\x35\x33\x35\x03\x54\x6F\x70\x02\x06\x05\x57\x69\x64\x74\x68\x02\x4E\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x08\x4D\x61\x78\x56\x61\x6C\x75\x65\x04\xFF\xFF\x00\x00\x08\x4D\x69\x6E\x56\x61\x6C\x75\x65\x02\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x05\x56\x61\x6C\x75\x65\x03\x5D\x20\x00\x00\x09\x54\x53\x70\x69\x6E\x45\x64\x69\x74\x0F\x53\x70\x69\x6E\x43\x6C\x69\x48\x54\x54\x50\x50\x6F\x72\x74\x04\x4C\x65\x66\x74\x03\xCE\x00\x06\x48\x65\x69\x67\x68\x74\x02\x16\x04\x48\x69\x6E\x74\x06\x10\xE5\x8F\xAF\xE8\xBE\x93\xE5\x85\xA5\x31\x2D\x36\x35\x35\x33\x35\x03\x54\x6F\x70\x02\x46\x05\x57\x69\x64\x74\x68\x02\x4E\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x08\x4D\x61\x78\x56\x61\x6C\x75\x65\x04\xFF\xFF\x00\x00\x08\x4D\x69\x6E\x56\x61\x6C\x75\x65\x02\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x01\x05\x56\x61\x6C\x75\x65\x03\x5E\x20\x00\x00\x09\x54\x43\x68\x65\x63\x6B\x42\x6F\x78\x08\x43\x68\x6B\x49\x73\x5A\x69\x70\x04\x4C\x65\x66\x74\x02\x13\x06\x48\x65\x69\x67\x68\x74\x02\x15\x03\x54\x6F\x70\x03\xAA\x00\x05\x57\x69\x64\x74\x68\x02\x58\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x0F\xE5\xBC\x80\xE5\x90\xAF\x5A\x49\x50\xE5\x8E\x8B\xE7\xBC\xA9\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x02\x00\x00\x05\x54\x45\x64\x69\x74\x0D\x45\x64\x69\x74\x56\x65\x72\x69\x66\x79\x4B\x65\x79\x04\x4C\x65\x66\x74\x02\x5C\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x03\x87\x00\x05\x57\x69\x64\x74\x68\x03\x95\x00\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x03\x00\x00\x07\x54\x42\x75\x74\x74\x6F\x6E\x0A\x42\x74\x6E\x52\x61\x6E\x64\x4B\x65\x79\x04\x4C\x65\x66\x74\x03\xF2\x00\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x03\x86\x00\x05\x57\x69\x64\x74\x68\x02\x2B\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x06\xE9\x9A\x8F\xE6\x9C\xBA\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x04\x00\x00\x07\x54\x42\x75\x74\x74\x6F\x6E\x0A\x42\x74\x6E\x53\x61\x76\x65\x43\x66\x67\x04\x4C\x65\x66\x74\x03\x93\x01\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x3E\x05\x57\x69\x64\x74\x68\x02\x4B\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x0C\xE4\xBF\x9D\xE5\xAD\x98\xE9\x85\x8D\xE7\xBD\xAE\x07\x4F\x6E\x43\x6C\x69\x63\x6B\x07\x0F\x42\x74\x6E\x53\x61\x76\x65\x43\x66\x67\x43\x6C\x69\x63\x6B\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x05\x00\x00\x07\x54\x42\x75\x74\x74\x6F\x6E\x0A\x42\x74\x6E\x4C\x6F\x61\x64\x43\x66\x67\x04\x4C\x65\x66\x74\x03\x93\x01\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x06\x05\x57\x69\x64\x74\x68\x02\x4B\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x0C\xE8\xBD\xBD\xE5\x85\xA5\xE9\x85\x8D\xE7\xBD\xAE\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x06\x00\x00\x07\x54\x42\x75\x74\x74\x6F\x6E\x09\x42\x74\x6E\x4E\x65\x77\x43\x66\x67\x04\x4C\x65\x66\x74\x03\x93\x01\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x22\x05\x57\x69\x64\x74\x68\x02\x4B\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x0C\xE6\x96\xB0\xE5\xBB\xBA\xE9\x85\x8D\xE7\xBD\xAE\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x07\x00\x00\x05\x54\x45\x64\x69\x74\x0B\x45\x64\x69\x74\x53\x76\x72\x41\x64\x64\x72\x04\x4C\x65\x66\x74\x02\x5C\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x66\x05\x57\x69\x64\x74\x68\x03\xC1\x00\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x08\x00\x00\x09\x54\x43\x68\x65\x63\x6B\x42\x6F\x78\x0A\x43\x68\x6B\x49\x73\x48\x74\x74\x70\x73\x04\x4C\x65\x66\x74\x02\x7C\x06\x48\x65\x69\x67\x68\x74\x02\x15\x03\x54\x6F\x70\x03\xAA\x00\x05\x57\x69\x64\x74\x68\x02\x70\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x12\xE7\x9B\x91\xE5\x90\xAC\x2F\xE8\xBD\xAC\xE5\x8F\x91\x48\x54\x54\x50\x53\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x09\x00\x00\x06\x54\x4C\x61\x62\x65\x6C\x06\x4C\x61\x62\x65\x6C\x38\x04\x4C\x65\x66\x74\x02\x11\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x26\x05\x57\x69\x64\x74\x68\x03\xA2\x00\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x22\xE6\x9C\x8D\xE5\x8A\xA1\xE7\xAB\xAF\xE7\x9B\x91\xE5\x90\xAC\xE7\x9A\x84\x48\x54\x54\x50\x28\x53\x29\xE7\xAB\xAF\xE5\x8F\xA3\xEF\xBC\x9A\x06\x4C\x61\x79\x6F\x75\x74\x07\x08\x74\x6C\x43\x65\x6E\x74\x65\x72\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x09\x54\x53\x70\x69\x6E\x45\x64\x69\x74\x0F\x53\x70\x69\x6E\x53\x76\x72\x48\x54\x54\x50\x50\x6F\x72\x74\x04\x4C\x65\x66\x74\x03\xCE\x00\x06\x48\x65\x69\x67\x68\x74\x02\x16\x04\x48\x69\x6E\x74\x06\x10\xE5\x8F\xAF\xE8\xBE\x93\xE5\x85\xA5\x31\x2D\x36\x35\x35\x33\x35\x03\x54\x6F\x70\x02\x26\x05\x57\x69\x64\x74\x68\x02\x4E\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x08\x4D\x61\x78\x56\x61\x6C\x75\x65\x04\xFF\xFF\x00\x00\x08\x4D\x69\x6E\x56\x61\x6C\x75\x65\x02\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x0A\x05\x56\x61\x6C\x75\x65\x03\x5E\x20\x00\x00\x00\x09\x54\x47\x72\x6F\x75\x70\x42\x6F\x78\x05\x47\x42\x54\x4C\x53\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x03\xA6\x00\x03\x54\x6F\x70\x03\x4A\x01\x05\x57\x69\x64\x74\x68\x03\xEA\x01\x05\x41\x6C\x69\x67\x6E\x07\x08\x61\x6C\x42\x6F\x74\x74\x6F\x6D\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x0F\x54\x4C\x53\xE8\xAF\x81\xE4\xB9\xA6\xE8\xAE\xBE\xE7\xBD\xAE\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x03\x90\x00\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xE6\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x02\x00\x06\x54\x50\x61\x6E\x65\x6C\x06\x50\x61\x6E\x65\x6C\x33\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x02\x20\x03\x54\x6F\x70\x02\x00\x05\x57\x69\x64\x74\x68\x03\xE6\x01\x05\x41\x6C\x69\x67\x6E\x07\x05\x61\x6C\x54\x6F\x70\x0A\x42\x65\x76\x65\x6C\x4F\x75\x74\x65\x72\x07\x06\x62\x76\x4E\x6F\x6E\x65\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x02\x20\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xE6\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x00\x06\x54\x4C\x61\x62\x65\x6C\x06\x4C\x61\x62\x65\x6C\x34\x04\x4C\x65\x66\x74\x02\x11\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x07\x05\x57\x69\x64\x74\x68\x02\x56\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x12\x54\x4C\x53\x20\x43\x41\xE6\xA0\xB9\xE8\xAF\x81\xE4\xB9\xA6\xEF\xBC\x9A\x06\x4C\x61\x79\x6F\x75\x74\x07\x08\x74\x6C\x43\x65\x6E\x74\x65\x72\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x05\x54\x45\x64\x69\x74\x0D\x45\x64\x69\x74\x54\x4C\x53\x43\x41\x46\x69\x6C\x65\x04\x4C\x65\x66\x74\x02\x70\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x03\x05\x57\x69\x64\x74\x68\x03\x4A\x01\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x00\x00\x07\x54\x42\x75\x74\x74\x6F\x6E\x09\x42\x74\x6E\x43\x41\x4F\x70\x65\x6E\x04\x4C\x65\x66\x74\x03\xBC\x01\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x03\x05\x57\x69\x64\x74\x68\x02\x1B\x08\x42\x69\x64\x69\x4D\x6F\x64\x65\x07\x0D\x62\x64\x52\x69\x67\x68\x74\x54\x6F\x4C\x65\x66\x74\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x03\x2E\x2E\x2E\x0E\x50\x61\x72\x65\x6E\x74\x42\x69\x64\x69\x4D\x6F\x64\x65\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x01\x00\x00\x00\x0C\x54\x50\x61\x67\x65\x43\x6F\x6E\x74\x72\x6F\x6C\x0C\x50\x61\x67\x65\x43\x6F\x6E\x74\x72\x6F\x6C\x32\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x02\x70\x03\x54\x6F\x70\x02\x20\x05\x57\x69\x64\x74\x68\x03\xE6\x01\x0A\x41\x63\x74\x69\x76\x65\x50\x61\x67\x65\x07\x09\x54\x61\x62\x53\x68\x65\x65\x74\x33\x05\x41\x6C\x69\x67\x6E\x07\x08\x61\x6C\x43\x6C\x69\x65\x6E\x74\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x49\x6E\x64\x65\x78\x02\x00\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x01\x0B\x54\x61\x62\x50\x6F\x73\x69\x74\x69\x6F\x6E\x07\x08\x74\x70\x42\x6F\x74\x74\x6F\x6D\x00\x09\x54\x54\x61\x62\x53\x68\x65\x65\x74\x09\x54\x61\x62\x53\x68\x65\x65\x74\x33\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x0C\xE5\xAE\xA2\xE6\x88\xB7\xE7\xAB\xAF\x54\x4C\x53\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x02\x52\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xDE\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x06\x54\x50\x61\x6E\x65\x6C\x06\x50\x61\x6E\x65\x6C\x34\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x02\x52\x03\x54\x6F\x70\x02\x00\x05\x57\x69\x64\x74\x68\x03\xDE\x01\x05\x41\x6C\x69\x67\x6E\x07\x08\x61\x6C\x43\x6C\x69\x65\x6E\x74\x0A\x42\x65\x76\x65\x6C\x4F\x75\x74\x65\x72\x07\x06\x62\x76\x4E\x6F\x6E\x65\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x02\x52\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xDE\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x00\x06\x54\x4C\x61\x62\x65\x6C\x06\x4C\x61\x62\x65\x6C\x36\x04\x4C\x65\x66\x74\x02\x0D\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x33\x05\x57\x69\x64\x74\x68\x02\x56\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x10\x54\x4C\x53\x20\x4B\x65\x79\xE6\x96\x87\xE4\xBB\xB6\xEF\xBC\x9A\x06\x4C\x61\x79\x6F\x75\x74\x07\x08\x74\x6C\x43\x65\x6E\x74\x65\x72\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x05\x54\x45\x64\x69\x74\x11\x45\x64\x69\x74\x54\x4C\x53\x43\x6C\x69\x4B\x65\x79\x46\x69\x6C\x65\x04\x4C\x65\x66\x74\x02\x6C\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x31\x05\x57\x69\x64\x74\x68\x03\x4A\x01\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x00\x00\x06\x54\x4C\x61\x62\x65\x6C\x06\x4C\x61\x62\x65\x6C\x35\x04\x4C\x65\x66\x74\x02\x0D\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x0F\x05\x57\x69\x64\x74\x68\x02\x51\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x11\x54\x4C\x53\x20\x43\x65\x72\x74\xE6\x96\x87\xE4\xBB\xB6\xEF\xBC\x9A\x06\x4C\x61\x79\x6F\x75\x74\x07\x08\x74\x6C\x43\x65\x6E\x74\x65\x72\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x05\x54\x45\x64\x69\x74\x12\x45\x64\x69\x74\x54\x4C\x53\x43\x6C\x69\x43\x65\x72\x74\x46\x69\x6C\x65\x04\x4C\x65\x66\x74\x02\x6C\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x0D\x05\x57\x69\x64\x74\x68\x03\x4A\x01\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x01\x00\x00\x07\x54\x42\x75\x74\x74\x6F\x6E\x0E\x42\x74\x6E\x43\x6C\x69\x43\x65\x72\x74\x4F\x70\x65\x6E\x04\x4C\x65\x66\x74\x03\xB8\x01\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x0D\x05\x57\x69\x64\x74\x68\x02\x1B\x08\x42\x69\x64\x69\x4D\x6F\x64\x65\x07\x0D\x62\x64\x52\x69\x67\x68\x74\x54\x6F\x4C\x65\x66\x74\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x03\x2E\x2E\x2E\x0E\x50\x61\x72\x65\x6E\x74\x42\x69\x64\x69\x4D\x6F\x64\x65\x08\x07\x4F\x6E\x43\x6C\x69\x63\x6B\x07\x13\x42\x74\x6E\x43\x6C\x69\x43\x65\x72\x74\x4F\x70\x65\x6E\x43\x6C\x69\x63\x6B\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x02\x00\x00\x07\x54\x42\x75\x74\x74\x6F\x6E\x0D\x42\x74\x6E\x43\x6C\x69\x4B\x65\x79\x4F\x70\x65\x6E\x04\x4C\x65\x66\x74\x03\xB8\x01\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x31\x05\x57\x69\x64\x74\x68\x02\x1B\x08\x42\x69\x64\x69\x4D\x6F\x64\x65\x07\x0D\x62\x64\x52\x69\x67\x68\x74\x54\x6F\x4C\x65\x66\x74\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x03\x2E\x2E\x2E\x0E\x50\x61\x72\x65\x6E\x74\x42\x69\x64\x69\x4D\x6F\x64\x65\x08\x07\x4F\x6E\x43\x6C\x69\x63\x6B\x07\x12\x42\x74\x6E\x43\x6C\x69\x4B\x65\x79\x4F\x70\x65\x6E\x43\x6C\x69\x63\x6B\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x03\x00\x00\x00\x00\x09\x54\x54\x61\x62\x53\x68\x65\x65\x74\x09\x54\x61\x62\x53\x68\x65\x65\x74\x34\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x0C\xE6\x9C\x8D\xE5\x8A\xA1\xE7\xAB\xAF\x54\x4C\x53\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x02\x52\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xDE\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x06\x54\x50\x61\x6E\x65\x6C\x06\x50\x61\x6E\x65\x6C\x35\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x02\x52\x03\x54\x6F\x70\x02\x00\x05\x57\x69\x64\x74\x68\x03\xDE\x01\x05\x41\x6C\x69\x67\x6E\x07\x08\x61\x6C\x43\x6C\x69\x65\x6E\x74\x0A\x42\x65\x76\x65\x6C\x4F\x75\x74\x65\x72\x07\x06\x62\x76\x4E\x6F\x6E\x65\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x02\x52\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xDE\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x00\x06\x54\x4C\x61\x62\x65\x6C\x07\x4C\x61\x62\x65\x6C\x31\x30\x04\x4C\x65\x66\x74\x02\x0D\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x0F\x05\x57\x69\x64\x74\x68\x02\x51\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x11\x54\x4C\x53\x20\x43\x65\x72\x74\xE6\x96\x87\xE4\xBB\xB6\xEF\xBC\x9A\x06\x4C\x61\x79\x6F\x75\x74\x07\x08\x74\x6C\x43\x65\x6E\x74\x65\x72\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x05\x54\x45\x64\x69\x74\x12\x45\x64\x69\x74\x54\x4C\x53\x53\x76\x72\x43\x65\x72\x74\x46\x69\x6C\x65\x04\x4C\x65\x66\x74\x02\x6C\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x0D\x05\x57\x69\x64\x74\x68\x03\x4A\x01\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x00\x00\x07\x54\x42\x75\x74\x74\x6F\x6E\x0E\x42\x74\x6E\x53\x76\x72\x43\x65\x72\x74\x4F\x70\x65\x6E\x04\x4C\x65\x66\x74\x03\xB8\x01\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x0D\x05\x57\x69\x64\x74\x68\x02\x1B\x08\x42\x69\x64\x69\x4D\x6F\x64\x65\x07\x0D\x62\x64\x52\x69\x67\x68\x74\x54\x6F\x4C\x65\x66\x74\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x03\x2E\x2E\x2E\x0E\x50\x61\x72\x65\x6E\x74\x42\x69\x64\x69\x4D\x6F\x64\x65\x08\x07\x4F\x6E\x43\x6C\x69\x63\x6B\x07\x13\x42\x74\x6E\x53\x76\x72\x43\x65\x72\x74\x4F\x70\x65\x6E\x43\x6C\x69\x63\x6B\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x01\x00\x00\x07\x54\x42\x75\x74\x74\x6F\x6E\x0D\x42\x74\x6E\x53\x76\x72\x4B\x65\x79\x4F\x70\x65\x6E\x04\x4C\x65\x66\x74\x03\xB8\x01\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x31\x05\x57\x69\x64\x74\x68\x02\x1B\x08\x42\x69\x64\x69\x4D\x6F\x64\x65\x07\x0D\x62\x64\x52\x69\x67\x68\x74\x54\x6F\x4C\x65\x66\x74\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x03\x2E\x2E\x2E\x0E\x50\x61\x72\x65\x6E\x74\x42\x69\x64\x69\x4D\x6F\x64\x65\x08\x07\x4F\x6E\x43\x6C\x69\x63\x6B\x07\x12\x42\x74\x6E\x53\x76\x72\x4B\x65\x79\x4F\x70\x65\x6E\x43\x6C\x69\x63\x6B\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x02\x00\x00\x05\x54\x45\x64\x69\x74\x11\x45\x64\x69\x74\x54\x4C\x53\x53\x76\x72\x4B\x65\x79\x46\x69\x6C\x65\x04\x4C\x65\x66\x74\x02\x6C\x06\x48\x65\x69\x67\x68\x74\x02\x19\x03\x54\x6F\x70\x02\x31\x05\x57\x69\x64\x74\x68\x03\x4A\x01\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x03\x00\x00\x06\x54\x4C\x61\x62\x65\x6C\x07\x4C\x61\x62\x65\x6C\x31\x31\x04\x4C\x65\x66\x74\x02\x0D\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x33\x05\x57\x69\x64\x74\x68\x02\x56\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x10\x54\x4C\x53\x20\x4B\x65\x79\xE6\x96\x87\xE4\xBB\xB6\xEF\xBC\x9A\x06\x4C\x61\x79\x6F\x75\x74\x07\x08\x74\x6C\x43\x65\x6E\x74\x65\x72\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x00\x00\x00\x00\x09\x54\x47\x72\x6F\x75\x70\x42\x6F\x78\x0D\x47\x42\x41\x70\x70\x53\x65\x74\x74\x69\x6E\x67\x73\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x02\x33\x03\x54\x6F\x70\x02\x3A\x05\x57\x69\x64\x74\x68\x03\xEA\x01\x05\x41\x6C\x69\x67\x6E\x07\x05\x61\x6C\x54\x6F\x70\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x09\x41\x50\x50\xE8\xAE\xBE\xE7\xBD\xAE\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x02\x1D\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\xE6\x01\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x03\x00\x09\x54\x43\x68\x65\x63\x6B\x42\x6F\x78\x10\x43\x68\x6B\x41\x75\x74\x6F\x52\x65\x63\x6F\x6E\x6E\x65\x63\x74\x04\x4C\x65\x66\x74\x02\x13\x06\x48\x65\x69\x67\x68\x74\x02\x15\x03\x54\x6F\x70\x02\x03\x05\x57\x69\x64\x74\x68\x03\xB2\x00\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x27\xE4\xB8\x8E\xE6\x9C\x8D\xE5\x8A\xA1\xE5\x99\xA8\xE8\xBF\x9E\xE6\x8E\xA5\xE6\x96\xAD\xE5\xBC\x80\xE5\x90\x8E\xE8\x87\xAA\xE5\x8A\xA8\xE9\x87\x8D\xE8\xBF\x9E\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x00\x00\x06\x54\x4C\x61\x62\x65\x6C\x06\x4C\x61\x62\x65\x6C\x39\x04\x4C\x65\x66\x74\x03\xF3\x00\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x00\x05\x57\x69\x64\x74\x68\x02\x5A\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x15\xE6\x9C\x80\xE5\xA4\xA7\xE6\x97\xA5\xE5\xBF\x97\xE8\xA1\x8C\xE6\x95\xB0\xEF\xBC\x9A\x06\x4C\x61\x79\x6F\x75\x74\x07\x08\x74\x6C\x43\x65\x6E\x74\x65\x72\x0B\x50\x61\x72\x65\x6E\x74\x43\x6F\x6C\x6F\x72\x08\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x00\x09\x54\x53\x70\x69\x6E\x45\x64\x69\x74\x0E\x53\x70\x69\x6E\x4D\x61\x78\x4C\x6F\x67\x4C\x69\x6E\x65\x04\x4C\x65\x66\x74\x03\x46\x01\x06\x48\x65\x69\x67\x68\x74\x02\x16\x03\x54\x6F\x70\x02\x00\x05\x57\x69\x64\x74\x68\x03\x86\x00\x08\x41\x75\x74\x6F\x53\x69\x7A\x65\x08\x08\x4D\x61\x78\x56\x61\x6C\x75\x65\x04\x40\x0D\x03\x00\x08\x4D\x69\x6E\x56\x61\x6C\x75\x65\x02\x01\x08\x4F\x6E\x43\x68\x61\x6E\x67\x65\x07\x14\x53\x70\x69\x6E\x4D\x61\x78\x4C\x6F\x67\x4C\x69\x6E\x65\x43\x68\x61\x6E\x67\x65\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x01\x05\x56\x61\x6C\x75\x65\x03\x88\x13\x00\x00\x00\x00\x09\x54\x54\x61\x62\x53\x68\x65\x65\x74\x09\x54\x61\x62\x53\x68\x65\x65\x74\x32\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x06\xE6\x97\xA5\xE5\xBF\x97\x0C\x43\x6C\x69\x65\x6E\x74\x48\x65\x69\x67\x68\x74\x03\x6F\x02\x0B\x43\x6C\x69\x65\x6E\x74\x57\x69\x64\x74\x68\x03\x66\x02\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x00\x08\x54\x4C\x69\x73\x74\x42\x6F\x78\x07\x4C\x73\x74\x4C\x6F\x67\x73\x04\x4C\x65\x66\x74\x02\x00\x06\x48\x65\x69\x67\x68\x74\x03\x6A\x02\x03\x54\x6F\x70\x02\x00\x05\x57\x69\x64\x74\x68\x03\x66\x02\x05\x41\x6C\x69\x67\x6E\x07\x08\x61\x6C\x43\x6C\x69\x65\x6E\x74\x14\x42\x6F\x72\x64\x65\x72\x53\x70\x61\x63\x69\x6E\x67\x2E\x42\x6F\x74\x74\x6F\x6D\x02\x04\x0B\x46\x6F\x6E\x74\x2E\x48\x65\x69\x67\x68\x74\x02\xF4\x0A\x49\x74\x65\x6D\x48\x65\x69\x67\x68\x74\x02\x00\x0A\x50\x61\x72\x65\x6E\x74\x46\x6F\x6E\x74\x08\x05\x53\x74\x79\x6C\x65\x07\x10\x6C\x62\x4F\x77\x6E\x65\x72\x44\x72\x61\x77\x46\x69\x78\x65\x64\x08\x54\x61\x62\x4F\x72\x64\x65\x72\x02\x00\x00\x00\x00\x00\x00\x0B\x54\x53\x61\x76\x65\x44\x69\x61\x6C\x6F\x67\x0A\x44\x6C\x67\x53\x61\x76\x65\x43\x66\x67\x0A\x44\x65\x66\x61\x75\x6C\x74\x45\x78\x74\x06\x04\x2E\x63\x66\x67\x06\x46\x69\x6C\x74\x65\x72\x06\x12\xE9\x85\x8D\xE7\xBD\xAE\xE6\x96\x87\xE4\xBB\xB6\x7C\x2A\x2E\x63\x66\x67\x04\x6C\x65\x66\x74\x03\x8D\x01\x03\x74\x6F\x70\x03\x13\x01\x00\x00\x0B\x54\x4F\x70\x65\x6E\x44\x69\x61\x6C\x6F\x67\x07\x44\x6C\x67\x4F\x70\x65\x6E\x04\x6C\x65\x66\x74\x03\xB3\x01\x03\x74\x6F\x70\x03\x13\x01\x00\x00\x0B\x54\x41\x63\x74\x69\x6F\x6E\x4C\x69\x73\x74\x0B\x41\x63\x74\x69\x6F\x6E\x4C\x69\x73\x74\x31\x04\x6C\x65\x66\x74\x03\x66\x01\x03\x74\x6F\x70\x03\x13\x01\x00\x07\x54\x41\x63\x74\x69\x6F\x6E\x08\x41\x63\x74\x53\x74\x61\x72\x74\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x06\xE5\x90\xAF\xE5\x8A\xA8\x00\x00\x07\x54\x41\x63\x74\x69\x6F\x6E\x07\x41\x63\x74\x53\x74\x6F\x70\x07\x43\x61\x70\x74\x69\x6F\x6E\x06\x06\xE5\x81\x9C\xE6\xAD\xA2\x00\x00\x00\x09\x54\x54\x72\x61\x79\x49\x63\x6F\x6E\x09\x54\x72\x61\x79\x49\x63\x6F\x6E\x31\x07\x56\x69\x73\x69\x62\x6C\x65\x09\x04\x6C\x65\x66\x74\x03\x66\x01\x03\x74\x6F\x70\x03\xE6\x00\x00\x00\x00") 91 | 92 | // 注册Form资源 93 | var _ = vcl.RegisterFormResource(MainForm, &mainFormBytes) 94 | -------------------------------------------------------------------------------- /MainFormImpl.go: -------------------------------------------------------------------------------- 1 | // +build gui 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "math/rand" 8 | "runtime" 9 | "strings" 10 | "time" 11 | 12 | "errors" 13 | 14 | _ "github.com/ying32/govcl/pkgs/winappres" 15 | "github.com/ying32/govcl/vcl" 16 | "github.com/ying32/govcl/vcl/rtl" 17 | "github.com/ying32/govcl/vcl/types" 18 | "github.com/ying32/govcl/vcl/types/colors" 19 | "github.com/ying32/rproxy/librp" 20 | ) 21 | 22 | const ( 23 | randStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" 24 | SERVER = 1 25 | CLIENT = 0 26 | ) 27 | 28 | var CheckConfigError = errors.New("检查配置错误") 29 | 30 | //::private:: 31 | type TMainFormFields struct { 32 | rpObj librp.IRPObject 33 | rpConfigFileName string 34 | running bool 35 | autoReboot bool 36 | appCfg *vcl.TIniFile 37 | modeIndex int32 38 | //isDarwin bool 39 | rpConfigLoaded bool 40 | } 41 | 42 | func (f *TMainForm) OnFormCreate(sender vcl.IObject) { 43 | rand.Seed(time.Now().Unix()) 44 | //f.isDarwin = runtime.GOOS == "darwin" 45 | 46 | // 都是坑 47 | if runtime.GOOS == "linux" { 48 | f.SpinMaxLogLine.SetAutoSize(true) 49 | f.SpinCliHTTPPort.SetAutoSize(true) 50 | f.SpinSvrHTTPPort.SetAutoSize(true) 51 | f.SpinTCPPort.SetAutoSize(true) 52 | } 53 | 54 | f.ScreenCenter() 55 | f.PageControl1.SetActivePageIndex(0) 56 | f.PageControl2.SetActivePageIndex(0) 57 | 58 | f.running = false 59 | f.appCfg = vcl.NewIniFile(rtl.ExtractFilePath(vcl.Application.ExeName()) + "app.conf") 60 | 61 | if runtime.GOOS != "windows" { 62 | loadMainIconFromStream(f.TrayIcon1.Icon()) 63 | } 64 | 65 | librp.IsGUI = true 66 | librp.LogGUICallback = f.logCallback 67 | f.loadAppConfig() 68 | 69 | } 70 | 71 | func (f *TMainForm) OnFormCloseQuery(sender vcl.IObject, canClose *bool) { 72 | if f.running { 73 | vcl.MessageDlg("当前服务正在运行中,请停止后再退出。", types.MtWarning, types.MbOK) 74 | *canClose = false 75 | } 76 | } 77 | 78 | func loadMainIconFromStream(outIcon *vcl.TIcon) { 79 | if outIcon.IsValid() { 80 | mem := vcl.NewMemoryStreamFromBytes(mainIconBytes) 81 | defer mem.Free() 82 | mem.SetPosition(0) 83 | outIcon.LoadFromStream(mem) 84 | } 85 | } 86 | 87 | func (f *TMainForm) OnFormDestroy(sender vcl.IObject) { 88 | if f.appCfg != nil { 89 | f.appCfg.Free() 90 | } 91 | if f.rpObj != nil { 92 | f.rpObj.Close() 93 | } 94 | } 95 | 96 | func (f *TMainForm) loadAppConfig() { 97 | f.rpConfigFileName = f.appCfg.ReadString("System", "RPConfigFileName", "") 98 | cfg := new(librp.TRProxyConfig) 99 | err := librp.LoadConfig(f.rpConfigFileName, cfg) 100 | if err == nil { 101 | librp.SetConfig(cfg) 102 | f.updateUIConfig(cfg) 103 | f.rpConfigLoaded = true 104 | librp.Log.I("已加载RP配置:" + f.rpConfigFileName) 105 | } 106 | f.autoReboot = f.appCfg.ReadBool("System", "AutoReboot", true) 107 | f.ChkAutoReconnect.SetChecked(f.autoReboot) 108 | 109 | f.modeIndex = f.appCfg.ReadInteger("System", "ModeIndex", 0) 110 | f.setRPMode(f.modeIndex) 111 | 112 | f.SpinMaxLogLine.SetValue(f.appCfg.ReadInteger("System", "MaxLogLine", 5000)) 113 | 114 | f.updateCaption() 115 | } 116 | 117 | func (f *TMainForm) logCallback(msg string) { 118 | vcl.ThreadSync(func() { 119 | if f.LstLogs.Count() > f.SpinMaxLogLine.Value() { 120 | f.LstLogs.Clear() 121 | } 122 | f.LstLogs.Items().Add(msg) 123 | }) 124 | } 125 | 126 | // 下面两个函数用于解决TRadioGroup在MacOS下bug问题 127 | func (f *TMainForm) getRPMode() int32 { 128 | return f.RGMode.ItemIndex() 129 | } 130 | 131 | func (f *TMainForm) setRPMode(idx int32) { 132 | f.RGMode.SetItemIndex(idx) 133 | } 134 | 135 | func (f *TMainForm) setTrayHint(text string) { 136 | //if f.isDarwin { 137 | // // darwin下出bug 138 | // return 139 | //} 140 | f.TrayIcon1.SetHint(text) 141 | } 142 | 143 | func (f *TMainForm) OnBtnRandKeyClick(sender vcl.IObject) { 144 | var randKey []byte 145 | for i := 0; i < 16; i++ { 146 | randKey = append(randKey, randStr[rand.Intn(len(randStr))]) 147 | } 148 | f.EditVerifyKey.SetText(string(randKey)) 149 | } 150 | 151 | func (f *TMainForm) OnBtnCAOpenClick(sender vcl.IObject) { 152 | if f.DlgOpen.Execute() { 153 | f.EditTLSCAFile.SetText(f.DlgOpen.FileName()) 154 | } 155 | } 156 | 157 | func (f *TMainForm) OnBtnSaveCfgClick(sender vcl.IObject) { 158 | f.saveUIConfig() 159 | } 160 | 161 | func (f *TMainForm) updateUIConfig(cfg *librp.TRProxyConfig) { 162 | f.SpinTCPPort.SetValue(int32(cfg.TCPPort)) 163 | f.EditVerifyKey.SetText(cfg.VerifyKey) 164 | f.ChkIsZip.SetChecked(cfg.IsZIP) 165 | f.ChkIsHttps.SetChecked(cfg.IsHTTPS) 166 | f.EditTLSCAFile.SetText(cfg.TLSCAFile) 167 | 168 | // client 169 | f.SpinCliHTTPPort.SetValue(int32(cfg.Client.HTTPPort)) 170 | f.EditSvrAddr.SetText(cfg.Client.SvrAddr) 171 | f.EditTLSCliCertFile.SetText(cfg.Client.TLSCertFile) 172 | f.EditTLSCliKeyFile.SetText(cfg.Client.TLSKeyFile) 173 | 174 | // server 175 | f.SpinSvrHTTPPort.SetValue(int32(cfg.Server.HTTPPort)) 176 | f.EditTLSSvrCertFile.SetText(cfg.Server.TLSCertFile) 177 | f.EditTLSSvrKeyFile.SetText(cfg.Server.TLSKeyFile) 178 | } 179 | 180 | func (f *TMainForm) checkConfig() error { 181 | if f.EditVerifyKey.Text() == "" { 182 | f.EditVerifyKey.SetFocus() 183 | vcl.ShowMessage("必须输入一个验证的key") 184 | return CheckConfigError 185 | } 186 | if f.EditSvrAddr.Text() == "" { 187 | f.EditSvrAddr.SetFocus() 188 | vcl.ShowMessage("要连接的服务器地址不能为空") 189 | return CheckConfigError 190 | } 191 | if f.ChkIsHttps.Checked() { 192 | 193 | if f.EditTLSCliCertFile.Text() == "" || f.EditTLSCliKeyFile.Text() == "" { 194 | vcl.ShowMessage("当为HTTPS时,客户端TLS证书不能为空。") 195 | return CheckConfigError 196 | } 197 | 198 | if f.EditTLSSvrCertFile.Text() == "" || f.EditTLSSvrKeyFile.Text() == "" { 199 | vcl.ShowMessage("当为HTTPS时,服务端TLS证书不能为空。") 200 | return CheckConfigError 201 | } 202 | } 203 | return nil 204 | } 205 | 206 | func (f *TMainForm) saveUIConfig() { 207 | if f.checkConfig() != nil { 208 | return 209 | } 210 | cfg := new(librp.TRProxyConfig) 211 | 212 | cfg.TCPPort = int(f.SpinTCPPort.Value()) 213 | cfg.VerifyKey = f.EditVerifyKey.Text() 214 | cfg.IsZIP = f.ChkIsZip.Checked() 215 | cfg.IsHTTPS = f.ChkIsHttps.Checked() 216 | cfg.TLSCAFile = f.EditTLSCAFile.Text() 217 | 218 | // client 219 | cfg.Client.HTTPPort = int(f.SpinCliHTTPPort.Value()) 220 | cfg.Client.SvrAddr = f.EditSvrAddr.Text() 221 | cfg.Client.TLSCertFile = f.EditTLSCliCertFile.Text() 222 | cfg.Client.TLSKeyFile = f.EditTLSCliKeyFile.Text() 223 | 224 | // server 225 | cfg.Server.HTTPPort = int(f.SpinSvrHTTPPort.Value()) 226 | cfg.Server.TLSCertFile = f.EditTLSSvrCertFile.Text() 227 | cfg.Server.TLSKeyFile = f.EditTLSSvrKeyFile.Text() 228 | 229 | if !rtl.FileExists(f.rpConfigFileName) { 230 | if f.DlgSaveCfg.Execute() { 231 | f.rpConfigFileName = f.DlgSaveCfg.FileName() 232 | } else { 233 | librp.Log.I("取消保存RP配置") 234 | return 235 | } 236 | } 237 | librp.SetConfig(cfg) 238 | err := librp.SaveConfig(f.rpConfigFileName, cfg) 239 | if err != nil { 240 | librp.Log.I("P配置保存失败") 241 | return 242 | } 243 | f.rpConfigLoaded = true 244 | librp.Log.I("RP配置已保存:" + f.rpConfigFileName) 245 | } 246 | 247 | func (f *TMainForm) OnBtnLoadCfgClick(sender vcl.IObject) { 248 | if f.DlgOpen.Execute() { 249 | cfg := new(librp.TRProxyConfig) 250 | err := librp.LoadConfig(f.DlgOpen.FileName(), cfg) 251 | if err != nil { 252 | vcl.ShowMessage("载入RP配置失败:" + err.Error()) 253 | } else { 254 | librp.SetConfig(cfg) 255 | f.rpConfigFileName = f.DlgOpen.FileName() 256 | f.updateUIConfig(cfg) 257 | // 载入即保存下当前的文件名 258 | f.appCfg.WriteString("System", "RPConfigFileName", f.rpConfigFileName) 259 | f.rpConfigLoaded = true 260 | librp.Log.I("已加载RP配置:" + f.rpConfigFileName) 261 | } 262 | } 263 | } 264 | 265 | func (f *TMainForm) OnChkAutoReconnectClick(sender vcl.IObject) { 266 | f.autoReboot = f.ChkAutoReconnect.Checked() 267 | f.appCfg.WriteBool("System", "AutoReboot", f.autoReboot) 268 | } 269 | 270 | func (f *TMainForm) runSvr() { 271 | 272 | switch f.modeIndex { 273 | case CLIENT: 274 | librp.Log.I("连接服务端...") 275 | for f.running { 276 | err := f.rpObj.Start() 277 | if err != nil { 278 | librp.Log.E("连接服务器错误:", err) 279 | librp.Log.I("5秒后重新连接...") 280 | for i := 0; i < 5; i++ { 281 | if !f.running { 282 | break 283 | } 284 | time.Sleep(time.Second * 1) 285 | } 286 | if !f.autoReboot { 287 | break 288 | } 289 | } 290 | } 291 | case SERVER: 292 | if f.running { 293 | err := f.rpObj.Start() 294 | if err != nil { 295 | librp.Log.E("启动服务端错误:", err) 296 | } 297 | } 298 | } 299 | librp.Log.I("已停止") 300 | vcl.ThreadSync(func() { 301 | f.BtnStop.Click() 302 | }) 303 | } 304 | 305 | func (f *TMainForm) OnActStartExecute(sender vcl.IObject) { 306 | 307 | switch f.modeIndex { 308 | case CLIENT: 309 | f.rpObj = librp.NewRPClient() 310 | case SERVER: 311 | f.rpObj = librp.NewRPServer() 312 | } 313 | if f.rpObj == nil { 314 | vcl.ShowMessage("rproxy对象创建失败。") 315 | return 316 | } 317 | 318 | f.running = true 319 | 320 | f.LstLogs.Clear() 321 | 322 | str := f.Caption() + "\r\n" 323 | switch f.modeIndex { 324 | case CLIENT: 325 | s := fmt.Sprintln("客户端启动,连接服务器:", f.EditSvrAddr.Text(), ", 端口:", f.SpinTCPPort.Value()) 326 | str += s 327 | librp.Log.I(s) 328 | if f.ChkIsHttps.Checked() { 329 | s = "转发至HTTP服务为HTTPS" 330 | str += s + "\r\n" 331 | librp.Log.I(s) 332 | } 333 | s = fmt.Sprintln("转发至本地HTTP(S)端口:", f.SpinCliHTTPPort.Value()) 334 | str += s 335 | librp.Log.I(s) 336 | 337 | case SERVER: 338 | s := fmt.Sprintln("TCP服务端已启动,端口:", f.SpinTCPPort.Value()) 339 | str += s 340 | librp.Log.I(s) 341 | if f.ChkIsHttps.Checked() { 342 | s = "当前HTTP服务为HTTPS" 343 | str += s + "\r\n" 344 | librp.Log.I(s) 345 | } 346 | s = fmt.Sprintln("HTTP(S)服务端已开启,端口:", f.SpinSvrHTTPPort.Value()) 347 | str += s 348 | librp.Log.I(s) 349 | } 350 | f.setTrayHint(str) 351 | 352 | go f.runSvr() 353 | 354 | f.setControlState(false) 355 | } 356 | 357 | func (f *TMainForm) setControlState(state bool) { 358 | f.ChkIsHttps.SetEnabled(state) 359 | f.RGMode.SetEnabled(state) 360 | 361 | var i int32 362 | for i = 0; i < f.GBBase.ControlCount(); i++ { 363 | f.GBBase.Controls(i).SetEnabled(state) 364 | } 365 | for i = 0; i < f.GBTLS.ControlCount(); i++ { 366 | f.GBTLS.Controls(i).SetEnabled(state) 367 | } 368 | for i = 0; i < f.GBAppSettings.ControlCount(); i++ { 369 | f.GBAppSettings.Controls(i).SetEnabled(state) 370 | } 371 | } 372 | 373 | func (f *TMainForm) OnActStartUpdate(sender vcl.IObject) { 374 | vcl.AsAction(sender).SetEnabled(!f.running && f.rpConfigLoaded) 375 | } 376 | 377 | func (f *TMainForm) OnActStopExecute(sender vcl.IObject) { 378 | f.running = false 379 | f.setControlState(true) 380 | 381 | if f.rpObj != nil { 382 | f.rpObj.Close() 383 | } 384 | f.rpObj = nil 385 | f.updateCaption() 386 | } 387 | 388 | func (f *TMainForm) OnActStopUpdate(sender vcl.IObject) { 389 | vcl.AsAction(sender).SetEnabled(f.running && f.rpConfigLoaded) 390 | } 391 | 392 | func (f *TMainForm) OnBtnNewCfgClick(sender vcl.IObject) { 393 | librp.Log.I("新建配置") 394 | f.rpConfigFileName = "" 395 | f.rpConfigLoaded = false 396 | } 397 | 398 | func (f *TMainForm) updateCaption() { 399 | //if f.isDarwin { 400 | // // 唉macOS下liblcl.dylib有内部bug 401 | // m := []string{"客户端", "服务端"} 402 | // f.SetCaption("rproxy[" + m[f.modeIndex] + "]") 403 | //} else { 404 | f.SetCaption("rproxy[" + f.RGMode.Items().S(f.modeIndex) + "]") 405 | //} 406 | f.setTrayHint(f.Caption()) 407 | } 408 | 409 | func (f *TMainForm) OnRGModeClick(sender vcl.IObject) { 410 | f.modeIndex = f.getRPMode() 411 | f.appCfg.WriteInteger("System", "ModeIndex", f.modeIndex) 412 | f.updateCaption() 413 | } 414 | 415 | func (f *TMainForm) OnLstLogsDrawItem(control vcl.IWinControl, index int32, aRect types.TRect, state types.TOwnerDrawState) { 416 | canvas := f.LstLogs.Canvas() 417 | 418 | canvas.Font().SetColor(colors.ClBlack) 419 | s := f.LstLogs.Items().S(index) 420 | if strings.HasPrefix(s, "[ERROR]") { 421 | canvas.Font().SetColor(colors.ClRed) 422 | } else if strings.HasPrefix(s, "[DEBUG]") { 423 | canvas.Font().SetColor(colors.ClGreen) 424 | } else if strings.HasPrefix(s, "[WARNING]") { 425 | canvas.Font().SetColor(colors.ClYellow) 426 | } 427 | canvas.Brush().SetColor(colors.ClWhite) 428 | canvas.FillRect(aRect) 429 | if state.In(types.OdSelected) { 430 | canvas.Font().SetColor(colors.ClBlue) 431 | } 432 | canvas.TextOut(aRect.Left, aRect.Top, s) 433 | } 434 | 435 | func (f *TMainForm) OnBtnCliCertOpenClick(sender vcl.IObject) { 436 | if f.DlgOpen.Execute() { 437 | f.EditTLSCliCertFile.SetText(f.DlgOpen.FileName()) 438 | } 439 | } 440 | 441 | func (f *TMainForm) OnBtnCliKeyOpenClick(sender vcl.IObject) { 442 | if f.DlgOpen.Execute() { 443 | f.EditTLSCliKeyFile.SetText(f.DlgOpen.FileName()) 444 | } 445 | } 446 | 447 | func (f *TMainForm) OnBtnSvrCertOpenClick(sender vcl.IObject) { 448 | if f.DlgOpen.Execute() { 449 | f.EditTLSSvrCertFile.SetText(f.DlgOpen.FileName()) 450 | } 451 | } 452 | 453 | func (f *TMainForm) OnBtnSvrKeyOpenClick(sender vcl.IObject) { 454 | if f.DlgOpen.Execute() { 455 | f.EditTLSSvrKeyFile.SetText(f.DlgOpen.FileName()) 456 | } 457 | } 458 | 459 | func (f *TMainForm) OnSpinMaxLogLineChange(sender vcl.IObject) { 460 | f.appCfg.WriteInteger("System", "MaxLogLine", f.SpinMaxLogLine.Value()) 461 | } 462 | 463 | func (f *TMainForm) OnPageControl1Change(sender vcl.IObject) { 464 | 465 | } 466 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rproxy 2 | ## 简单的反向代理用于内网穿透 3 | 4 | **特别注意,此工具只适合小文件类的访问测试,用来做做数据调试。当初也只是用于微信公众号开发,所以定位也是如此(注:目前代码中限制一个包最大为4M)** 5 | 6 | ### 前言 7 | 8 | 最近周末闲来无事,想起了做下微信公共号的开发,但微信限制只能80端口的,自己用的城中村的那种宽带,共用一个公网,没办法自己用路由做端口映射。自己的服务器在腾讯云上,每次都要编译完后用ftp上传再进行调试,非常的浪费时间。 一时间又不知道上哪找一个符合我的这种要求的工具,就索性自己构思了下,整个工作流程大致为: 9 | 10 | ### 工作原理 11 | 12 | 外部请求自己服务器上的HTTP服务端 -> 将数据传递给Socket服务器 -> Socket服务器将数据发送至已连接的Socket客户端 -> Socket客户端收到数据 -> 使用http请求本地http服务端 -> 本地http服务端处理相关后返回 -> Socket客户端将返回的数据发送至Socket服务端 -> Socket服务端解析出数据后原路返回至外部请求的HTTP 13 | 14 | 15 | ### 使用方法 16 | 17 | > 1、go get github.com/ying32/rproxy 18 | > 2、使用[构建命令](build) 19 | > 3、参照[命令行用例](#命令行用例)使用,或者使用[带GUI的客户端](#带GUI的客户端) 20 | 21 | 22 | ### 命令行说明 23 | ```bash 24 | --tcpport # Socket连接或者监听的端口。 25 | --httpport # 当mode为server时为服务端监听端口,当为mode为client时为转发至本地客户端的端口。 26 | --mode # 启动模式,可选为client、server,默认为client。 27 | --svraddr # 当mode为client时有效,为连接服务器的地址,不需要填写端口。 28 | --vkey # 客户端与服务端建立连接时校验的加密key,简单的。 29 | ### 以下参数为v0.6版本及之后的 30 | --ishttps # httpPort端口是否只用作HTTPS监听,默认为false。 31 | --tlscafile # 当ishttps为true时,所需的CA根证书文件。可为空,根据实际情况确定。 32 | --tlscertfile # 当ishttps为true时,所需求的TLS证书文件。 33 | --tlskeyfile # 当ishttps为true时,所需求的TLS密匙文件。 34 | --iszip # 是否开启zip压缩 35 | --cfgfile # 使用指定的配置文件中的参数,此时只有mode参数有效 36 | ``` 37 | 38 | ### 用例 39 | 40 | #### 命令行用例 41 | * HTTP: 42 | ```bash 43 | ## ---- 从命令行加载主要参数 ---- 44 | # 服务端 45 | rproxy --tcpport=8285 --httpport=8286 --mode="server" --vkey="DKibZF5TXvic1g3kY" 46 | 47 | # 客户端 48 | rproxy --tcpport=8285 --httpport=8080 --svraddr="127.0.0.1" --vkey="DKibZF5TXvic1g3kY" 49 | 50 | ## ---- 从配置文件加载主要参数 ---- 51 | # 服务端 52 | rproxy --mode="server" --cfgfile="./conf/config.cfg" 53 | 54 | # 客户端 55 | rproxy --cfgfile="./conf/config.cfg" 56 | ``` 57 | 58 | * HTTPS 59 | ```bash 60 | ## ---- 从命令行加载主要参数 ---- 61 | # 服务端 62 | rproxy --tcpport=8285 --httpport=8286 --mode="server" --ishttps=true --tlscafile="./cert/ca.pem" --tlscertfile="./cert/server.pem" --tlskeyfile="./cert/server.key" --vkey="DKibZF5TXvic1g3kY" 63 | 64 | # 客户端 65 | rproxy --tcpport=8285 --httpport=8089 --svraddr="127.0.0.1" --ishttps=true --tlscafile="./cert/ca.pem" --tlscertfile="./cert/client.pem" --tlskeyfile="./cert/client.key" --vkey="DKibZF5TXvic1g3kY" 66 | 67 | ## ---- 从配置文件加载主要参数 ---- 68 | # 服务端 69 | rproxy --mode="server" --cfgfile="./conf/confighttps.cfg" 70 | 71 | # 客户端 72 | rproxy --cfgfile="./conf/confighttps.cfg" 73 | ``` 74 | 75 | #### 带GUI的客户端 76 | [查看截图](imgs) 77 | 78 | ### 操作系统支持 79 | 80 | 支持Windows、Linux、MacOSX等,无第三方依赖库。 81 | 82 | ### 二进制下载 83 | * v0.6带GUI https://github.com/ying32/rproxy/releases/tag/v0.6 84 | * v0.5 https://github.com/ying32/rproxy/releases/tag/v0.5 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /Sample/sample.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "fmt" 7 | "io/ioutil" 8 | "net/http" 9 | ) 10 | 11 | func main() { 12 | 13 | //http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 14 | // fmt.Println("服务端请求数据了!") 15 | // fmt.Println(r) 16 | // w.Write([]byte("请求成功!")) 17 | //}) 18 | fs := http.FileServer(http.Dir("C:\\")) 19 | http.Handle("/", http.StripPrefix("/", fs)) 20 | 21 | go func() { 22 | fmt.Println("监听HTTPS 8089端口中...") 23 | certPool := x509.NewCertPool() 24 | caCertFileName := "../cert/ca.pem" 25 | caCrt, err := ioutil.ReadFile(caCertFileName) 26 | if err != nil { 27 | fmt.Println("读TLS根证书错误", err) 28 | return 29 | } 30 | ok := certPool.AppendCertsFromPEM(caCrt) 31 | if !ok { 32 | fmt.Println("CA根证书添加失败。") 33 | return 34 | } 35 | httpsSvr := &http.Server{ 36 | Addr: ":8089", 37 | Handler: nil, 38 | TLSConfig: &tls.Config{ 39 | ClientCAs: certPool, 40 | //ClientAuth: tls.RequireAndVerifyClientCert, 41 | }, 42 | } 43 | err = httpsSvr.ListenAndServeTLS("../cert/server.pem", "../cert/server.key") 44 | if err != nil { 45 | fmt.Println("开启HTTPS服务端失败:", err) 46 | } 47 | }() 48 | 49 | fmt.Println("监听HTTP 8085端口中...") 50 | if err := http.ListenAndServe(":8085", nil); err != nil { 51 | fmt.Println("开启HTTP服血端失败:", err) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /build/README.md: -------------------------------------------------------------------------------- 1 | ### 构建rproxy命令 2 | 3 | 如果要编译带界面的客户端需要加上 -tags gui 如下面的 4 | go build -i -ldflags="-H windowsgui" -tags gui -o rproxy_GUI.exe 5 | 6 | 构建带UI的客户端/服务端需要用到https://github.com/ying32/govcl 这个库。 7 | 8 | 自签HTTPS证书可使用go标准库中已经有的工具 9 | go\src\crypto\tls\generate_cert.go 10 | 11 | 最后面下面下载对应的govcl二进制: 12 | https://github.com/ying32/govcl/releases/download/v1.2.2/Librarys-1.2.2.zip 13 | 14 | 注:现rproxy中使用的二进制为govcl dev分支中的代码,相应的二进制需要自己编译。 -------------------------------------------------------------------------------- /build/build-darwin32-GUI.sh: -------------------------------------------------------------------------------- 1 | echo Compiling 32-bit rproxy GUI... 2 | 3 | # 根据你的实际情况修改这里 4 | export GOROOT=$HOME/godev/go 5 | export GOPATH=$HOME/godev/gosrc 6 | export PATH=$GOROOT/bin:$PATH 7 | 8 | export GOARCH=386 9 | export GOOS=darwin 10 | export CGO_ENABLED=1 11 | cd ../ 12 | go build -tags gui -o rproxy_GUI -------------------------------------------------------------------------------- /build/build-darwin32.sh: -------------------------------------------------------------------------------- 1 | echo Compiling 32-bit rproxy... 2 | 3 | # 根据你的实际情况修改这里 4 | export GOROOT=$HOME/godev/go 5 | export GOPATH=$HOME/godev/gosrc 6 | export PATH=$GOROOT/bin:$PATH 7 | 8 | export GOARCH=386 9 | export GOOS=darwin 10 | export CGO_ENABLED=0 11 | cd ../ 12 | go build -o rproxy -------------------------------------------------------------------------------- /build/build-darwin64-GUI.sh: -------------------------------------------------------------------------------- 1 | echo Compiling 64-bit rproxy GUI... 2 | 3 | # 根据你的实际情况修改这里 4 | export GOROOT=$HOME/godev/go 5 | export GOPATH=$HOME/godev/gosrc 6 | export PATH=$GOROOT/bin:$PATH 7 | 8 | export GOARCH=amd64 9 | export GOOS=darwin 10 | export CGO_ENABLED=1 11 | cd ../ 12 | go build -tags gui -o rproxy_GUI -------------------------------------------------------------------------------- /build/build-darwin64.sh: -------------------------------------------------------------------------------- 1 | echo Compiling 64-bit rproxy... 2 | 3 | # 根据你的实际情况修改这里 4 | export GOROOT=$HOME/godev/go 5 | export GOPATH=$HOME/godev/gosrc 6 | export PATH=$GOROOT/bin:$PATH 7 | 8 | export GOARCH=amd64 9 | export GOOS=darwin 10 | export CGO_ENABLED=0 11 | cd ../ 12 | go build -o rproxy -------------------------------------------------------------------------------- /build/build-linux32-GUI.sh: -------------------------------------------------------------------------------- 1 | echo Compiling 32-bit rproxy... 2 | 3 | # 根据你的实际情况修改这里 4 | export GOROOT=$HOME/go 5 | export PATH=$GOROOT/bin:$PATH 6 | 7 | export GOARCH=386 8 | export GOOS=linux 9 | export CGO_ENABLED=1 10 | cd ../ 11 | go build -tags gui -o rproxy_GUI -------------------------------------------------------------------------------- /build/build-linux32.sh: -------------------------------------------------------------------------------- 1 | echo Compiling 32-bit rproxy... 2 | 3 | # 根据你的实际情况修改这里 4 | export GOROOT=$HOME/go 5 | export PATH=$GOROOT/bin:$PATH 6 | 7 | export GOARCH=386 8 | export GOOS=linux 9 | export CGO_ENABLED=0 10 | cd ../ 11 | go build -o rproxy -------------------------------------------------------------------------------- /build/build-linux64-GUI.sh: -------------------------------------------------------------------------------- 1 | echo Compiling 64-bit rproxy GUI... 2 | 3 | # 根据你的实际情况修改这里 4 | export GOROOT=$HOME/go 5 | export PATH=$GOROOT/bin:$PATH 6 | 7 | export GOARCH=amd64 8 | export GOOS=linux 9 | export CGO_ENABLED=1 10 | cd ../ 11 | go build -tags gui -o rproxy_GUI -------------------------------------------------------------------------------- /build/build-linux64.sh: -------------------------------------------------------------------------------- 1 | echo Compiling 64-bit rproxy... 2 | 3 | # 根据你的实际情况修改这里 4 | export GOROOT=$HOME/go 5 | export PATH=$GOROOT/bin:$PATH 6 | 7 | export GOARCH=amd64 8 | export GOOS=linux 9 | export CGO_ENABLED=0 10 | cd ../ 11 | go build -o rproxy -------------------------------------------------------------------------------- /build/build-win32-GUI.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Compiling 32-bit rproxy GUI... 3 | 4 | set GOARCH=386 5 | set GOOS=windows 6 | set CGO_ENABLED=0 7 | cd ../ 8 | go build -i -ldflags="-H windowsgui" -tags gui -o rproxy_GUI.exe 9 | pause -------------------------------------------------------------------------------- /build/build-win32.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Compiling 32-bit rproxy... 3 | 4 | set GOARCH=386 5 | set GOOS=windows 6 | set CGO_ENABLED=0 7 | cd ../ 8 | go build -o rproxy.exe 9 | pause -------------------------------------------------------------------------------- /build/build-win64-GUI.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Compiling 64-bit rproxy GUI... 3 | 4 | set GOARCH=amd64 5 | set GOOS=windows 6 | set CGO_ENABLED=0 7 | cd ../ 8 | go build -i -ldflags="-H windowsgui" -tags gui -o rproxy_GUI.exe 9 | pause -------------------------------------------------------------------------------- /build/build-win64.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Compiling 64-bit rproxy... 3 | 4 | set GOARCH=amd64 5 | set GOOS=windows 6 | set CGO_ENABLED=0 7 | cd ../ 8 | go build -o rproxy.exe 9 | pause -------------------------------------------------------------------------------- /build/rpbuild.go: -------------------------------------------------------------------------------- 1 | /* 2 | 这是一个自己用的构建工具,一个一个的构建太麻烦了。 3 | 这里主要整合编译,打包相应平台的 4 | */ 5 | 6 | package main 7 | 8 | import ( 9 | "archive/zip" 10 | "compress/flate" 11 | "fmt" 12 | "io" 13 | "io/ioutil" 14 | "os" 15 | "os/exec" 16 | "runtime" 17 | "strings" 18 | ) 19 | 20 | func main() { 21 | 22 | switch runtime.GOOS { 23 | case "windows": 24 | windowsPkg() 25 | 26 | case "linux": 27 | linuxPkg() 28 | 29 | case "darwin": 30 | darwinPkg() 31 | } 32 | } 33 | 34 | func windowsPkg() { 35 | 36 | fmt.Println("编译rproxy-win64-GUI") 37 | if executeBash("build-win64-GUI.bat") == nil { 38 | fmt.Println("打包rproxy-win64-GUI") 39 | createZipFile("rproxy-win64-GUI.zip", true) 40 | } 41 | fmt.Println("------------------------------") 42 | 43 | fmt.Println("编译rproxy-win64") 44 | if executeBash("build-win64.bat") == nil { 45 | fmt.Println("打包rproxy-win64") 46 | createZipFile("rproxy-win64.zip", false) 47 | } 48 | fmt.Println("------------------------------") 49 | 50 | fmt.Println("编译rproxy-win32-GUI") 51 | if executeBash("build-win32-GUI.bat") == nil { 52 | fmt.Println("打包rproxy-win32-GUI") 53 | createZipFile("rproxy-win32-GUI.zip", true) 54 | } 55 | fmt.Println("------------------------------") 56 | 57 | fmt.Println("编译rproxy-win32") 58 | if executeBash("build-win32.bat") == nil { 59 | fmt.Println("打包rproxy-win32") 60 | createZipFile("rproxy-win32.zip", false) 61 | } 62 | } 63 | 64 | func linuxPkg() { 65 | 66 | fmt.Println("编译rproxy-linux64-GUI") 67 | if executeBash("build-linux64-GUI.sh") == nil { 68 | fmt.Println("打包rproxy-linux64-GUI") 69 | createZipFile("rproxy-linux64-GUI.zip", true) 70 | } 71 | fmt.Println("------------------------------") 72 | 73 | fmt.Println("编译rproxy-linux64") 74 | if executeBash("build-linux64.sh") == nil { 75 | fmt.Println("打包rproxy-linux64") 76 | createZipFile("rproxy-linux64.zip", false) 77 | } 78 | fmt.Println("------------------------------") 79 | 80 | fmt.Println("编译rproxy-linux32") 81 | if executeBash("build-linux32.sh") == nil { 82 | fmt.Println("打包rproxy-linux32") 83 | createZipFile("rproxy-linux32.zip", false) 84 | } 85 | } 86 | 87 | func darwinPkg() { 88 | 89 | fmt.Println("编译rproxy-darwin64-GUI") 90 | if executeBash("build-darwin64-GUI.sh") == nil { 91 | fmt.Println("打包rproxy-darwin64-GUI") 92 | createZipFile("rproxy-darwin64-GUI.zip", true, true) 93 | } 94 | fmt.Println("------------------------------") 95 | 96 | fmt.Println("编译rproxy-darwin64") 97 | if executeBash("build-darwin64.sh") == nil { 98 | fmt.Println("打包rproxy-darwin64") 99 | createZipFile("rproxy-darwin64.zip", false) 100 | } 101 | fmt.Println("------------------------------") 102 | 103 | //fmt.Println("编译rproxy-darwin32-GUI") 104 | //if executeBash("build-darwin32-GUI.sh") == nil { 105 | // fmt.Println("打包rproxy-darwin32-GUI") 106 | // createZipFile("rproxy-darwin32-GUI.zip", true, true) 107 | //} 108 | //fmt.Println("------------------------------") 109 | 110 | fmt.Println("编译rproxy-darwin32") 111 | if executeBash("build-darwin32.sh") == nil { 112 | fmt.Println("打包rproxy-darwin32") 113 | createZipFile("rproxy-darwin32.zip", false) 114 | } 115 | } 116 | 117 | func executeBash(fileName string) error { 118 | var cmd *exec.Cmd 119 | switch runtime.GOOS { 120 | case "windows": 121 | cmd = exec.Command("cmd.exe", "/c", fileName) 122 | default: 123 | cmd = exec.Command("sh", "./"+fileName) 124 | cmd.Stdout = os.Stdout 125 | cmd.Stderr = os.Stderr 126 | } 127 | 128 | err := cmd.Run() 129 | if err != nil { 130 | fmt.Println("执行错误:", err) 131 | } 132 | return err 133 | } 134 | 135 | func createZipFile(zipFileName string, isGUI bool, isDarwinApp ...bool) error { 136 | f, err := os.Create(zipFileName) 137 | if err != nil { 138 | return err 139 | } 140 | defer f.Close() 141 | zw := zip.NewWriter(f) 142 | defer zw.Close() 143 | 144 | zw.RegisterCompressor(zip.Deflate, 145 | func(out io.Writer) (io.WriteCloser, error) { 146 | return flate.NewWriter(out, flate.BestCompression) 147 | }) 148 | 149 | compressFile := func(fileName, aliasName string) error { 150 | ff, err := os.Open(fileName) 151 | if err != nil { 152 | return err 153 | } 154 | defer ff.Close() 155 | info, _ := ff.Stat() 156 | header, err := zip.FileInfoHeader(info) 157 | header.Method = zip.Deflate 158 | if aliasName != "" { 159 | header.Name = aliasName 160 | } else { 161 | header.Name = info.Name() 162 | } 163 | 164 | wr, err := zw.CreateHeader(header) 165 | if err != nil { 166 | return err 167 | } 168 | _, err = io.Copy(wr, ff) 169 | if err != nil { 170 | return err 171 | } 172 | return nil 173 | } 174 | 175 | // 复制文档和配置 176 | compressFile("../README.md", "") 177 | compressFile("../conf/config.cfg", "conf/config.cfg") 178 | compressFile("../conf/confighttps.cfg", "conf/confighttps.cfg") 179 | 180 | // 复制可执行文件 181 | exeExt := "" 182 | if runtime.GOOS == "windows" { 183 | exeExt = ".exe" 184 | } 185 | fnSuffix := "" 186 | if isGUI { 187 | fnSuffix = "_GUI" 188 | } 189 | 190 | if len(isDarwinApp) == 0 { 191 | compressFile("../rproxy"+fnSuffix+exeExt, "rproxy"+exeExt) 192 | } 193 | 194 | // 复制动态链接库 195 | if isGUI { 196 | switch runtime.GOOS { 197 | case "windows": 198 | liblclPath := "F:\\Golang\\src\\github.com\\ying32\\govcl\\Librarys\\liblcl" 199 | if runtime.GOARCH == "386" { 200 | compressFile(liblclPath+"\\win32\\liblcl.dll", "") 201 | } else if runtime.GOARCH == "amd64" { 202 | compressFile(liblclPath+"\\win64\\liblcl.dll", "") 203 | } 204 | case "linux": 205 | if runtime.GOARCH == "amd64" { 206 | compressFile("/usr/lib/liblcl.so", "") 207 | } 208 | case "darwin": 209 | 210 | // 产生一个app 211 | pkgMacOSApp("../rproxy_GUI") 212 | 213 | compressFile("./rproxy.app/Contents/PkgInfo", "rproxy.app/Contents/PkgInfo") 214 | compressFile("./rproxy.app/Contents/Info.plist", "rproxy.app/Contents/Info.plist") 215 | compressFile("./rproxy.app/Contents/Resources/rproxy.icns", "rproxy.app/Contents/Resources/rproxy.icns") 216 | compressFile("./rproxy.app/Contents/MacOS/rproxy", "rproxy.app/Contents/MacOS/rproxy") 217 | compressFile("./rproxy.app/Contents/MacOS/liblcl.dylib", "rproxy.app/Contents/MacOS/liblcl.dylib") 218 | 219 | } 220 | } 221 | 222 | //zw.Flush() 223 | 224 | return nil 225 | } 226 | 227 | // --- macOS下的 228 | 229 | const ( 230 | infoplist = ` 231 | 232 | 233 | 234 | CFBundleDevelopmentRegion 235 | zh_CN 236 | CFBundleExecutable 237 | %s 238 | CFBundleName 239 | %s 240 | CFBundleIdentifier 241 | ying32.%s 242 | CFBundleInfoDictionaryVersion 243 | 6.0 244 | CFBundlePackageType 245 | APPL 246 | CFBundleSignature 247 | proj 248 | CFBundleShortVersionString 249 | 0.1 250 | CFBundleVersion 251 | 1 252 | CSResourcesFileMapped 253 | 254 | CFBundleIconFile 255 | %s.icns 256 | CFBundleDocumentTypes 257 | 258 | 259 | CFBundleTypeRole 260 | Viewer 261 | CFBundleTypeExtensions 262 | 263 | * 264 | 265 | CFBundleTypeOSTypes 266 | 267 | fold 268 | disk 269 | **** 270 | 271 | 272 | 273 | NSHighResolutionCapable 274 | 275 | NSHumanReadableCopyright 276 | copyright 2017-2018 ying32.com 277 | 278 | ` 279 | ) 280 | 281 | var ( 282 | pkgInfo = []byte{0x41, 0x50, 0x50, 0x4C, 0x3F, 0x3F, 0x3F, 0x3F, 0x0D, 0x0A} 283 | ) 284 | 285 | func copyFile(src, dest string) error { 286 | filedest, err := os.Create(dest) 287 | if err != nil { 288 | return err 289 | } 290 | defer filedest.Close() 291 | filesrc, err := os.Open(src) 292 | if err != nil { 293 | return err 294 | } 295 | defer filesrc.Close() 296 | _, err = io.Copy(filedest, filesrc) 297 | return err 298 | } 299 | 300 | func fileExists(path string) bool { 301 | _, err := os.Stat(path) 302 | if err == nil { 303 | return true 304 | } 305 | if os.IsNotExist(err) { 306 | return false 307 | } 308 | return false 309 | } 310 | 311 | func getdylib() string { 312 | env := os.Getenv("GOPATH") 313 | if env == "" { 314 | return "" 315 | } 316 | for _, s := range strings.Split(env, ":") { 317 | s += "/bin/liblcl.dylib" 318 | if fileExists(s) { 319 | return s 320 | } 321 | } 322 | return "" 323 | } 324 | 325 | func pkgMacOSApp(exeFileName string) error { 326 | 327 | execName := "rproxy" 328 | macContentsDir := execName + ".app/Contents" 329 | macOSDir := macContentsDir + "/MacOS" 330 | macResources := macContentsDir + "/Resources" 331 | execFile := macOSDir + "/" + execName 332 | if !fileExists(macOSDir) { 333 | if err := os.MkdirAll(macOSDir, 0755); err != nil { 334 | return err 335 | } 336 | } 337 | 338 | if !fileExists(macResources) { 339 | os.MkdirAll(macResources, 0755) 340 | } 341 | 342 | copyFile("../imgs/rproxy.icns", macResources+"/rproxy.icns") 343 | 344 | liblclFileName := macOSDir + "/liblcl.dylib" 345 | if !fileExists(liblclFileName) { 346 | libFileName := getdylib() 347 | if fileExists(libFileName) { 348 | copyFile(libFileName, liblclFileName) 349 | } 350 | } 351 | 352 | plistFileName := macContentsDir + "/Info.plist" 353 | if !fileExists(plistFileName) { 354 | ioutil.WriteFile(plistFileName, []byte(fmt.Sprintf(infoplist, execName, execName, execName, execName)), 0666) 355 | } 356 | 357 | pkgInfoFileName := macContentsDir + "/PkgInfo" 358 | if !fileExists(pkgInfoFileName) { 359 | ioutil.WriteFile(pkgInfoFileName, pkgInfo, 0666) 360 | } 361 | 362 | copyFile(exeFileName, execFile) 363 | os.Chmod(execFile, 0755) 364 | 365 | return nil 366 | } 367 | -------------------------------------------------------------------------------- /cert/README.md: -------------------------------------------------------------------------------- 1 | 用于本地自签的测试CA证书,只适用于127.0.0.1或者localhost -------------------------------------------------------------------------------- /cert/ca.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/cert/ca.der -------------------------------------------------------------------------------- /cert/ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIICXQIBAAKBgQDN6WQxvG87CNZ/iCuH9GyXOSv9vDHdCtRb9t2VNFbGQwjGfEuR 3 | yqdYAb8s97s+CS1w57S5FylUEztwt09hxs2jKSVOIjDVODyBd/SkFwH0Tk7vqtgx 4 | 58W5sSI2F1618jbn1hLASt7GfuweffpmUbJZ4ODDH2qICftsnkaGLwZ16wIDAQAB 5 | AoGAMEjyfdc6HhXMdstvqcnfTPbTIgTnjHXlpksVWs+TKZq+jAzJi76Bz1lZgyn0 6 | dm+ggEFVV7HetyBrZ9sUelEsFxLsgbmaYjdw3vGIF8ROrtB5UOtcIu9Q3+prDT/K 7 | 3hR6o4b4Eoc4bjnhuNPpNqL2dueutVgXUAFIb6Xkzf+/v8ECQQDesnMscsWqKoBI 8 | UiNjoami+WymLyBcWRJkZs1+h3eCRtYyE5LMrJzqs+HrgB5GTlcxGxPQeNIDnSLU 9 | gPhBdgOlAkEA7LRX/jPvio3Vb3v3w+07n98EVu7tX2JFj/sdQWrvjk9aPh+JMLhm 10 | 14TRd6hZKn1MrdAhAKQEPapdzjp+yxYeTwJBAKU4I7bAV+INsir1tYe/csmU34TT 11 | xeB9vOV8V80d2A5xW4y/dNQg5DJEzsIXxV5H1Ox7uFGcscM4m5SpMoXudnkCQHxr 12 | +8jqYeLR1TxpzH4XqHzLzMspgmreDDS3ydQGMu/6NDRtfT63348wCK8+NciI3pKK 13 | 0Z41mOkVMYPi6Z00/i8CQQC8s3nEvEG4mv46OUd4zszElx1DPmSys49VcUd1X5Iy 14 | 00LLROrFk7eYgVdPuszHgTJH1xictO78Cai7OVnutdc7 15 | -----END PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /cert/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB7TCCAVagAwIBAgICBnUwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEChMHQWNt 3 | ZSBDbzAeFw0xOTA1MDcwMTQzNDhaFw0yOTA1MDcwMTQzNDhaMBIxEDAOBgNVBAoT 4 | B0FjbWUgQ28wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM3pZDG8bzsI1n+I 5 | K4f0bJc5K/28Md0K1Fv23ZU0VsZDCMZ8S5HKp1gBvyz3uz4JLXDntLkXKVQTO3C3 6 | T2HGzaMpJU4iMNU4PIF39KQXAfROTu+q2DHnxbmxIjYXXrXyNufWEsBK3sZ+7B59 7 | +mZRslng4MMfaogJ+2yeRoYvBnXrAgMBAAGjUjBQMA4GA1UdDwEB/wQEAwIChDAd 8 | BgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAO 9 | BgNVHQ4EBwQFAQIDBAUwDQYJKoZIhvcNAQELBQADgYEAvRUQjDjbGOFEFjK8RFzS 10 | R0Pek3FJQ/6dfMUJdURLG9COnK7kQ9EOyHyvjkDpzXRFRtbj1PAHC8RbM6aiq9cD 11 | gWdhN2Oi3kLnE2hAhM5awTPnSK/dgbXD09sK+7wwPWGZFWAAb6LQd6s8lTWQn2/g 12 | PLJ5gZS0ERI4cQY3eDdGFX8= 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /cert/client.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIICXQIBAAKBgQC4nAkGMyen0iwUiXs/96GJYPCFn11fBSewMsNrmxzrYXwPsjw/ 3 | /5SfioJdn5A1WkzNSEGXsWKwrmwzrxHrFl5wcd0zC3grKAMop4UfteQrjJ9HaDRw 4 | zGSxrXVzWL1IxjhHysGz8+jx9tWkSWFKewKJwBaLQBNlERtlx7dgZYY3XQIDAQAB 5 | AoGAROL8vxKBnq7fgf5XPmRiI8hHmCUCi3159NbMcy/bV731tEm3D86IIAxoXxU2 6 | k6IRfJyU1Uz83Z8IgzS1w/qB3GNKZxs+ljgZGAJI3FHB3LP7C95hJsiNrlyNc03d 7 | +x2M1U8JT5jPlarhr9by/aAWiafMGTMo+CZpK5SXeFnyxKECQQDQCBNP+9fdWRkW 8 | cnsNLJvy0bdqbpVH7Zfy4p5ytVBX+FLeQWEFNjA8LlRF5Ufwf0VZ8zwx4WgIO1d7 9 | 6ogN9EAlAkEA4y1gk31mEy31hz6adOBnL0f4Amj7WraR9CaSKREJPK7z3i9LHIQF 10 | jDkt8YMkqqYA3XUGDtUBrbb33X8Dunj42QJBAK2c77EitsZt4zgOlo8qGYQObYoP 11 | e9opeVQkuKN2mfSws0f1PCkDTkILUB18+grFzHUDP8tJGG82Rw6Nbrpmi1kCQELC 12 | Y/4TvLpoKB4NZKByDYCUeqpipXLb8fo4l30f94Hwu9OQPFdt6J9zci/l5RGM5PYv 13 | XI9hQzQEb8SUfcj/ockCQQDAGtYp0Sf41T5bJiHGTLYDlnaNsgk6yc+d5susyAqE 14 | CXqk3pxczGmNog2QN4g841oFIBquNhiRimHyjWs/UJi3 15 | -----END PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /cert/client.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB7TCCAVagAwIBAgICBnowDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEChMHQWNt 3 | ZSBDbzAeFw0xOTA1MDcwMTQzNDhaFw0yOTA1MDcwMTQzNDhaMBExDzANBgNVBAoT 4 | BkNMSUVOVDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuJwJBjMnp9IsFIl7 5 | P/ehiWDwhZ9dXwUnsDLDa5sc62F8D7I8P/+Un4qCXZ+QNVpMzUhBl7FisK5sM68R 6 | 6xZecHHdMwt4KygDKKeFH7XkK4yfR2g0cMxksa11c1i9SMY4R8rBs/Po8fbVpElh 7 | SnsCicAWi0ATZREbZce3YGWGN10CAwEAAaNTMFEwDgYDVR0PAQH/BAQDAgKEMB0G 8 | A1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAOBgNVHQ4EBwQFAQIDBAcwEAYD 9 | VR0jBAkwB4AFAQIDBAUwDQYJKoZIhvcNAQELBQADgYEAO4vPPgyQ+KJVrRiNC06Z 10 | ZpTMTmN12x/5OxJ4W+no52wk+iwtjpOnqD1BccbVogNZ1w/jAhcRSBqxE5WCvbAO 11 | PQx6/DRzCHiOt4eyEp7V/WK4N4+ndXpAxzYB5tGpUVqPpZLcoTLgPA+pgxIWtJZ0 12 | 5KAhxulex6Zx+xfoPQ8UkBA= 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /cert/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIICWwIBAAKBgQCvK3pkucsn0JdxDazSwRzsJt/zPyZLHamCqRPUebv/QlejS0U1 3 | kfE+CEuHtCZPFTqI7i01W2ViU/e6HVgmABsOgGxgV5D0DJw6At0JVXN1K8S9Ra3T 4 | vpgU3ikYZJCnRLHqt398F9oh8KKIXq8+DBQQKVuhzL2lHwQ+N1yJoFp8mwIDAQAB 5 | AoGAH0hse0CS/3FJGm+OxbSnLaVjqVVFyXRqqWL4n6F96YA3lnoCyiZeJu3kTz/k 6 | 94qbAYlHmZfQ61aDj0FeVKsAKbMhS02yRxtFOMZfkEVtCNOeDQmiVGFj8STCHVYg 7 | UT8l5Smm3Vjw5Ltd7gc3KA7cMDnwN+hFBqRxvDQLyq+1twECQQDK/4UgEdLh3cLH 8 | I5Xwqot7EvIRFTepV8u+dWWG6K8dKZ/J9lkI6ZPxLpx3pVaNo4jnyTSajU4DJXdO 9 | tq0t4J/RAkEA3OfnUAwPjB1km0H3klbcuisK5/erOaP4cP9rpHzv8SGojbthAa3v 10 | 5SWscjYw2umi8cUhl775osYXGXfeS578qwJAAexr6YLhuawtRU/MAuzKx47FZm4K 11 | Cfu//X0FSkL4LdGQJwzDiTcVZMqpRuT1LgBnsrKQYgqGu7bmK4PFnlKrkQJAMbz1 12 | VAyjI4Uqtdpwh76PDEvMtNYK83t74NVhwzNuQvi1HtRlzx7+uLV20nBpJ6EbUxxz 13 | p9sUEhZP9SgMITK26QJAagnR3N5A7DjdLg9rPmLtwJYKrHQtSbFzCD/3OeSA22OM 14 | 5clN21J0YWS+rkSm+MXGyjTc6P+gGviDnTXFW1mPTA== 15 | -----END PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /cert/server.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICCTCCAXKgAwIBAgICBnowDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEChMHQWNt 3 | ZSBDbzAeFw0xOTA1MDcwMTQzNDhaFw0yOTA1MDcwMTQzNDhaMBExDzANBgNVBAoT 4 | BlNFUlZFUjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAryt6ZLnLJ9CXcQ2s 5 | 0sEc7Cbf8z8mSx2pgqkT1Hm7/0JXo0tFNZHxPghLh7QmTxU6iO4tNVtlYlP3uh1Y 6 | JgAbDoBsYFeQ9AycOgLdCVVzdSvEvUWt076YFN4pGGSQp0Sx6rd/fBfaIfCiiF6v 7 | PgwUEClbocy9pR8EPjdciaBafJsCAwEAAaNvMG0wDgYDVR0PAQH/BAQDAgKEMB0G 8 | A1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAOBgNVHQ4EBwQFAQIDBAYwEAYD 9 | VR0jBAkwB4AFAQIDBAUwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqG 10 | SIb3DQEBCwUAA4GBAK2IYzY2Wk4up0HGKjfyfUvOjo5KLu1CTa3h7jSSL5lZfWs9 11 | bsHsFHnHDvHZWEL0SfsyY0ZoILXNn7d5ilnPhZr105TzKzGEuOczt7f277YFLhIb 12 | e8U6Bf2t9ambaF/g3TAmWcpMF+eGWAPv/L72OpiUuNj/kv1dICc3QV+9h7xf 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /conf/config.cfg: -------------------------------------------------------------------------------- 1 | { 2 | "tcpport": 8285, 3 | "vkey": "DKibZF5TXvic1g3kY", 4 | "ishttps": false, 5 | "tlscafile": "./cert/ca.pem", 6 | "iszip": true, 7 | "server": { 8 | "httpport": 8286, 9 | "tlscertfile": "./cert/server.pem", 10 | "tlskeyfile": "./cert/server.key" 11 | }, 12 | "client": { 13 | "svraddr": "127.0.0.1", 14 | "httpport": 8080, 15 | "tlscertfile": "./cert/client.pem", 16 | "tlskeyfile": "./cert/client.key" 17 | } 18 | } -------------------------------------------------------------------------------- /conf/confighttps.cfg: -------------------------------------------------------------------------------- 1 | { 2 | "tcpport": 8285, 3 | "vkey": "DKibZF5TXvic1g3kY", 4 | "ishttps": true, 5 | "tlscafile": "./cert/ca.pem", 6 | "iszip": true, 7 | "server": { 8 | "httpport": 8286, 9 | "tlscertfile": "./cert/server.pem", 10 | "tlskeyfile": "./cert/server.key" 11 | }, 12 | "client": { 13 | "svraddr": "127.0.0.1", 14 | "httpport": 8089, 15 | "tlscertfile": "./cert/client.pem", 16 | "tlskeyfile": "./cert/client.key" 17 | } 18 | } -------------------------------------------------------------------------------- /icon_posix.go: -------------------------------------------------------------------------------- 1 | // +build !windows,gui 2 | 3 | package main 4 | 5 | var ( 6 | mainIconBytes = []byte{ 7 | 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x00, 8 | 0x18, 0x00, 0x68, 0x03, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00, 9 | 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 10 | 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 11 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 12 | 0x00, 0x00, 0x6C, 0x5C, 0x25, 0x60, 0x53, 0x28, 0xD9, 0xD7, 0xD5, 0xFF, 13 | 0xFF, 0xFF, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 14 | 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFC, 0xFE, 0xFE, 0xF5, 15 | 0xF9, 0xF9, 0xE4, 0xEF, 0xF3, 0xBE, 0xD1, 0xD7, 0x66, 0x5C, 0x34, 0x6F, 16 | 0x5C, 0x26, 0x86, 0x6C, 0x26, 0x73, 0x5A, 0x1C, 0xD9, 0xD6, 0xD0, 0xFF, 17 | 0xFF, 0xFF, 0xFD, 0xFD, 0xFC, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 18 | 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFC, 0xFE, 0xFD, 0xF4, 19 | 0xF8, 0xF8, 0xE3, 0xF0, 0xF4, 0xBA, 0xCD, 0xD2, 0x76, 0x60, 0x26, 0x89, 20 | 0x6F, 0x28, 0x8A, 0x87, 0x61, 0x82, 0x91, 0x84, 0xD2, 0xD3, 0xD1, 0xFF, 21 | 0xFF, 0xFF, 0xFD, 0xFD, 0xFC, 0xFE, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 22 | 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFC, 0xFE, 0xFE, 0xF3, 23 | 0xF8, 0xF8, 0xE2, 0xF1, 0xF5, 0xB4, 0xC7, 0xCB, 0x80, 0x87, 0x72, 0x8C, 24 | 0x7D, 0x44, 0x97, 0x85, 0x46, 0x87, 0x8B, 0x6D, 0xCD, 0xD0, 0xCF, 0xFF, 25 | 0xFF, 0xFF, 0xFD, 0xFD, 0xFC, 0xFD, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFD, 26 | 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xF3, 27 | 0xF8, 0xF8, 0xE3, 0xF1, 0xF4, 0xB1, 0xC5, 0xCB, 0x8A, 0x9A, 0x8C, 0x93, 28 | 0x81, 0x42, 0xA6, 0x84, 0x2C, 0x8C, 0x6C, 0x1D, 0xD6, 0xD2, 0xCB, 0xFF, 29 | 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 30 | 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xF3, 31 | 0xF6, 0xF6, 0xE1, 0xF0, 0xF6, 0xAE, 0xBE, 0xBE, 0x8C, 0x6D, 0x20, 0xA4, 32 | 0x84, 0x2F, 0xAB, 0x89, 0x2D, 0x96, 0x7D, 0x38, 0xE2, 0xE2, 0xE0, 0xFF, 33 | 0xFF, 0xFF, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFA, 34 | 0xFA, 0xFA, 0xFB, 0xFC, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xF3, 35 | 0xF7, 0xF7, 0xDE, 0xEE, 0xF5, 0xAA, 0xBC, 0xBC, 0x97, 0x7B, 0x2D, 0xAC, 36 | 0x8B, 0x35, 0xB2, 0x8B, 0x28, 0x9E, 0x84, 0x43, 0xEC, 0xED, 0xEE, 0xFE, 37 | 0xFE, 0xFE, 0xFC, 0xFC, 0xFC, 0xFE, 0xFE, 0xFD, 0xFB, 0xFA, 0xFA, 0xD1, 38 | 0xCF, 0xCE, 0xDC, 0xDA, 0xD9, 0xFF, 0xFE, 0xFD, 0xFD, 0xFC, 0xFC, 0xF1, 39 | 0xF5, 0xF6, 0xD9, 0xEC, 0xF3, 0xA7, 0xBA, 0xBA, 0x9E, 0x7F, 0x2E, 0xB4, 40 | 0x91, 0x36, 0xBA, 0x91, 0x29, 0xA2, 0x88, 0x46, 0xEC, 0xED, 0xF0, 0xFE, 41 | 0xFE, 0xFE, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xCF, 0xDA, 0xDE, 0xCC, 42 | 0xD8, 0xDB, 0xC0, 0xD0, 0xD4, 0xDD, 0xE4, 0xE7, 0xFF, 0xFF, 0xFF, 0xEE, 43 | 0xF4, 0xF5, 0xD4, 0xE8, 0xF0, 0xA4, 0xB8, 0xB7, 0xA5, 0x84, 0x2E, 0xBB, 44 | 0x96, 0x37, 0xC4, 0x99, 0x30, 0xAF, 0x8D, 0x3C, 0xE6, 0xE4, 0xE1, 0xFF, 45 | 0xFF, 0xFF, 0xF6, 0xF6, 0xF0, 0xE8, 0xE8, 0xDD, 0xC4, 0xCE, 0xCE, 0x58, 46 | 0x64, 0x68, 0x84, 0x93, 0x97, 0xE0, 0xE6, 0xE4, 0xEA, 0xEA, 0xE3, 0xE4, 47 | 0xED, 0xEF, 0xCE, 0xE7, 0xF1, 0xA1, 0xB1, 0xA9, 0xB2, 0x8B, 0x2D, 0xC2, 48 | 0x9B, 0x3A, 0xD7, 0xA6, 0x36, 0x96, 0x7D, 0x35, 0xD6, 0xDB, 0xDB, 0xE9, 49 | 0xE9, 0xE5, 0xAB, 0xAB, 0xA2, 0xF7, 0xF7, 0xE7, 0xEE, 0xED, 0xD2, 0xA9, 50 | 0xA7, 0xA3, 0xAD, 0xAB, 0xA4, 0xE1, 0xE1, 0xD1, 0xF1, 0xF2, 0xDE, 0xD7, 51 | 0xDC, 0xCD, 0xC3, 0xE0, 0xEF, 0x97, 0x9E, 0x89, 0xC1, 0x92, 0x28, 0xC5, 52 | 0x9E, 0x3C, 0xAF, 0x8E, 0x39, 0x3D, 0x6E, 0x76, 0x91, 0xA1, 0xAA, 0xDD, 53 | 0xD9, 0xCE, 0x4A, 0x4A, 0x43, 0xF1, 0xF2, 0xE9, 0xF7, 0xFA, 0xD6, 0xFF, 54 | 0xFF, 0xF4, 0x8D, 0x8D, 0x85, 0x6D, 0x6D, 0x6D, 0xFF, 0xFF, 0xFF, 0xE9, 55 | 0xEC, 0xCB, 0xB5, 0xCB, 0xCF, 0x4E, 0x74, 0x82, 0x8D, 0x86, 0x4C, 0xD8, 56 | 0xA5, 0x30, 0xB6, 0x8F, 0x33, 0x50, 0x7C, 0x7E, 0x34, 0x68, 0x82, 0xBF, 57 | 0xC3, 0xC4, 0xF4, 0xF7, 0xE7, 0xF8, 0xFA, 0xDE, 0xE8, 0xE8, 0xCC, 0xF3, 58 | 0xF2, 0xF0, 0xDF, 0xDE, 0xD1, 0xE7, 0xE7, 0xC9, 0xFD, 0xFE, 0xDC, 0xD8, 59 | 0xE6, 0xD9, 0x72, 0x91, 0xA2, 0x1D, 0x5E, 0x82, 0x78, 0x86, 0x66, 0xE3, 60 | 0xA8, 0x2A, 0xDB, 0xA9, 0x35, 0xBE, 0x99, 0x3C, 0x9F, 0x8E, 0x47, 0xAD, 61 | 0x8F, 0x43, 0xBD, 0xAF, 0x8D, 0xCE, 0xCC, 0xC1, 0xE4, 0xE5, 0xE6, 0xF2, 62 | 0xF7, 0xFC, 0xEA, 0xF2, 0xF9, 0xD4, 0xDE, 0xDA, 0xBC, 0xC7, 0xBD, 0xA5, 63 | 0xA1, 0x84, 0x86, 0x80, 0x4E, 0x7D, 0x84, 0x5D, 0xC1, 0x9A, 0x39, 0xD7, 64 | 0xA7, 0x39, 0xD1, 0xA4, 0x39, 0xD7, 0xA7, 0x38, 0xDD, 0xA9, 0x36, 0xD8, 65 | 0xA7, 0x35, 0xCB, 0x9C, 0x2D, 0xBF, 0x98, 0x3B, 0xBB, 0x9A, 0x4C, 0xB9, 66 | 0x9D, 0x59, 0xB6, 0x9E, 0x60, 0xB5, 0x9C, 0x5A, 0xB8, 0x96, 0x40, 0xCD, 67 | 0x9D, 0x2F, 0xDC, 0xA8, 0x34, 0xDC, 0xA7, 0x32, 0xD6, 0xA7, 0x38, 0xD2, 68 | 0xA4, 0x39, 0xD3, 0xA5, 0x39, 0xD3, 0xA5, 0x39, 0xD1, 0xA4, 0x39, 0xD1, 69 | 0xA4, 0x39, 0xD4, 0xA6, 0x3B, 0xD6, 0xA7, 0x37, 0xD6, 0xA6, 0x34, 0xD5, 70 | 0xA4, 0x31, 0xD4, 0xA3, 0x30, 0xD6, 0xA4, 0x30, 0xD7, 0xA7, 0x36, 0xD4, 71 | 0xA6, 0x3A, 0xD1, 0xA4, 0x3A, 0xD1, 0xA4, 0x3A, 0xD3, 0xA5, 0x3A, 0xD3, 72 | 0xA5, 0x39, 0xD3, 0xA5, 0x3A, 0xD3, 0xA5, 0x39, 0xD3, 0xA5, 0x39, 0xD3, 73 | 0xA5, 0x39, 0xD1, 0xA4, 0x38, 0xD0, 0xA3, 0x39, 0xD1, 0xA5, 0x3C, 0xD2, 74 | 0xA6, 0x3D, 0xD3, 0xA6, 0x3D, 0xD1, 0xA5, 0x3B, 0xD0, 0xA3, 0x3A, 0xD3, 75 | 0xA4, 0x39, 0xD3, 0xA5, 0x39, 0xD3, 0xA5, 0x38, 0xD4, 0xA6, 0x39, 0xD4, 76 | 0xA5, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 77 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 78 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 82 | ) 83 | -------------------------------------------------------------------------------- /icon_windows.go: -------------------------------------------------------------------------------- 1 | // +build gui 2 | 3 | package main 4 | 5 | var ( 6 | mainIconBytes = []byte{} 7 | ) 8 | -------------------------------------------------------------------------------- /imgs/README.md: -------------------------------------------------------------------------------- 1 | ![rp_windows.jpg](rp_windows.jpg) 2 | ![rp_linux.jpg](rp_linux.jpg) 3 | ![rp_macOS.jpg](rp_macOS.jpg) -------------------------------------------------------------------------------- /imgs/cli.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/imgs/cli.jpg -------------------------------------------------------------------------------- /imgs/rp_linux.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/imgs/rp_linux.jpg -------------------------------------------------------------------------------- /imgs/rp_macOS.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/imgs/rp_macOS.jpg -------------------------------------------------------------------------------- /imgs/rp_windows.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/imgs/rp_windows.jpg -------------------------------------------------------------------------------- /imgs/rproxy.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/imgs/rproxy.icns -------------------------------------------------------------------------------- /imgs/rproxy.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/imgs/rproxy.ico -------------------------------------------------------------------------------- /imgs/rproxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/imgs/rproxy.png -------------------------------------------------------------------------------- /imgs/svr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/imgs/svr.jpg -------------------------------------------------------------------------------- /librp/client.go: -------------------------------------------------------------------------------- 1 | package librp 2 | 3 | import ( 4 | "crypto/tls" 5 | "errors" 6 | "fmt" 7 | "net" 8 | "net/http" 9 | ) 10 | 11 | type TRPClient struct { 12 | IRPObject 13 | conn net.Conn 14 | running bool 15 | } 16 | 17 | func NewRPClient() *TRPClient { 18 | c := new(TRPClient) 19 | return c 20 | } 21 | 22 | func (c *TRPClient) Start() error { 23 | conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", conf.Client.SvrAddr, conf.TCPPort)) 24 | if err != nil { 25 | return err 26 | } 27 | c.running = true 28 | c.conn = conn 29 | return c.process() 30 | } 31 | 32 | func (c *TRPClient) process() error { 33 | // 首先请求验证 34 | if _, err := c.conn.Write(EncodeVerify()); err != nil { 35 | return err 36 | } 37 | err := readPacket(c.conn, func(cmd uint16, data []byte) error { 38 | if cmd == PacketVerify { 39 | if string(data) == "ok" { 40 | return nil 41 | } 42 | } 43 | return errors.New("验证失败。") 44 | }) 45 | if err != nil { 46 | return err 47 | } 48 | 49 | keepALive(c.conn) 50 | Log.I("已连接服务端。") 51 | 52 | doHTTPClient := func(req *http.Request) ([]byte, error) { 53 | rawQuery := "" 54 | if req.URL.RawQuery != "" { 55 | rawQuery = "?" + req.URL.RawQuery 56 | } 57 | Log.I(req.Method + " " + req.URL.Path + rawQuery) 58 | // 请求本地指定的HTTP服务器 59 | client := new(http.Client) 60 | 61 | if conf.IsHTTPS { 62 | client.Transport = &http.Transport{ 63 | TLSClientConfig: &tls.Config{ 64 | RootCAs: conf.certPool, 65 | Certificates: []tls.Certificate{conf.cliCert}, 66 | }, 67 | } 68 | } 69 | 70 | client.CheckRedirect = func(req *http.Request, via []*http.Request) error { 71 | return http.ErrUseLastResponse 72 | } 73 | resp, err := client.Do(req) 74 | 75 | if err != nil { 76 | return nil, err 77 | } 78 | defer resp.Body.Close() 79 | respBytes, err := EncodeResponse(resp) 80 | if err != nil { 81 | return nil, err 82 | } 83 | 84 | return respBytes, nil 85 | } 86 | 87 | // read循环 88 | for c.running { 89 | err := readPacket(c.conn, func(cmd uint16, data []byte) error { 90 | switch cmd { 91 | case PacketCmd1: 92 | // Decode请求 93 | 94 | req, err := DecodeRequest(data, conf.Client.LocalAddr, conf.Client.HTTPPort, conf.IsHTTPS) 95 | if err != nil { 96 | return wError(c.conn, err) 97 | } 98 | respBytes, err := doHTTPClient(req) 99 | if err != nil { 100 | return wError(c.conn, err) 101 | } 102 | _, err = c.conn.Write(respBytes) 103 | if err != nil { 104 | // 写出错了,这里要退出 105 | return err 106 | } 107 | case PackageError: 108 | Log.E(string(data)) 109 | } 110 | 111 | return nil 112 | }) 113 | // read出错,退出 114 | if err != nil { 115 | return err 116 | } 117 | } 118 | return nil 119 | } 120 | 121 | func (c *TRPClient) Close() error { 122 | c.running = false 123 | if c.conn != nil { 124 | err := c.conn.Close() 125 | c.conn = nil 126 | return err 127 | } 128 | return errors.New("TCP实例未创建") 129 | } 130 | -------------------------------------------------------------------------------- /librp/common.go: -------------------------------------------------------------------------------- 1 | package librp 2 | 3 | import ( 4 | "bytes" 5 | "compress/zlib" 6 | "crypto/sha1" 7 | "crypto/tls" 8 | "crypto/x509" 9 | "io" 10 | "io/ioutil" 11 | "net" 12 | "path/filepath" 13 | "strings" 14 | ) 15 | 16 | var ( 17 | // 全局配置文件 18 | conf = initConfig() 19 | ) 20 | 21 | const ( 22 | CLIENT = "client" 23 | SERVER = "server" 24 | errorHTML = ` 25 | 26 | 27 | 28 | (*>﹏<*)错误啦 29 | 32 | 33 | 34 |

请求错误啦

35 |

(*>﹏<*)您要访问的页面目前无法使用
36 | 要不等一会再试试吧。。。

37 |

本服务由[rproxy]所提供。

38 | 39 | ` 40 | ) 41 | 42 | func initConfig() *TRProxyConfig { 43 | cfg := new(TRProxyConfig) 44 | if cfg.certPool == nil { 45 | cfg.certPool = x509.NewCertPool() 46 | } 47 | return cfg 48 | } 49 | 50 | // 设置配置文件 51 | func SetConfig(cfg *TRProxyConfig) { 52 | 53 | // 复制字段 54 | conf.TCPPort = cfg.TCPPort 55 | conf.VerifyKey = cfg.VerifyKey 56 | conf.IsHTTPS = cfg.IsHTTPS 57 | conf.TLSCAFile = cfg.TLSCAFile 58 | conf.IsZIP = cfg.IsZIP 59 | 60 | // server 61 | conf.Server.TLSCertFile = cfg.Server.TLSCertFile 62 | conf.Server.TLSKeyFile = cfg.Server.TLSKeyFile 63 | conf.Server.HTTPPort = cfg.Server.HTTPPort 64 | // client 65 | conf.Client.SvrAddr = cfg.Client.SvrAddr 66 | conf.Client.HTTPPort = cfg.Client.HTTPPort 67 | conf.Client.TLSCertFile = cfg.Client.TLSCertFile 68 | conf.Client.TLSKeyFile = cfg.Client.TLSKeyFile 69 | 70 | if conf.Client.TLSCertFile != "" && conf.Client.TLSKeyFile != "" { 71 | var err error 72 | conf.cliCert, err = tls.LoadX509KeyPair(conf.Client.TLSCertFile, conf.Client.TLSKeyFile) 73 | if err != nil { 74 | Log.E(err) 75 | } 76 | } else { 77 | conf.cliCert = tls.Certificate{} 78 | } 79 | // 初始KEY 80 | conf.verifyVal = sha1.Sum([]byte("I AM A KEY:" + conf.VerifyKey)) 81 | 82 | addRootCert() 83 | } 84 | 85 | func GetConfig() *TRProxyConfig { 86 | return conf 87 | } 88 | 89 | // 从 xxx.xxx.xxx.xxx:xxx格式中取出ip地址 90 | func IPStr(conn net.Conn) string { 91 | if conn == nil { 92 | return "" 93 | } 94 | ip := conn.RemoteAddr().String() 95 | i := strings.LastIndex(ip, ":") 96 | if i == -1 { 97 | return ip 98 | } 99 | return ip[:i] 100 | } 101 | 102 | // ExtractFilePath 提取文件名路径 103 | func ExtractFilePath(path string) string { 104 | filename := filepath.Base(path) 105 | return path[:len(path)-len(filename)] 106 | } 107 | 108 | // 添加CA根证书 109 | func addRootCert() { 110 | if !conf.IsHTTPS { 111 | return 112 | } 113 | if conf.TLSCAFile == "" { 114 | Log.E("CA根证书文件不存在。") 115 | } 116 | bs, err := ioutil.ReadFile(conf.TLSCAFile) 117 | if err != nil { 118 | Log.E(err) 119 | return 120 | } 121 | if ok := conf.certPool.AppendCertsFromPEM(bs); !ok { 122 | Log.E("添加CA根证书失败。") 123 | } 124 | } 125 | 126 | // zlib解压缩 127 | func ZlibUnCompress(input []byte) ([]byte, error) { 128 | var out bytes.Buffer 129 | r, err := zlib.NewReader(bytes.NewReader(input)) 130 | if err != nil { 131 | return nil, err 132 | } 133 | defer r.Close() 134 | _, err = io.Copy(&out, r) 135 | if err != nil { 136 | return nil, nil 137 | } 138 | return out.Bytes(), nil 139 | } 140 | 141 | // zlib压缩 142 | func ZlibCompress(input []byte) ([]byte, error) { 143 | var in bytes.Buffer 144 | w, err := zlib.NewWriterLevel(&in, zlib.BestCompression) 145 | if err != nil { 146 | return nil, err 147 | } 148 | _, err = w.Write(input) 149 | if err != nil { 150 | return nil, err 151 | } 152 | err = w.Close() 153 | if err != nil { 154 | return nil, err 155 | } 156 | return in.Bytes(), nil 157 | } 158 | -------------------------------------------------------------------------------- /librp/config.go: -------------------------------------------------------------------------------- 1 | package librp 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "encoding/json" 7 | "io/ioutil" 8 | ) 9 | 10 | // 配置文件,一个json文件,可包含客户端和服务端配置 11 | type TRProxyConfig struct { 12 | // 不导出字段 13 | certPool *x509.CertPool // 这个字段不导出的,只内部使用 14 | cliCert tls.Certificate // 这个字段不导出的,只内部使用 15 | verifyVal [20]byte // 验证的值 16 | 17 | // 导出的字段 18 | TCPPort int `json:"tcpport"` // Socket连接或者监听的端口 19 | VerifyKey string `json:"vkey"` // 用作客户端与服务端连接时的校验 20 | IsHTTPS bool `json:"ishttps"` // httpPort端口是否只用作HTTPS监听 21 | TLSCAFile string `json:"tlscafile"` // 当ishttps为true时,所需的CA根证书文件 22 | IsZIP bool `json:"iszip"` // 是否开启zip压缩 23 | Server struct { 24 | HTTPPort int `json:"httpport"` // 当mode为server时为服务端监听端口,当为mode为client时为转发至本地客户端的端口 25 | TLSCertFile string `json:"tlscertfile"` // 当ishttps为true时,所需求的TLS证书文件 26 | TLSKeyFile string `json:"tlskeyfile"` // 当ishttps为true时,所需求的TLS密匙文件 27 | } `json:"server"` 28 | Client struct { 29 | SvrAddr string `json:"svraddr"` // 127.0.0.1", "当mode为client时有效,为连接服务器的地址 30 | HTTPPort int `json:"httpport"` // 当mode为server时为服务端监听端口,当为mode为client时为转发至本地客户端的端口 31 | TLSCertFile string `json:"tlscertfile"` // 当ishttps为true时,所需求的TLS证书文件 32 | TLSKeyFile string `json:"tlskeyfile"` // 当ishttps为true时,所需求的TLS密匙文件 33 | LocalAddr string `json:"localaddr"` // 转发至本地的地址,默认为127.0.0.1 34 | } `json:"client"` 35 | } 36 | 37 | func LoadConfig(fileName string, cfg *TRProxyConfig) error { 38 | bs, err := ioutil.ReadFile(fileName) 39 | if err != nil { 40 | return err 41 | } 42 | return json.Unmarshal(bs, cfg) 43 | } 44 | 45 | func SaveConfig(fileName string, cfg *TRProxyConfig) error { 46 | bs, err := json.MarshalIndent(cfg, "", "\t") 47 | if err != nil { 48 | return err 49 | } 50 | return ioutil.WriteFile(fileName, bs, 0666) 51 | } 52 | -------------------------------------------------------------------------------- /librp/log.go: -------------------------------------------------------------------------------- 1 | package librp 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | ) 8 | 9 | var ( 10 | DEBUG = false // 调试模式 输出 Log.D 字符 11 | IsGUI = false // 是否为GUI 12 | LogGUICallback func(msg string) // 当IsGUI=true时,不再输出到日志,使用当前回调函数 13 | ) 14 | 15 | type Logger struct { 16 | } 17 | 18 | var Log Logger 19 | 20 | var std = log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile) 21 | 22 | func (l Logger) println(calldepth int, flag string, v ...interface{}) { 23 | msg := fmt.Sprintf("[%s]: %s", flag, fmt.Sprint(v...)) 24 | if IsGUI { 25 | if LogGUICallback != nil { 26 | LogGUICallback(msg) 27 | } 28 | return 29 | } 30 | std.Output(calldepth, msg) 31 | } 32 | 33 | // 警告 34 | func (l Logger) W(v ...interface{}) { 35 | textYellow() 36 | l.println(3, "WARNING", v...) 37 | } 38 | 39 | // 错误 40 | func (l Logger) E(v ...interface{}) { 41 | textRed() 42 | l.println(3, "ERROR", v...) 43 | } 44 | 45 | func (l Logger) EF(v ...interface{}) { 46 | textRed() 47 | l.println(3, "ERROR", v...) 48 | // 非GUI模式下才退出,APP就挂了 49 | if !IsGUI { 50 | os.Exit(1) 51 | } 52 | } 53 | 54 | // 信息 55 | func (l Logger) I(v ...interface{}) { 56 | textDefault() 57 | l.println(3, "INFO", v...) 58 | } 59 | 60 | // 调试 61 | func (l Logger) D(v ...interface{}) { 62 | if DEBUG { 63 | textGreen() 64 | l.println(3, "DEBUG", v...) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /librp/log_posix.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package librp 4 | 5 | import "fmt" 6 | 7 | func textColor(cr uint16) { 8 | if IsGUI { 9 | return 10 | } 11 | fmt.Print(fmt.Sprintf("\033[0;%dm", cr)) 12 | } 13 | func textRed() { 14 | textColor(31) 15 | } 16 | 17 | func textYellow() { 18 | textColor(33) 19 | } 20 | 21 | func textGreen() { 22 | textColor(32) 23 | } 24 | 25 | func textDefault() { 26 | textColor(37) 27 | } 28 | -------------------------------------------------------------------------------- /librp/log_windows.go: -------------------------------------------------------------------------------- 1 | package librp 2 | 3 | import ( 4 | "syscall" 5 | ) 6 | 7 | const ( 8 | STD_OUTPUT_HANDLE = ^uint32(11) 9 | ) 10 | 11 | var ( 12 | kernel32 = syscall.NewLazyDLL("kernel32.dll") 13 | _GetStdHandle = kernel32.NewProc("GetStdHandle") 14 | _SetConsoleTextAttribute = kernel32.NewProc("SetConsoleTextAttribute") 15 | 16 | windowsConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE) 17 | ) 18 | 19 | func GetStdHandle(nStdHandle uint32) uintptr { 20 | ret, _, _ := _GetStdHandle.Call(uintptr(nStdHandle)) 21 | return ret 22 | } 23 | 24 | func SetConsoleTextAttribute(hConsoleOutput uintptr, wAttributes uint16) bool { 25 | ret, _, _ := _SetConsoleTextAttribute.Call(hConsoleOutput, uintptr(wAttributes)) 26 | return ret != 0 27 | } 28 | 29 | func textColor(cr uint16) { 30 | if IsGUI { 31 | return 32 | } 33 | if windowsConsoleHandle <= 0 { 34 | return 35 | } 36 | SetConsoleTextAttribute(windowsConsoleHandle, cr) 37 | } 38 | 39 | func textRed() { 40 | textColor(8 | 4) // 8 | 4 41 | } 42 | 43 | func textYellow() { 44 | textColor(8 | 6) //8|6 45 | } 46 | 47 | func textGreen() { 48 | textColor(8 | 2) 49 | } 50 | 51 | func textDefault() { 52 | textColor(7) // 7 53 | } 54 | -------------------------------------------------------------------------------- /librp/net.go: -------------------------------------------------------------------------------- 1 | package librp 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "encoding/binary" 7 | "errors" 8 | "fmt" 9 | "net" 10 | "net/http" 11 | "net/http/httputil" 12 | "net/url" 13 | "reflect" 14 | "strconv" 15 | "time" 16 | ) 17 | 18 | const ( 19 | PacketHead uint8 = 0x02 20 | PacketTail uint8 = 0x03 21 | 22 | PacketCmd1 uint16 = 1000 23 | PacketVerify uint16 = 1001 24 | PackageError uint16 = 1002 25 | 26 | PacketVersion uint16 = 0x02 27 | ) 28 | 29 | type TPacketHead struct { 30 | //Head uint8 31 | Version uint16 // 2 32 | Cmd uint16 // 2 33 | IsZip uint16 // 2 34 | DataLen uint32 // 4 35 | //Data []byte 36 | //Tail uint8 37 | } 38 | 39 | type IRPObject interface { 40 | Start() error 41 | Close() error 42 | } 43 | 44 | var ( 45 | // 封包头的结构长度 46 | PacketHeadLen = getPacketHeadSize() //8 47 | ) 48 | 49 | func getPacketHeadSize() (size uintptr) { 50 | t := reflect.TypeOf(TPacketHead{}) 51 | for i := 0; i < t.NumField(); i++ { 52 | size += t.Field(i).Type.Size() 53 | } 54 | return 55 | } 56 | 57 | // 编码数据 58 | func EncodeCmd(cmd uint16, data []byte) []byte { 59 | raw := bytes.NewBuffer([]byte{}) 60 | head := TPacketHead{} 61 | head.Version = PacketVersion 62 | head.Cmd = cmd 63 | head.IsZip = 0 64 | if conf.IsZIP { 65 | head.IsZip = 1 66 | 67 | // 压缩数据 68 | temp, err := ZlibCompress(data) 69 | if err != nil { 70 | Log.E(err) 71 | } else { 72 | Log.D("压缩,原长度:", len(data)) 73 | data = temp 74 | Log.D("压缩,现长度:", len(data)) 75 | } 76 | } 77 | head.DataLen = uint32(len(data)) 78 | 79 | binary.Write(raw, binary.LittleEndian, PacketHead) 80 | binary.Write(raw, binary.LittleEndian, head) 81 | raw.Write(data) 82 | binary.Write(raw, binary.LittleEndian, PacketTail) 83 | return raw.Bytes() 84 | } 85 | 86 | // DecodeHead 87 | func DecodeHead(data []byte) *TPacketHead { 88 | head := new(TPacketHead) 89 | raw := bytes.NewBuffer(data) 90 | binary.Read(raw, binary.LittleEndian, head) 91 | 92 | return head 93 | } 94 | 95 | // 编码验证包 96 | func EncodeVerify() []byte { 97 | return EncodeCmd(PacketVerify, conf.verifyVal[:]) 98 | } 99 | 100 | // 验证成功回写 101 | func EncodeVerifyOK() []byte { 102 | return EncodeCmd(PacketVerify, []byte("ok")) 103 | } 104 | 105 | // 验证失败回写 106 | func EncodeVerifyFailed() []byte { 107 | return EncodeCmd(PacketVerify, []byte("failed")) 108 | } 109 | 110 | // 将request 的处理 111 | func EncodeRequest(r *http.Request) ([]byte, error) { 112 | reqBytes, err := httputil.DumpRequest(r, true) 113 | if err != nil { 114 | return nil, err 115 | } 116 | return EncodeCmd(PacketCmd1, reqBytes), err 117 | } 118 | 119 | // 将字节转为request 120 | func DecodeRequest(data []byte, reqHost string, port int, isHttps bool) (*http.Request, error) { 121 | req, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(data))) 122 | if err != nil { 123 | return nil, err 124 | } 125 | if reqHost == "" { 126 | reqHost = "127.0.0.1" 127 | } 128 | req.Host = reqHost 129 | scheme := "http" 130 | if isHttps { 131 | scheme = "https" 132 | if port != 443 { 133 | req.Host += ":" + strconv.Itoa(port) 134 | } 135 | } else { 136 | if port != 80 { 137 | req.Host += ":" + strconv.Itoa(port) 138 | } 139 | } 140 | req.URL, _ = url.Parse(fmt.Sprintf("%s://%s%s", scheme, req.Host, req.RequestURI)) 141 | req.RequestURI = "" 142 | 143 | return req, nil 144 | } 145 | 146 | // 将response转为字节 147 | func EncodeResponse(r *http.Response) ([]byte, error) { 148 | respBytes, err := httputil.DumpResponse(r, true) 149 | if err != nil { 150 | return nil, err 151 | } 152 | return EncodeCmd(PacketCmd1, respBytes), err 153 | } 154 | 155 | //// 将字节转为response 156 | func DecodeResponse(data []byte) (*http.Response, error) { 157 | 158 | resp, err := http.ReadResponse(bufio.NewReader(bytes.NewReader(data)), nil) 159 | if err != nil { 160 | return nil, err 161 | } 162 | return resp, nil 163 | } 164 | 165 | //-------------------------一些简化--------------------------- 166 | 167 | // 写错误 168 | func wError(conn net.Conn, err error) error { 169 | return wData(conn, EncodeCmd(PackageError, []byte(err.Error()))) 170 | } 171 | 172 | // 写数据 173 | func wData(conn net.Conn, data []byte) error { 174 | if conn == nil { 175 | return errors.New("连接无效。") 176 | } 177 | // 先不理写入的 178 | _, err := conn.Write(data) 179 | return err 180 | } 181 | 182 | // 读数据 183 | func rData(conn net.Conn, bLen int) ([]byte, error) { 184 | bsBuff := bytes.NewBuffer([]byte{}) 185 | bufLen := bLen 186 | for { 187 | if bsBuff.Len() >= bLen { 188 | break 189 | } 190 | buf := make([]byte, bufLen) 191 | nr, err := conn.Read(buf) 192 | if err != nil { 193 | return nil, err 194 | } 195 | bsBuff.Write(buf[:nr]) 196 | if nr == bLen { 197 | break 198 | } 199 | bufLen = bLen - bsBuff.Len() 200 | } 201 | return bsBuff.Bytes(), nil 202 | } 203 | 204 | // 读数据包 205 | func readPacket(conn net.Conn, fn func(cmd uint16, data []byte) error) error { 206 | if conn == nil { 207 | return errors.New("连接无效。") 208 | } 209 | byteFlag := make([]byte, 1) 210 | _, err := conn.Read(byteFlag) 211 | if err != nil { 212 | return err 213 | } 214 | // 检测包头,必须等于这个才 215 | if byteFlag[0] == PacketHead { 216 | headBuff := make([]byte, PacketHeadLen) 217 | _, err := conn.Read(headBuff) 218 | if err != nil { 219 | return err 220 | } 221 | head := DecodeHead(headBuff) 222 | if head.Version == PacketVersion { 223 | if head.DataLen > 0 || head.DataLen <= 1024*1024*4 { 224 | bodyData, err := rData(conn, int(head.DataLen)) 225 | if err != nil { 226 | return err 227 | } 228 | _, err = conn.Read(byteFlag) 229 | if err != nil { 230 | return err 231 | } 232 | if byteFlag[0] == PacketTail { 233 | // zip解压 234 | if head.IsZip == 1 { 235 | temp, err := ZlibUnCompress(bodyData) 236 | if err != nil { 237 | Log.E(err) 238 | } else { 239 | Log.D("解压缩,原长度:", len(bodyData)) 240 | bodyData = temp 241 | Log.D("解压缩,现长度:", len(bodyData)) 242 | } 243 | } 244 | return fn(head.Cmd, bodyData) 245 | } else { 246 | Log.E("包尾不正确") 247 | } 248 | } else { 249 | Log.E("数据太长,不给处理。") 250 | } 251 | } else { 252 | return errors.New("版本不一致") 253 | } 254 | } 255 | return nil 256 | } 257 | 258 | func keepALive(conn net.Conn) { 259 | if conn.(*net.TCPConn).SetKeepAlive(true) == nil { 260 | conn.(*net.TCPConn).SetKeepAlivePeriod(time.Duration(1 * time.Minute)) 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /librp/net_test.go: -------------------------------------------------------------------------------- 1 | package librp 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestHttp(t *testing.T) { 8 | t.Log("Size:", getPacketHeadSize()) 9 | //GenDefConfig() 10 | } 11 | -------------------------------------------------------------------------------- /librp/server.go: -------------------------------------------------------------------------------- 1 | package librp 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "crypto/tls" 7 | "errors" 8 | "fmt" 9 | "io/ioutil" 10 | "net" 11 | "net/http" 12 | "strings" 13 | "sync" 14 | "time" 15 | ) 16 | 17 | type TRPServer struct { 18 | IRPObject 19 | listener net.Listener 20 | httpSvr *http.Server 21 | conn net.Conn 22 | sync.RWMutex 23 | running bool 24 | } 25 | 26 | func NewRPServer() *TRPServer { 27 | s := new(TRPServer) 28 | return s 29 | } 30 | 31 | func (s *TRPServer) Start() error { 32 | var err error 33 | s.listener, err = net.Listen("tcp", fmt.Sprintf(":%d", conf.TCPPort)) 34 | s.running = true 35 | if err != nil { 36 | return err 37 | } 38 | go s.httpServer() 39 | return s.tcpServer() 40 | } 41 | 42 | func (s *TRPServer) Close() error { 43 | s.running = false 44 | if s.conn != nil { 45 | s.conn.Close() 46 | s.conn = nil 47 | } 48 | if s.httpSvr != nil { 49 | ctx, _ := context.WithTimeout(context.Background(), time.Second*5) 50 | s.httpSvr.Shutdown(ctx) 51 | s.httpSvr.Close() 52 | s.httpSvr = nil 53 | } 54 | if s.listener != nil { 55 | err := s.listener.Close() 56 | s.listener = nil 57 | return err 58 | } 59 | return errors.New("TCP实例未创建!") 60 | } 61 | 62 | func (s *TRPServer) tcpServer() error { 63 | var err error 64 | for s.running { 65 | var conn net.Conn 66 | conn, err = s.listener.Accept() 67 | if err != nil { 68 | if strings.Contains(err.Error(), "use of closed network connection") { 69 | return nil 70 | } 71 | Log.E(err) 72 | continue 73 | } 74 | go s.cliProcess(conn) 75 | } 76 | return err 77 | } 78 | 79 | func badRequest(w http.ResponseWriter) { 80 | w.Header().Set("Content-Type", "text/html; charset=utf-8") 81 | w.Header().Set("X-Content-Type-Options", "nosniff") 82 | w.WriteHeader(http.StatusBadRequest) 83 | w.Write([]byte(errorHTML)) 84 | } 85 | 86 | type THTTPHandler struct { 87 | http.Handler 88 | l sync.RWMutex 89 | read func(w http.ResponseWriter) error 90 | write func(r *http.Request) error 91 | } 92 | 93 | func newHTTPHandler(l sync.RWMutex, read func(w http.ResponseWriter) error, write func(r *http.Request) error) *THTTPHandler { 94 | h := new(THTTPHandler) 95 | h.l = l 96 | h.read = read 97 | h.write = write 98 | return h 99 | } 100 | 101 | func (h *THTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 102 | h.l.Lock() 103 | defer h.l.Unlock() 104 | Log.I(r.Method + " " + r.RequestURI) 105 | err := h.write(r) 106 | if err != nil { 107 | badRequest(w) 108 | Log.E(err) 109 | return 110 | } 111 | err = h.read(w) 112 | if err != nil { 113 | badRequest(w) 114 | Log.E(err) 115 | return 116 | } 117 | } 118 | 119 | func (s *TRPServer) httpServer() { 120 | 121 | s.httpSvr = &http.Server{ 122 | Addr: fmt.Sprintf(":%d", conf.Server.HTTPPort), 123 | Handler: newHTTPHandler(s.RWMutex, s.read, s.write), 124 | TLSConfig: &tls.Config{ 125 | ClientCAs: conf.certPool, 126 | //ClientAuth: tls.RequireAndVerifyClientCert, 127 | }, 128 | } 129 | var err error 130 | if !conf.IsHTTPS { 131 | err = s.httpSvr.ListenAndServe() 132 | } else { 133 | 134 | err = s.httpSvr.ListenAndServeTLS(conf.Server.TLSCertFile, conf.Server.TLSKeyFile) 135 | } 136 | if err != nil && err != http.ErrServerClosed { 137 | Log.EF(err) 138 | } else { 139 | Log.I("HTTP服务已关闭。") 140 | } 141 | } 142 | 143 | func (s *TRPServer) cliProcess(conn net.Conn) error { 144 | // 客户端没有在连接成功后5秒内发送数据则超时 145 | conn.SetReadDeadline(time.Now().Add(5 * time.Second)) 146 | err := readPacket(conn, func(cmd uint16, data []byte) error { 147 | conn.SetReadDeadline(time.Time{}) 148 | if cmd == PacketVerify { 149 | if bytes.Compare(data, conf.verifyVal[:]) != 0 { 150 | return errors.New("首次连接校验证失败。") 151 | } 152 | } else { 153 | return errors.New("首次请求命令不正确。") 154 | } 155 | return nil 156 | }) 157 | if err != nil { 158 | Log.W("当前客户端连接校验错误,关闭此客户端。") 159 | conn.Write(EncodeVerifyFailed()) 160 | conn.Close() 161 | return err 162 | } 163 | // 检测上次已连接的客户端,尝试断开 164 | if s.conn != nil { 165 | Log.W("服务端已有客户端连接!断开之前的:", IPStr(conn)) 166 | s.conn.Close() 167 | s.conn = nil 168 | } 169 | if _, err := conn.Write(EncodeVerifyOK()); err != nil { 170 | return err 171 | } 172 | Log.I("连接新的客户端:", IPStr(conn)) 173 | s.conn = conn 174 | keepALive(s.conn) 175 | return nil 176 | } 177 | 178 | func (s *TRPServer) write(r *http.Request) error { 179 | if s.conn == nil { 180 | return errors.New("客户端未连接。") 181 | } 182 | reqBytes, err := EncodeRequest(r) 183 | if err != nil { 184 | return err 185 | } 186 | return wData(s.conn, reqBytes) 187 | } 188 | 189 | func (s *TRPServer) read(w http.ResponseWriter) error { 190 | return readPacket(s.conn, func(cmd uint16, data []byte) error { 191 | switch cmd { 192 | case PacketCmd1: 193 | resp, err := DecodeResponse(data) 194 | if err != nil { 195 | return err 196 | } 197 | bodyBytes, err := ioutil.ReadAll(resp.Body) 198 | if err != nil { 199 | return err 200 | } 201 | for k, v := range resp.Header { 202 | for _, v2 := range v { 203 | w.Header().Set(k, v2) 204 | } 205 | } 206 | w.WriteHeader(resp.StatusCode) 207 | w.Write(bodyBytes) 208 | 209 | case PackageError: 210 | return errors.New(string(data)) 211 | } 212 | 213 | return nil 214 | }) 215 | } 216 | -------------------------------------------------------------------------------- /lzUI/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | res2go -outmain false -outpath "../" -pause "ew" -outres false 3 | echo // +build gui>> $ 4 | echo.>> $ 5 | type "..\MainForm.go" >> $ 6 | move $ "..\MainForm.go" -------------------------------------------------------------------------------- /lzUI/lzUI.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/lzUI/lzUI.ico -------------------------------------------------------------------------------- /lzUI/lzUI.lpi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | <Scaled Value="True"/> 11 | <ResourceType Value="res"/> 12 | <UseXPManifest Value="True"/> 13 | <XPManifest> 14 | <DpiAware Value="True"/> 15 | </XPManifest> 16 | <Icon Value="0"/> 17 | </General> 18 | <BuildModes Count="1"> 19 | <Item1 Name="Default" Default="True"/> 20 | </BuildModes> 21 | <PublishOptions> 22 | <Version Value="2"/> 23 | </PublishOptions> 24 | <RunParams> 25 | <FormatVersion Value="2"/> 26 | <Modes Count="1"> 27 | <Mode0 Name="default"/> 28 | </Modes> 29 | </RunParams> 30 | <RequiredPackages Count="1"> 31 | <Item1> 32 | <PackageName Value="LCL"/> 33 | </Item1> 34 | </RequiredPackages> 35 | <Units Count="2"> 36 | <Unit0> 37 | <Filename Value="lzUI.lpr"/> 38 | <IsPartOfProject Value="True"/> 39 | </Unit0> 40 | <Unit1> 41 | <Filename Value="umain.pas"/> 42 | <IsPartOfProject Value="True"/> 43 | <ComponentName Value="MainForm"/> 44 | <HasResources Value="True"/> 45 | <ResourceBaseClass Value="Form"/> 46 | <UnitName Value="uMain"/> 47 | </Unit1> 48 | </Units> 49 | </ProjectOptions> 50 | <CompilerOptions> 51 | <Version Value="11"/> 52 | <PathDelim Value="\"/> 53 | <Target> 54 | <Filename Value="lzUI"/> 55 | </Target> 56 | <SearchPaths> 57 | <IncludeFiles Value="$(ProjOutDir)"/> 58 | <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> 59 | </SearchPaths> 60 | <Linking> 61 | <Options> 62 | <Win32> 63 | <GraphicApplication Value="True"/> 64 | </Win32> 65 | </Options> 66 | </Linking> 67 | </CompilerOptions> 68 | <Debugging> 69 | <Exceptions Count="3"> 70 | <Item1> 71 | <Name Value="EAbort"/> 72 | </Item1> 73 | <Item2> 74 | <Name Value="ECodetoolError"/> 75 | </Item2> 76 | <Item3> 77 | <Name Value="EFOpenError"/> 78 | </Item3> 79 | </Exceptions> 80 | </Debugging> 81 | </CONFIG> 82 | -------------------------------------------------------------------------------- /lzUI/lzUI.lpr: -------------------------------------------------------------------------------- 1 | program lzUI; 2 | 3 | {$mode objfpc}{$H+} 4 | 5 | uses 6 | {$IFDEF UNIX}{$IFDEF UseCThreads} 7 | cthreads, 8 | {$ENDIF}{$ENDIF} 9 | Interfaces, // this includes the LCL widgetset 10 | Forms, uMain 11 | { you can add units after this }; 12 | 13 | {$R *.res} 14 | 15 | begin 16 | RequireDerivedFormResource:=True; 17 | Application.Scaled:=True; 18 | Application.Initialize; 19 | Application.CreateForm(TMainForm, MainForm); 20 | Application.Run; 21 | end. 22 | 23 | -------------------------------------------------------------------------------- /lzUI/lzUI.lps: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <CONFIG> 3 | <ProjectSession> 4 | <PathDelim Value="\"/> 5 | <Version Value="11"/> 6 | <BuildModes Active="Default"/> 7 | <Units Count="3"> 8 | <Unit0> 9 | <Filename Value="lzUI.lpr"/> 10 | <IsPartOfProject Value="True"/> 11 | <EditorIndex Value="-1"/> 12 | <WindowIndex Value="-1"/> 13 | <TopLine Value="-1"/> 14 | <CursorPos X="-1" Y="-1"/> 15 | <UsageCount Value="27"/> 16 | </Unit0> 17 | <Unit1> 18 | <Filename Value="umain.pas"/> 19 | <IsPartOfProject Value="True"/> 20 | <ComponentName Value="MainForm"/> 21 | <HasResources Value="True"/> 22 | <ResourceBaseClass Value="Form"/> 23 | <UnitName Value="uMain"/> 24 | <IsVisibleTab Value="True"/> 25 | <TopLine Value="95"/> 26 | <CursorPos X="36" Y="118"/> 27 | <UsageCount Value="27"/> 28 | <Loaded Value="True"/> 29 | <LoadedDesigner Value="True"/> 30 | </Unit1> 31 | <Unit2> 32 | <Filename Value="umain.lfm"/> 33 | <EditorIndex Value="-1"/> 34 | <TopLine Value="199"/> 35 | <CursorPos X="173" Y="89"/> 36 | <UsageCount Value="10"/> 37 | <DefaultSyntaxHighlighter Value="LFM"/> 38 | </Unit2> 39 | </Units> 40 | <JumpHistory Count="30" HistoryIndex="29"> 41 | <Position1> 42 | <Filename Value="umain.pas"/> 43 | <Caret Line="87" Column="3" TopLine="66"/> 44 | </Position1> 45 | <Position2> 46 | <Filename Value="umain.pas"/> 47 | <Caret Line="86" Column="3" TopLine="65"/> 48 | </Position2> 49 | <Position3> 50 | <Filename Value="umain.pas"/> 51 | <Caret Line="85" Column="3" TopLine="64"/> 52 | </Position3> 53 | <Position4> 54 | <Filename Value="umain.pas"/> 55 | <Caret Line="84" Column="3" TopLine="63"/> 56 | </Position4> 57 | <Position5> 58 | <Filename Value="umain.pas"/> 59 | <Caret Line="83" Column="3" TopLine="62"/> 60 | </Position5> 61 | <Position6> 62 | <Filename Value="umain.pas"/> 63 | <Caret Line="82" Column="3" TopLine="61"/> 64 | </Position6> 65 | <Position7> 66 | <Filename Value="umain.pas"/> 67 | <Caret Line="81" Column="3" TopLine="60"/> 68 | </Position7> 69 | <Position8> 70 | <Filename Value="umain.pas"/> 71 | <Caret Line="80" Column="3" TopLine="59"/> 72 | </Position8> 73 | <Position9> 74 | <Filename Value="umain.pas"/> 75 | <Caret Line="79" Column="3" TopLine="58"/> 76 | </Position9> 77 | <Position10> 78 | <Filename Value="umain.pas"/> 79 | <Caret Line="85" Column="3" TopLine="64"/> 80 | </Position10> 81 | <Position11> 82 | <Filename Value="umain.pas"/> 83 | <Caret Line="91" Column="3" TopLine="70"/> 84 | </Position11> 85 | <Position12> 86 | <Filename Value="umain.pas"/> 87 | <Caret Line="90" Column="3" TopLine="69"/> 88 | </Position12> 89 | <Position13> 90 | <Filename Value="umain.pas"/> 91 | <Caret Line="89" Column="3" TopLine="68"/> 92 | </Position13> 93 | <Position14> 94 | <Filename Value="umain.pas"/> 95 | <Caret Line="88" Column="3" TopLine="67"/> 96 | </Position14> 97 | <Position15> 98 | <Filename Value="umain.pas"/> 99 | <Caret Line="87" Column="3" TopLine="66"/> 100 | </Position15> 101 | <Position16> 102 | <Filename Value="umain.pas"/> 103 | <Caret Line="86" Column="3" TopLine="65"/> 104 | </Position16> 105 | <Position17> 106 | <Filename Value="umain.pas"/> 107 | <Caret Line="85" Column="3" TopLine="64"/> 108 | </Position17> 109 | <Position18> 110 | <Filename Value="umain.pas"/> 111 | <Caret Line="91" Column="3" TopLine="70"/> 112 | </Position18> 113 | <Position19> 114 | <Filename Value="umain.pas"/> 115 | <Caret Line="92" Column="3" TopLine="70"/> 116 | </Position19> 117 | <Position20> 118 | <Filename Value="umain.pas"/> 119 | <Caret Line="98" Column="3" TopLine="77"/> 120 | </Position20> 121 | <Position21> 122 | <Filename Value="umain.pas"/> 123 | <Caret Line="104" Column="3" TopLine="83"/> 124 | </Position21> 125 | <Position22> 126 | <Filename Value="umain.pas"/> 127 | <Caret Line="110" Column="3" TopLine="89"/> 128 | </Position22> 129 | <Position23> 130 | <Filename Value="umain.pas"/> 131 | <Caret Line="115" Column="3" TopLine="94"/> 132 | </Position23> 133 | <Position24> 134 | <Filename Value="umain.pas"/> 135 | <Caret Line="116" Column="3" TopLine="95"/> 136 | </Position24> 137 | <Position25> 138 | <Filename Value="umain.pas"/> 139 | <Caret Line="123" Column="3" TopLine="98"/> 140 | </Position25> 141 | <Position26> 142 | <Filename Value="umain.pas"/> 143 | <Caret Line="103" Column="3" TopLine="86"/> 144 | </Position26> 145 | <Position27> 146 | <Filename Value="umain.pas"/> 147 | <Caret Line="127" Column="39" TopLine="103"/> 148 | </Position27> 149 | <Position28> 150 | <Filename Value="umain.pas"/> 151 | <Caret Line="117" Column="36" TopLine="103"/> 152 | </Position28> 153 | <Position29> 154 | <Filename Value="umain.pas"/> 155 | <Caret Line="118" Column="36" TopLine="104"/> 156 | </Position29> 157 | <Position30> 158 | <Filename Value="umain.pas"/> 159 | <Caret Line="117" Column="36" TopLine="103"/> 160 | </Position30> 161 | </JumpHistory> 162 | <RunParams> 163 | <FormatVersion Value="2"/> 164 | <Modes Count="0" ActiveMode="default"/> 165 | </RunParams> 166 | </ProjectSession> 167 | </CONFIG> 168 | -------------------------------------------------------------------------------- /lzUI/lzUI.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ying32/rproxy/6d385c87b5d6799e62c0f07ec08701d6d3aa2cdb/lzUI/lzUI.res -------------------------------------------------------------------------------- /lzUI/umain.lfm: -------------------------------------------------------------------------------- 1 | object MainForm: TMainForm 2 | Left = 905 3 | Height = 582 4 | Top = 288 5 | Width = 498 6 | BorderIcons = [biSystemMenu, biMinimize] 7 | BorderStyle = bsSingle 8 | Caption = 'rproxy' 9 | ClientHeight = 582 10 | ClientWidth = 498 11 | Position = poScreenCenter 12 | LCLVersion = '2.0.6.0' 13 | object StatusBar1: TStatusBar 14 | Left = 0 15 | Height = 22 16 | Top = 560 17 | Width = 498 18 | Panels = <> 19 | ParentFont = False 20 | end 21 | object Panel1: TPanel 22 | Left = 0 23 | Height = 560 24 | Top = 0 25 | Width = 498 26 | Align = alClient 27 | BevelOuter = bvNone 28 | ClientHeight = 560 29 | ClientWidth = 498 30 | ParentFont = False 31 | TabOrder = 1 32 | object Panel2: TPanel 33 | Left = 0 34 | Height = 34 35 | Top = 526 36 | Width = 498 37 | Align = alBottom 38 | ClientHeight = 34 39 | ClientWidth = 498 40 | ParentFont = False 41 | TabOrder = 0 42 | object BtnStart: TButton 43 | Left = 326 44 | Height = 25 45 | Top = 4 46 | Width = 75 47 | Action = ActStart 48 | ParentFont = False 49 | TabOrder = 0 50 | end 51 | object BtnStop: TButton 52 | Left = 410 53 | Height = 25 54 | Top = 4 55 | Width = 75 56 | Action = ActStop 57 | ParentFont = False 58 | TabOrder = 1 59 | end 60 | object Label12: TLabel 61 | Left = 32 62 | Height = 17 63 | Top = 9 64 | Width = 276 65 | Caption = '注:如有修改配置,需要【保存配置】后方能生效。' 66 | Font.Color = clGreen 67 | ParentColor = False 68 | ParentFont = False 69 | end 70 | end 71 | object PageControl1: TPageControl 72 | Left = 0 73 | Height = 526 74 | Top = 0 75 | Width = 498 76 | ActivePage = TabSheet1 77 | Align = alClient 78 | ParentFont = False 79 | TabIndex = 0 80 | TabOrder = 1 81 | OnChange = PageControl1Change 82 | object TabSheet1: TTabSheet 83 | Caption = '服务端/客户端设置' 84 | ClientHeight = 496 85 | ClientWidth = 490 86 | ParentFont = False 87 | object RGMode: TRadioGroup 88 | Left = 0 89 | Height = 58 90 | Top = 0 91 | Width = 490 92 | Align = alTop 93 | AutoFill = True 94 | Caption = '模式选择' 95 | ChildSizing.LeftRightSpacing = 6 96 | ChildSizing.EnlargeHorizontal = crsHomogenousChildResize 97 | ChildSizing.EnlargeVertical = crsHomogenousChildResize 98 | ChildSizing.ShrinkHorizontal = crsScaleChilds 99 | ChildSizing.ShrinkVertical = crsScaleChilds 100 | ChildSizing.Layout = cclLeftToRightThenTopToBottom 101 | ChildSizing.ControlsPerLine = 2 102 | ClientHeight = 36 103 | ClientWidth = 486 104 | Columns = 2 105 | ItemIndex = 0 106 | Items.Strings = ( 107 | '客户端' 108 | '服务端' 109 | ) 110 | ParentFont = False 111 | TabOrder = 0 112 | end 113 | object GBBase: TGroupBox 114 | Left = 0 115 | Height = 221 116 | Top = 109 117 | Width = 490 118 | Align = alClient 119 | Caption = '服务端/客户端设置' 120 | ClientHeight = 199 121 | ClientWidth = 486 122 | ParentFont = False 123 | TabOrder = 1 124 | object Label1: TLabel 125 | Left = 17 126 | Height = 22 127 | Top = 6 128 | Width = 162 129 | AutoSize = False 130 | Caption = '连接或监听的TCP端口:' 131 | Layout = tlCenter 132 | ParentColor = False 133 | ParentFont = False 134 | end 135 | object Label2: TLabel 136 | Left = 17 137 | Height = 22 138 | Top = 70 139 | Width = 162 140 | AutoSize = False 141 | Caption = '客户端转发的HTTP(S)端口:' 142 | Layout = tlCenter 143 | ParentColor = False 144 | ParentFont = False 145 | end 146 | object Label3: TLabel 147 | Left = 19 148 | Height = 22 149 | Top = 135 150 | Width = 70 151 | AutoSize = False 152 | Caption = '验证KEY:' 153 | Layout = tlCenter 154 | ParentColor = False 155 | ParentFont = False 156 | end 157 | object Label7: TLabel 158 | Left = 19 159 | Height = 22 160 | Top = 102 161 | Width = 71 162 | AutoSize = False 163 | Caption = '服务器地址:' 164 | Layout = tlCenter 165 | ParentColor = False 166 | ParentFont = False 167 | end 168 | object SpinTCPPort: TSpinEdit 169 | Left = 206 170 | Height = 22 171 | Hint = '可输入1-65535' 172 | Top = 6 173 | Width = 78 174 | AutoSize = False 175 | MaxValue = 65535 176 | MinValue = 1 177 | ParentFont = False 178 | TabOrder = 0 179 | Value = 8285 180 | end 181 | object SpinCliHTTPPort: TSpinEdit 182 | Left = 206 183 | Height = 22 184 | Hint = '可输入1-65535' 185 | Top = 70 186 | Width = 78 187 | AutoSize = False 188 | MaxValue = 65535 189 | MinValue = 1 190 | ParentFont = False 191 | TabOrder = 1 192 | Value = 8286 193 | end 194 | object ChkIsZip: TCheckBox 195 | Left = 19 196 | Height = 21 197 | Top = 170 198 | Width = 88 199 | Caption = '开启ZIP压缩' 200 | ParentFont = False 201 | TabOrder = 2 202 | end 203 | object EditVerifyKey: TEdit 204 | Left = 92 205 | Height = 22 206 | Top = 135 207 | Width = 149 208 | AutoSize = False 209 | ParentFont = False 210 | TabOrder = 3 211 | end 212 | object BtnRandKey: TButton 213 | Left = 242 214 | Height = 25 215 | Top = 134 216 | Width = 43 217 | Caption = '随机' 218 | ParentFont = False 219 | TabOrder = 4 220 | end 221 | object BtnSaveCfg: TButton 222 | Left = 403 223 | Height = 25 224 | Top = 62 225 | Width = 75 226 | Caption = '保存配置' 227 | OnClick = BtnSaveCfgClick 228 | ParentFont = False 229 | TabOrder = 5 230 | end 231 | object BtnLoadCfg: TButton 232 | Left = 403 233 | Height = 25 234 | Top = 6 235 | Width = 75 236 | Caption = '载入配置' 237 | ParentFont = False 238 | TabOrder = 6 239 | end 240 | object BtnNewCfg: TButton 241 | Left = 403 242 | Height = 25 243 | Top = 34 244 | Width = 75 245 | Caption = '新建配置' 246 | ParentFont = False 247 | TabOrder = 7 248 | end 249 | object EditSvrAddr: TEdit 250 | Left = 92 251 | Height = 22 252 | Top = 102 253 | Width = 193 254 | AutoSize = False 255 | ParentFont = False 256 | TabOrder = 8 257 | end 258 | object ChkIsHttps: TCheckBox 259 | Left = 124 260 | Height = 21 261 | Top = 170 262 | Width = 112 263 | Caption = '监听/转发HTTPS' 264 | ParentFont = False 265 | TabOrder = 9 266 | end 267 | object Label8: TLabel 268 | Left = 17 269 | Height = 22 270 | Top = 38 271 | Width = 162 272 | AutoSize = False 273 | Caption = '服务端监听的HTTP(S)端口:' 274 | Layout = tlCenter 275 | ParentColor = False 276 | ParentFont = False 277 | end 278 | object SpinSvrHTTPPort: TSpinEdit 279 | Left = 206 280 | Height = 22 281 | Hint = '可输入1-65535' 282 | Top = 38 283 | Width = 78 284 | AutoSize = False 285 | MaxValue = 65535 286 | MinValue = 1 287 | ParentFont = False 288 | TabOrder = 10 289 | Value = 8286 290 | end 291 | end 292 | object GBTLS: TGroupBox 293 | Left = 0 294 | Height = 166 295 | Top = 330 296 | Width = 490 297 | Align = alBottom 298 | Caption = 'TLS证书设置' 299 | ClientHeight = 144 300 | ClientWidth = 486 301 | ParentFont = False 302 | TabOrder = 2 303 | object Panel3: TPanel 304 | Left = 0 305 | Height = 32 306 | Top = 0 307 | Width = 486 308 | Align = alTop 309 | BevelOuter = bvNone 310 | ClientHeight = 32 311 | ClientWidth = 486 312 | ParentFont = False 313 | TabOrder = 0 314 | object Label4: TLabel 315 | Left = 17 316 | Height = 22 317 | Top = 7 318 | Width = 86 319 | AutoSize = False 320 | Caption = 'TLS CA根证书:' 321 | Layout = tlCenter 322 | ParentColor = False 323 | ParentFont = False 324 | end 325 | object EditTLSCAFile: TEdit 326 | Left = 112 327 | Height = 25 328 | Top = 3 329 | Width = 330 330 | AutoSize = False 331 | ParentFont = False 332 | TabOrder = 0 333 | end 334 | object BtnCAOpen: TButton 335 | Left = 444 336 | Height = 25 337 | Top = 3 338 | Width = 27 339 | BidiMode = bdRightToLeft 340 | Caption = '...' 341 | ParentBidiMode = False 342 | ParentFont = False 343 | TabOrder = 1 344 | end 345 | end 346 | object PageControl2: TPageControl 347 | Left = 0 348 | Height = 112 349 | Top = 32 350 | Width = 486 351 | ActivePage = TabSheet3 352 | Align = alClient 353 | ParentFont = False 354 | TabIndex = 0 355 | TabOrder = 1 356 | TabPosition = tpBottom 357 | object TabSheet3: TTabSheet 358 | Caption = '客户端TLS' 359 | ClientHeight = 82 360 | ClientWidth = 478 361 | ParentFont = False 362 | object Panel4: TPanel 363 | Left = 0 364 | Height = 82 365 | Top = 0 366 | Width = 478 367 | Align = alClient 368 | BevelOuter = bvNone 369 | ClientHeight = 82 370 | ClientWidth = 478 371 | ParentFont = False 372 | TabOrder = 0 373 | object Label6: TLabel 374 | Left = 13 375 | Height = 22 376 | Top = 51 377 | Width = 86 378 | AutoSize = False 379 | Caption = 'TLS Key文件:' 380 | Layout = tlCenter 381 | ParentColor = False 382 | ParentFont = False 383 | end 384 | object EditTLSCliKeyFile: TEdit 385 | Left = 108 386 | Height = 25 387 | Top = 49 388 | Width = 330 389 | AutoSize = False 390 | ParentFont = False 391 | TabOrder = 0 392 | end 393 | object Label5: TLabel 394 | Left = 13 395 | Height = 22 396 | Top = 15 397 | Width = 81 398 | AutoSize = False 399 | Caption = 'TLS Cert文件:' 400 | Layout = tlCenter 401 | ParentColor = False 402 | ParentFont = False 403 | end 404 | object EditTLSCliCertFile: TEdit 405 | Left = 108 406 | Height = 25 407 | Top = 13 408 | Width = 330 409 | AutoSize = False 410 | ParentFont = False 411 | TabOrder = 1 412 | end 413 | object BtnCliCertOpen: TButton 414 | Left = 440 415 | Height = 25 416 | Top = 13 417 | Width = 27 418 | BidiMode = bdRightToLeft 419 | Caption = '...' 420 | ParentBidiMode = False 421 | OnClick = BtnCliCertOpenClick 422 | ParentFont = False 423 | TabOrder = 2 424 | end 425 | object BtnCliKeyOpen: TButton 426 | Left = 440 427 | Height = 25 428 | Top = 49 429 | Width = 27 430 | BidiMode = bdRightToLeft 431 | Caption = '...' 432 | ParentBidiMode = False 433 | OnClick = BtnCliKeyOpenClick 434 | ParentFont = False 435 | TabOrder = 3 436 | end 437 | end 438 | end 439 | object TabSheet4: TTabSheet 440 | Caption = '服务端TLS' 441 | ClientHeight = 82 442 | ClientWidth = 478 443 | ParentFont = False 444 | object Panel5: TPanel 445 | Left = 0 446 | Height = 82 447 | Top = 0 448 | Width = 478 449 | Align = alClient 450 | BevelOuter = bvNone 451 | ClientHeight = 82 452 | ClientWidth = 478 453 | ParentFont = False 454 | TabOrder = 0 455 | object Label10: TLabel 456 | Left = 13 457 | Height = 22 458 | Top = 15 459 | Width = 81 460 | AutoSize = False 461 | Caption = 'TLS Cert文件:' 462 | Layout = tlCenter 463 | ParentColor = False 464 | ParentFont = False 465 | end 466 | object EditTLSSvrCertFile: TEdit 467 | Left = 108 468 | Height = 25 469 | Top = 13 470 | Width = 330 471 | AutoSize = False 472 | ParentFont = False 473 | TabOrder = 0 474 | end 475 | object BtnSvrCertOpen: TButton 476 | Left = 440 477 | Height = 25 478 | Top = 13 479 | Width = 27 480 | BidiMode = bdRightToLeft 481 | Caption = '...' 482 | ParentBidiMode = False 483 | OnClick = BtnSvrCertOpenClick 484 | ParentFont = False 485 | TabOrder = 1 486 | end 487 | object BtnSvrKeyOpen: TButton 488 | Left = 440 489 | Height = 25 490 | Top = 49 491 | Width = 27 492 | BidiMode = bdRightToLeft 493 | Caption = '...' 494 | ParentBidiMode = False 495 | OnClick = BtnSvrKeyOpenClick 496 | ParentFont = False 497 | TabOrder = 2 498 | end 499 | object EditTLSSvrKeyFile: TEdit 500 | Left = 108 501 | Height = 25 502 | Top = 49 503 | Width = 330 504 | AutoSize = False 505 | ParentFont = False 506 | TabOrder = 3 507 | end 508 | object Label11: TLabel 509 | Left = 13 510 | Height = 22 511 | Top = 51 512 | Width = 86 513 | AutoSize = False 514 | Caption = 'TLS Key文件:' 515 | Layout = tlCenter 516 | ParentColor = False 517 | ParentFont = False 518 | end 519 | end 520 | end 521 | end 522 | end 523 | object GBAppSettings: TGroupBox 524 | Left = 0 525 | Height = 51 526 | Top = 58 527 | Width = 490 528 | Align = alTop 529 | Caption = 'APP设置' 530 | ClientHeight = 29 531 | ClientWidth = 486 532 | ParentFont = False 533 | TabOrder = 3 534 | object ChkAutoReconnect: TCheckBox 535 | Left = 19 536 | Height = 21 537 | Top = 3 538 | Width = 178 539 | Caption = '与服务器连接断开后自动重连' 540 | ParentFont = False 541 | TabOrder = 0 542 | end 543 | object Label9: TLabel 544 | Left = 243 545 | Height = 22 546 | Top = 0 547 | Width = 90 548 | AutoSize = False 549 | Caption = '最大日志行数:' 550 | Layout = tlCenter 551 | ParentColor = False 552 | ParentFont = False 553 | end 554 | object SpinMaxLogLine: TSpinEdit 555 | Left = 326 556 | Height = 22 557 | Top = 0 558 | Width = 134 559 | AutoSize = False 560 | MaxValue = 200000 561 | MinValue = 1 562 | OnChange = SpinMaxLogLineChange 563 | ParentFont = False 564 | TabOrder = 1 565 | Value = 5000 566 | end 567 | end 568 | end 569 | object TabSheet2: TTabSheet 570 | Caption = '日志' 571 | ClientHeight = 623 572 | ClientWidth = 614 573 | ParentFont = False 574 | object LstLogs: TListBox 575 | Left = 0 576 | Height = 618 577 | Top = 0 578 | Width = 614 579 | Align = alClient 580 | BorderSpacing.Bottom = 4 581 | Font.Height = -12 582 | ItemHeight = 0 583 | ParentFont = False 584 | Style = lbOwnerDrawFixed 585 | TabOrder = 0 586 | end 587 | end 588 | end 589 | end 590 | object DlgSaveCfg: TSaveDialog 591 | DefaultExt = '.cfg' 592 | Filter = '配置文件|*.cfg' 593 | left = 397 594 | top = 275 595 | end 596 | object DlgOpen: TOpenDialog 597 | left = 435 598 | top = 275 599 | end 600 | object ActionList1: TActionList 601 | left = 358 602 | top = 275 603 | object ActStart: TAction 604 | Caption = '启动' 605 | end 606 | object ActStop: TAction 607 | Caption = '停止' 608 | end 609 | end 610 | object TrayIcon1: TTrayIcon 611 | Visible = True 612 | left = 358 613 | top = 230 614 | end 615 | end 616 | -------------------------------------------------------------------------------- /lzUI/umain.pas: -------------------------------------------------------------------------------- 1 | unit uMain; 2 | 3 | {$mode objfpc}{$H+} 4 | 5 | interface 6 | 7 | uses 8 | Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ActnList, ComCtrls, 9 | ExtCtrls, StdCtrls, Spin, Buttons, Types; 10 | 11 | type 12 | 13 | { TMainForm } 14 | 15 | TMainForm = class(TForm) 16 | ActionList1: TActionList; 17 | ActStart: TAction; 18 | ActStop: TAction; 19 | BtnCAOpen: TButton; 20 | BtnCliCertOpen: TButton; 21 | BtnSvrCertOpen: TButton; 22 | BtnCliKeyOpen: TButton; 23 | BtnSvrKeyOpen: TButton; 24 | BtnLoadCfg: TButton; 25 | BtnNewCfg: TButton; 26 | BtnRandKey: TButton; 27 | BtnSaveCfg: TButton; 28 | BtnStart: TButton; 29 | BtnStop: TButton; 30 | ChkAutoReconnect: TCheckBox; 31 | ChkIsHttps: TCheckBox; 32 | ChkIsZip: TCheckBox; 33 | DlgOpen: TOpenDialog; 34 | DlgSaveCfg: TSaveDialog; 35 | EditSvrAddr: TEdit; 36 | EditTLSCAFile: TEdit; 37 | EditTLSCliCertFile: TEdit; 38 | EditTLSSvrCertFile: TEdit; 39 | EditTLSCliKeyFile: TEdit; 40 | EditTLSSvrKeyFile: TEdit; 41 | EditVerifyKey: TEdit; 42 | GBBase: TGroupBox; 43 | GBTLS: TGroupBox; 44 | GBAppSettings: TGroupBox; 45 | Label1: TLabel; 46 | Label10: TLabel; 47 | Label11: TLabel; 48 | Label12: TLabel; 49 | Label2: TLabel; 50 | Label3: TLabel; 51 | Label4: TLabel; 52 | Label5: TLabel; 53 | Label6: TLabel; 54 | Label7: TLabel; 55 | Label8: TLabel; 56 | Label9: TLabel; 57 | LstLogs: TListBox; 58 | PageControl1: TPageControl; 59 | PageControl2: TPageControl; 60 | Panel1: TPanel; 61 | Panel2: TPanel; 62 | Panel3: TPanel; 63 | Panel4: TPanel; 64 | Panel5: TPanel; 65 | RGMode: TRadioGroup; 66 | SpinCliHTTPPort: TSpinEdit; 67 | SpinMaxLogLine: TSpinEdit; 68 | SpinSvrHTTPPort: TSpinEdit; 69 | SpinTCPPort: TSpinEdit; 70 | StatusBar1: TStatusBar; 71 | TabSheet1: TTabSheet; 72 | TabSheet2: TTabSheet; 73 | TabSheet3: TTabSheet; 74 | TabSheet4: TTabSheet; 75 | TrayIcon1: TTrayIcon; 76 | procedure BtnCliCertOpenClick(Sender: TObject); 77 | procedure BtnCliKeyOpenClick(Sender: TObject); 78 | procedure BtnSaveCfgClick(Sender: TObject); 79 | procedure BtnSvrCertOpenClick(Sender: TObject); 80 | procedure BtnSvrKeyOpenClick(Sender: TObject); 81 | procedure PageControl1Change(Sender: TObject); 82 | procedure SpinMaxLogLineChange(Sender: TObject); 83 | private 84 | 85 | public 86 | 87 | end; 88 | 89 | var 90 | MainForm: TMainForm; 91 | 92 | implementation 93 | 94 | {$R *.lfm} 95 | 96 | { TMainForm } 97 | 98 | procedure TMainForm.PageControl1Change(Sender: TObject); 99 | begin 100 | 101 | end; 102 | 103 | procedure TMainForm.SpinMaxLogLineChange(Sender: TObject); 104 | begin 105 | 106 | end; 107 | 108 | procedure TMainForm.BtnCliCertOpenClick(Sender: TObject); 109 | begin 110 | 111 | end; 112 | 113 | procedure TMainForm.BtnCliKeyOpenClick(Sender: TObject); 114 | begin 115 | 116 | end; 117 | 118 | procedure TMainForm.BtnSaveCfgClick(Sender: TObject); 119 | begin 120 | 121 | end; 122 | 123 | procedure TMainForm.BtnSvrCertOpenClick(Sender: TObject); 124 | begin 125 | 126 | end; 127 | 128 | procedure TMainForm.BtnSvrKeyOpenClick(Sender: TObject); 129 | begin 130 | 131 | end; 132 | 133 | end. 134 | 135 | -------------------------------------------------------------------------------- /main_gui.go: -------------------------------------------------------------------------------- 1 | // +build gui 2 | 3 | package main 4 | 5 | import ( 6 | "github.com/ying32/govcl/vcl" 7 | ) 8 | 9 | // GUI模式下暂时只能是客户端,服务端依然使用命令行。 10 | // 另外如果更新了MainForm.go或者MainFormImpl.go需要在前面补充自定义标题 // +build gui 11 | func main() { 12 | 13 | vcl.Application.Initialize() 14 | vcl.Application.SetMainFormOnTaskBar(true) 15 | vcl.Application.CreateForm(&MainForm) 16 | vcl.Application.Run() 17 | 18 | } 19 | -------------------------------------------------------------------------------- /main_nogui.go: -------------------------------------------------------------------------------- 1 | // +build !gui 2 | 3 | package main 4 | 5 | import ( 6 | "flag" 7 | "time" 8 | 9 | rp "github.com/ying32/rproxy/librp" 10 | ) 11 | 12 | var ( 13 | tcpPort = flag.Int("tcpport", 0, "Socket连接或者监听的端口") 14 | httpPort = flag.Int("httpport", 0, "当mode为server时为服务端监听端口,当为mode为client时为转发至本地客户端的端口") 15 | rpMode = flag.String("mode", "client", "启动模式,可选为client、server") 16 | svrAddr = flag.String("svraddr", "127.0.0.1", "当mode为client时有效,为连接服务器的地址") 17 | verifyKey = flag.String("vkey", "", "用作客户端与服务端连接时的校验") 18 | isHTTPS = flag.Bool("ishttps", false, "httpPort端口是否只用作HTTPS监听") 19 | tlsCAFile = flag.String("tlscafile", "", "当ishttps为true时,所需的CA根证书文件。可为空,根据实际情况确定") 20 | tlsCertFile = flag.String("tlscertfile", "", "当ishttps为true时,所需求的TLS证书文件") 21 | tlsKeyFile = flag.String("tlskeyfile", "", "当ishttps为true时,所需求的TLS密匙文件") 22 | isZip = flag.Bool("iszip", false, "是否开启zip压缩") 23 | configFile = flag.String("cfgfile", "", "使用指定的配置文件中的参数,此时只有mode参数有效") 24 | localAddr = flag.String("localaddr", "127.0.0.1", "转发至本地的地址,只有mode参数为client时有效") 25 | ) 26 | 27 | func main() { 28 | flag.Parse() 29 | 30 | mode := *rpMode 31 | 32 | rpConfig := new(rp.TRProxyConfig) 33 | 34 | if *configFile != "" { 35 | err := rp.LoadConfig(*configFile, rpConfig) 36 | if err != nil { 37 | rp.Log.EF("加载配置失败:", err) 38 | } 39 | } else { 40 | // 初始填充配置 41 | rpConfig.TCPPort = *tcpPort 42 | switch mode { 43 | case rp.SERVER: 44 | rpConfig.Server.HTTPPort = *httpPort 45 | rpConfig.Server.TLSCertFile = *tlsCertFile 46 | rpConfig.Server.TLSKeyFile = *tlsKeyFile 47 | case rp.CLIENT: 48 | rpConfig.Client.HTTPPort = *httpPort 49 | rpConfig.Client.SvrAddr = *svrAddr 50 | rpConfig.Client.TLSCertFile = *tlsCertFile 51 | rpConfig.Client.TLSKeyFile = *tlsKeyFile 52 | rpConfig.Client.LocalAddr = *localAddr 53 | } 54 | rpConfig.VerifyKey = *verifyKey 55 | rpConfig.IsHTTPS = *isHTTPS 56 | rpConfig.TLSCAFile = *tlsCAFile 57 | rpConfig.IsZIP = *isZip 58 | } 59 | 60 | if rpConfig.VerifyKey == "" { 61 | rp.Log.EF("必须输入一个验证的key") 62 | } 63 | if rpConfig.TCPPort <= 0 || rpConfig.TCPPort >= 65536 { 64 | rp.Log.EF("请输入正确的tcp端口。") 65 | } 66 | rPort := rpConfig.Client.HTTPPort 67 | if mode == rp.SERVER { 68 | rPort = rpConfig.Server.HTTPPort 69 | } 70 | if rPort <= 0 || rPort >= 65536 { 71 | rp.Log.EF("请输入正确的http端口。") 72 | } 73 | if mode != rp.CLIENT && mode != rp.SERVER { 74 | rp.Log.EF("请输入正确的服务启动模式") 75 | } 76 | if mode == rp.SERVER && rpConfig.TCPPort == rpConfig.Server.HTTPPort { 77 | rp.Log.EF("tcp端口与http端口不能为同一个。") 78 | } 79 | if rpConfig.IsHTTPS { 80 | if mode == rp.SERVER && (rpConfig.Server.TLSCertFile == "" || rpConfig.Server.TLSKeyFile == "") { 81 | rp.Log.EF("当为HTTPS时,服务端TLS证书不能为空。") 82 | } else if mode == rp.CLIENT && (rpConfig.Client.TLSCertFile == "" || rpConfig.Client.TLSKeyFile == "") { 83 | rp.Log.EF("当为HTTPS时,客户端TLS证书不能为空。") 84 | } 85 | } 86 | 87 | // 初始配置文件 88 | rp.SetConfig(rpConfig) 89 | 90 | switch mode { 91 | 92 | case rp.SERVER: 93 | rp.Log.I("TCP服务端已启动,端口:", rpConfig.TCPPort) 94 | if rpConfig.IsHTTPS { 95 | rp.Log.I("当前HTTP服务为HTTPS") 96 | } 97 | rp.Log.I("HTTP(S)服务端已开启,端口:", rpConfig.Server.HTTPPort) 98 | svr := rp.NewRPServer() 99 | if err := svr.Start(); err != nil { 100 | rp.Log.EF(err) 101 | } 102 | defer svr.Close() 103 | 104 | case rp.CLIENT: 105 | retry: 106 | rp.Log.I("客户端启动,连接服务器:", rpConfig.Client.SvrAddr, ", 端口:", rpConfig.TCPPort) 107 | if rpConfig.IsHTTPS { 108 | rp.Log.I("转发至HTTP服务为HTTPS") 109 | } 110 | rp.Log.I("转发至本地HTTP(S)端口:", rpConfig.Client.HTTPPort) 111 | cli := rp.NewRPClient() 112 | if err := cli.Start(); err != nil { 113 | cli.Close() 114 | rp.Log.E(err) 115 | // 重连 116 | rp.Log.I("5秒后重新连接...") 117 | time.Sleep(time.Second * 5) 118 | goto retry 119 | } 120 | defer cli.Close() 121 | 122 | } 123 | } 124 | --------------------------------------------------------------------------------