diff --git a/README-ZH.md b/README-ZH.md index d3e29f0..eed3c04 100644 --- a/README-ZH.md +++ b/README-ZH.md @@ -28,38 +28,43 @@ P2P直连可以让你的设备跑满带宽。不论你的设备在任何网络 基于OpenP2P只需数行代码,就能让原来只能局域网通信的程序,变成任何内网都能通信 ## 快速入门 +仅需简单4步就能用起来。 +下面是一个远程办公例子:在家里连入办公室Windows电脑。 +### 1.注册 +前往 注册新用户,暂无需任何认证 -> :warning: 本文所有命令, Windows环境使用"openp2p.exe", Linux环境使用"./openp2p" + ![image](/doc/images/register.png) +### 2.安装 +分别在本地和远程电脑下载后双击运行,一键安装 + ![image](/doc/images/install.png) -以一个最常见的例子说明OpenP2P如何使用:远程办公,在家里连入办公室Windows电脑。 -相信很多人在疫情下远程办公是刚需。 -1. 先确认办公室电脑已开启远程桌面功能(如何开启参考官方说明https://docs.microsoft.com/zh-cn/windows-server/remote/remote-desktop-services/clients/remote-desktop-allow-access) -2. 在办公室下载最新的`OpenP2P`[下载页](https://openp2p.cn/),解压出来,在命令行执行 - ``` - openp2p.exe install -node OFFICEPC1 -user USERNAME1 -password PASSWORD1 - ``` - - > :warning: **切记将标记大写的参数改成自己的,3个参数的长度必须>=8个字符** + Windows默认会阻止没有花钱买它家证书签名过的程序,选择“仍要运行”即可。 - ![image](/doc/images/officelisten.png) -3. 在家里下载最新的OpenP2P,解压出来,在命令行执行 - ``` - openp2p.exe -d -node HOMEPC123 -user USERNAME1 -password PASSWORD1 -appname WindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389 -protocol tcp - ``` - > :warning: **切记将标记大写的参数改成自己的** + ![image](/doc/images/win10warn.png) + + ![image](/doc/images/stillrun.png) +### 3.新建P2P应用 + +![image](/doc/images/devices.png) + +![image](/doc/images/newapp.png) + +![image](/doc/images/newappedit.png) + +### 4.使用P2P应用 +在“MyHomePC”设备上能看到刚才创建的P2P应用,连接下图显示的“本地监听端口”即可。 + +![image](/doc/images/p2pappok.png) + +在家里Windows电脑,按Win+R输入mstsc打开远程桌面,输入127.0.0.1:23389 /admin - ![image](/doc/images/homeconnect.png) - ![image](/doc/images/mem.png) - `LISTEN ON PORT 23389 START` 看到这行日志表示P2PApp建立成功,监听23389端口。只需连接本机的127.0.0.1:23389就相当于连接公司Windows电脑的3389端口。 - -4. 在家里Windows电脑,按Win+R输入mstsc打开远程桌面,输入127.0.0.1:23389 /admin ![image](/doc/images/mstscconnect.png) ![image](/doc/images/afterconnect.png) ## 详细使用说明 -[这里](/USAGE-ZH.md)详细介绍如何使用和运行参数 +[这里](/USAGE-ZH.md)介绍如何手动运行 ## 典型应用场景 特别适合大流量的内网访问 diff --git a/README.md b/README.md index a42fb56..199d72c 100644 --- a/README.md +++ b/README.md @@ -30,52 +30,45 @@ P2P direct connection lets your devices make good use of bandwidth. Your device Your applicaiton can call OpenP2P with a few code to make any internal networks communicate with each other. ## Get Started -A common scenario to introduce OpenP2P: remote work. At home connects to office's Linux PC . -Under the outbreak of covid-19 pandemic, surely remote work becomes a fundamental demand. +Just 4 simple steps to use. +Here's an example of remote work: connecting to an office Windows computer at home. + +### 1.Register +Go to register a new user -> :warning: all commands in this doc, Windows env uses "openp2p.exe", Linux env uses "./openp2p" - + ![image](/doc/images/register.png) +### 2.Install +Download on local and remote computers and double-click to run, one-click installation -1. Make sure your office device(Linux) has opened the access of ssh. - ``` - netstat -nl | grep 22 - ``` - Output sample - ![image](/doc/images/officelisten_linux.png) + ![image](/doc/images/install.png) -2. Download the latest version of `OpenP2P` [Download Page](https://openp2p.cn/),unzip the downloaded package, and execute below command line. - ``` - tar xzvf ${PackageName} - ./openp2p install -node OFFICEPC1 -user USERNAME1 -password PASSWORD1 - ``` + By default, Windows will block programs that have not been signed by the Microsoft's certificate, and you can select "Run anyway". - > :warning: **Must change the parameters marked in UPPERCASE to your own. These 3 parameters must >= 8 charaters** + ![image](/doc/images/win10warn.png) - Output sample - ![image](/doc/images/officeexecute_linux.png) + ![image](/doc/images/stillrun.png) +### 3.New P2PApp -3. Download OpenP2P on your home device,unzip and execute below command line. - ``` - openp2p.exe -d -node HOMEPC123 -user USERNAME1 -password PASSWORD1 -appname OfficeSSH -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 22 -srcport 22022 -protocol tcp - ``` - - > :warning: **Must change the parameters marked in UPPERCASE to your own** +![image](/doc/images/devices.png) - Output sample - ![image](/doc/images/homeconnect_windows.png) - The log of `LISTEN ON PORT 22022 START` indicates P2PApp runs successfully on your home device, listing port is 22022. Once connects to local ip:port,127.0.0.1:22022, it means the home device has conneccted to the office device's port, 22. - ![image](/doc/images/officelisten_2_linux.png) +![image](/doc/images/newapp.png) +![image](/doc/images/newappedit.png) -4. Test the connection between office device and home device.In your home deivce, run SSH to login the office device. - ``` - ssh -p22022 root@127.0.0.1:22022 - ``` - ![image](/doc/images/sshconnect.png) +### 4.Use P2PApp +You can see the P2P application you just created on the "MyHomePC" device, just connect to the "local listening port" shown in the figure below. + +![image](/doc/images/p2pappok.png) + +On MyHomePC, press Win+R and enter MSTSC to open the remote desktop, input `127.0.0.1:23389 /admin` + + ![image](/doc/images/mstscconnect.png) + + ![image](/doc/images/afterconnect.png) ## Usage -[Here](/USAGE.md) is a detailed description of how to use and running parameters +[Here](/USAGE.md) describes how to run manually ## Scenarios Especially suitable for large traffic intranet access. diff --git a/USAGE-ZH.md b/USAGE-ZH.md index b157680..bac6a7a 100644 --- a/USAGE-ZH.md +++ b/USAGE-ZH.md @@ -1,36 +1,33 @@ -# 详细运行参数说明 +# 手动运行说明 +大部分情况通过 操作即可。有些情况需要手动运行 > :warning: 本文所有命令, Windows环境使用"openp2p.exe", Linux环境使用"./openp2p" ## 安装和监听 ``` -./openp2p install -node OFFICEPC1 -user USERNAME1 -password PASSWORD1 +./openp2p install -node OFFICEPC1 -token TOKEN 或 -./openp2p -d -node OFFICEPC1 -user USERNAME1 -password PASSWORD1 +./openp2p -d -node OFFICEPC1 -token TOKEN # 注意Windows系统把“./openp2p” 换成“openp2p.exe” ``` >* install: 安装模式【推荐】,会安装成系统服务,这样它就能随系统自动启动 >* -d: daemon模式。发现worker进程意外退出就会自动启动新的worker进程 >* -node: 独一无二的节点名字,唯一标识 ->* -user: 独一无二的用户名字,该节点属于这个user ->* -password: 密码 +>* -token: 在“我的”里面找到 >* -sharebandwidth: 作为共享节点时提供带宽,默认10mbps. 如果是光纤大带宽,设置越大效果越好. -1表示不共享,该节点只在私有的P2P网络使用。不加入共享的P2P网络,这样也意味着无法使用别人的共享节点 >* -loglevel: 需要查看更多调试日志,设置0;默认是1 ## 连接 ``` -./openp2p -d -node HOMEPC123 -user USERNAME1 -password PASSWORD1 -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389 -protocol tcp +./openp2p -d -node HOMEPC123 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389 使用配置文件,建立多个P2PApp -./openp2p -d -f -./openp2p -f +./openp2p -d ``` >* -appname: 这个P2P应用名字 >* -peernode: 目标节点名字 >* -dstip: 目标服务地址,默认本机127.0.0.1 >* -dstport: 目标服务端口,常见的如windows远程桌面3389,Linux ssh 22 >* -protocol: 目标服务协议 tcp、udp ->* -peeruser: 目标用户,如果是同一个用户下的节点,则无需设置 ->* -peerpassword: 目标密码,如果是同一个用户下的节点,则无需设置 ## 配置文件 一般保存在当前目录,安装模式下会保存到 `C:\Program Files\OpenP2P\config.json` 或 `/usr/local/openp2p/config.json` @@ -41,11 +38,10 @@ { "network": { "Node": "hhd1207-222", - "User": "USERNAME1", - "Password": "PASSWORD1", + "Token": "TOKEN", "ShareBandwidth": -1, "ServerHost": "api.openp2p.cn", - "ServerPort": 27182, + "ServerPort": 27183, "UDPPort1": 27182, "UDPPort2": 27183 }, @@ -57,8 +53,6 @@ "PeerNode": "OFFICEPC1", "DstPort": 3389, "DstHost": "localhost", - "PeerUser": "", - "PeerPassword": "" }, { "AppName": "OfficeServerSSH", @@ -67,8 +61,6 @@ "PeerNode": "OFFICEPC1", "DstPort": 22, "DstHost": "192.168.1.5", - "PeerUser": "", - "PeerPassword": "" } ] } diff --git a/USAGE.md b/USAGE.md index 8567a22..b54f6bb 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1,37 +1,35 @@ -# Parameters details + +# Parameters details +In most cases, you can operate it through . In some cases it is necessary to run manually > :warning: all commands in this doc, Windows env uses "openp2p.exe", Linux env uses "./openp2p" ## Install and Listen ``` -./openp2p install -node OFFICEPC1 -user USERNAME1 -password PASSWORD1 +./openp2p install -node OFFICEPC1 -token TOKEN Or -./openp2p -d -node OFFICEPC1 -user USERNAME1 -password PASSWORD1 +./openp2p -d -node OFFICEPC1 -token TOKEN ``` >* install: [recommand] will install as system service. So it will autorun when system booting. >* -d: daemon mode run once. When the worker process is found to exit unexpectedly, a new worker process will be automatically started >* -node: Unique node name, unique identification ->* -user: Unique user name, the node belongs to this user ->* -password: Password +>* -token: See "Profile" >* -sharebandwidth: Provides bandwidth when used as a shared node, the default is 10mbps. If it is a large bandwidth of optical fiber, the larger the setting, the better the effect. -1 means not shared, the node is only used in a private P2P network. Do not join the shared P2P network, which also means that you CAN NOT use other people’s shared nodes >* -loglevel: Need to view more debug logs, set 0; the default is 1 ## Connect ``` -./openp2p -d -node HOMEPC123 -user USERNAME1 -password PASSWORD1 -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389 -protocol tcp +./openp2p -d -node HOMEPC123 -token TOKEN -appname OfficeWindowsRemote -peernode OFFICEPC1 -dstip 127.0.0.1 -dstport 3389 -srcport 23389 Create multiple P2PApp by config file -./openp2p -d -f -./openp2p -f +./openp2p -d ``` >* -appname: This P2PApp name >* -peernode: Target node name >* -dstip: Target service address, default local 127.0.0.1 >* -dstport: Target service port, such as windows remote desktop 3389, Linux ssh 22 >* -protocol: Target service protocol tcp, udp ->* -peeruser: The target user, if it is a node under the same user, no need to set ->* -peerpassword: The target password, if it is a node under the same user, no need to set ## Config file Generally saved in the current directory, in installation mode it will be saved to `C:\Program Files\OpenP2P\config.json` or `/usr/local/openp2p/config.json` @@ -42,11 +40,10 @@ Configuration example { "network": { "Node": "hhd1207-222", - "User": "USERNAME1", - "Password": "PASSWORD1", + "Token": "TOKEN", "ShareBandwidth": -1, "ServerHost": "api.openp2p.cn", - "ServerPort": 27182, + "ServerPort": 27183, "UDPPort1": 27182, "UDPPort2": 27183 }, @@ -58,8 +55,6 @@ Configuration example "PeerNode": "OFFICEPC1", "DstPort": 3389, "DstHost": "localhost", - "PeerUser": "", - "PeerPassword": "" }, { "AppName": "OfficeServerSSH", @@ -68,8 +63,6 @@ Configuration example "PeerNode": "OFFICEPC1", "DstPort": 22, "DstHost": "192.168.1.5", - "PeerUser": "", - "PeerPassword": "" } ] } diff --git a/bandwidthLimit.go b/bandwidthLimit.go index a6c800c..149f92d 100644 --- a/bandwidthLimit.go +++ b/bandwidthLimit.go @@ -7,39 +7,39 @@ import ( // BandwidthLimiter ... type BandwidthLimiter struct { - freeFlowTime time.Time - bandwidth int // mbps - freeFlow int // bytes - maxFreeFlow int // bytes - freeFlowMtx sync.Mutex + ts time.Time + bw int // mbps + freeBytes int // bytes + maxFreeBytes int // bytes + mtx sync.Mutex } // mbps func newBandwidthLimiter(bw int) *BandwidthLimiter { return &BandwidthLimiter{ - bandwidth: bw, - freeFlowTime: time.Now(), - maxFreeFlow: bw * 1024 * 1024 / 8, - freeFlow: bw * 1024 * 1024 / 8, + bw: bw, + ts: time.Now(), + maxFreeBytes: bw * 1024 * 1024 / 8, + freeBytes: bw * 1024 * 1024 / 8, } } // Add ... func (bl *BandwidthLimiter) Add(bytes int) { - if bl.bandwidth <= 0 { + if bl.bw <= 0 { return } - bl.freeFlowMtx.Lock() - defer bl.freeFlowMtx.Unlock() + bl.mtx.Lock() + defer bl.mtx.Unlock() // calc free flow 1000*1000/1024/1024=0.954; 1024*1024/1000/1000=1.048 - bl.freeFlow += int(time.Now().Sub(bl.freeFlowTime) * time.Duration(bl.bandwidth) / 8 / 954) - if bl.freeFlow > bl.maxFreeFlow { - bl.freeFlow = bl.maxFreeFlow + bl.freeBytes += int(time.Since(bl.ts) * time.Duration(bl.bw) / 8 / 954) + if bl.freeBytes > bl.maxFreeBytes { + bl.freeBytes = bl.maxFreeBytes } - bl.freeFlow -= bytes - bl.freeFlowTime = time.Now() - if bl.freeFlow < 0 { + bl.freeBytes -= bytes + bl.ts = time.Now() + if bl.freeBytes < 0 { // sleep for the overflow - time.Sleep(time.Millisecond * time.Duration(-bl.freeFlow/(bl.bandwidth*1048/8))) + time.Sleep(time.Millisecond * time.Duration(-bl.freeBytes/(bl.bw*1048/8))) } } diff --git a/config.go b/config.go index cafa16b..c69a24a 100644 --- a/config.go +++ b/config.go @@ -2,7 +2,9 @@ package main import ( "encoding/json" + "flag" "io/ioutil" + "os" "sync" "time" ) @@ -13,14 +15,14 @@ const IntValueNotSet int = -99999999 type AppConfig struct { // required - AppName string - Protocol string - SrcPort int - PeerNode string - DstPort int - DstHost string - PeerUser string - PeerPassword string + AppName string + Protocol string + SrcPort int + PeerNode string + DstPort int + DstHost string + PeerUser string + Enabled int // default:1 // runtime info peerToken uint64 peerNatType int @@ -40,14 +42,29 @@ type Config struct { mtx sync.Mutex } -func (c *Config) add(app AppConfig) { +func (c *Config) switchApp(app AppConfig, enabled int) { + c.mtx.Lock() + defer c.mtx.Unlock() + for i := 0; i < len(c.Apps); i++ { + if c.Apps[i].Protocol == app.Protocol && c.Apps[i].SrcPort == app.SrcPort { + c.Apps[i].Enabled = enabled + return + } + } +} + +func (c *Config) add(app AppConfig, force bool) { c.mtx.Lock() defer c.mtx.Unlock() if app.SrcPort == 0 || app.DstPort == 0 { + gLog.Println(LevelERROR, "invalid app ", app) return } for i := 0; i < len(c.Apps); i++ { if c.Apps[i].Protocol == app.Protocol && c.Apps[i].SrcPort == app.SrcPort { + if force { + c.Apps[i] = app + } return } } @@ -85,7 +102,7 @@ func (c *Config) load() error { defer c.mtx.Unlock() data, err := ioutil.ReadFile("config.json") if err != nil { - gLog.Println(LevelERROR, "read config.json error:", err) + // gLog.Println(LevelERROR, "read config.json error:", err) return err } err = json.Unmarshal(data, &c) @@ -97,9 +114,9 @@ func (c *Config) load() error { type NetworkConfig struct { // local info + Token uint64 Node string User string - Password string localIP string ipv6 string hostName string @@ -114,3 +131,80 @@ type NetworkConfig struct { UDPPort1 int UDPPort2 int } + +func parseParams() { + serverHost := flag.String("serverhost", "api.openp2p.cn", "server host ") + // serverHost := flag.String("serverhost", "127.0.0.1", "server host ") // for debug + node := flag.String("node", "", "node name. 8-31 characters") + token := flag.Uint64("token", 0, "token") + peerNode := flag.String("peernode", "", "peer node name that you want to connect") + dstIP := flag.String("dstip", "127.0.0.1", "destination ip ") + dstPort := flag.Int("dstport", 0, "destination port ") + srcPort := flag.Int("srcport", 0, "source port ") + protocol := flag.String("protocol", "tcp", "tcp or udp") + appName := flag.String("appname", "", "app name") + flag.Bool("noshare", false, "deprecated. uses -sharebandwidth -1") // Deprecated, rm later + shareBandwidth := flag.Int("sharebandwidth", 10, "N mbps share bandwidth limit, private node no limit") + flag.Bool("f", false, "deprecated. config file") // Deprecated, rm later + daemonMode := flag.Bool("d", false, "daemonMode") + flag.Bool("bydaemon", false, "start by daemon") // Deprecated, rm later + logLevel := flag.Int("loglevel", 1, "0:debug 1:info 2:warn 3:error") + flag.Parse() + + config := AppConfig{Enabled: 1} + config.PeerNode = *peerNode + config.DstHost = *dstIP + config.DstPort = *dstPort + config.SrcPort = *srcPort + config.Protocol = *protocol + config.AppName = *appName + gConf.load() + if config.SrcPort != 0 { + gConf.add(config, true) + } + gConf.mtx.Lock() + + // spec paramters in commandline will always be used + flag.Visit(func(f *flag.Flag) { + if f.Name == "sharebandwidth" { + gConf.Network.ShareBandwidth = *shareBandwidth + } + if f.Name == "node" { + gConf.Network.Node = *node + } + if f.Name == "serverhost" { + gConf.Network.ServerHost = *serverHost + } + if f.Name == "loglevel" { + gConf.LogLevel = *logLevel + } + }) + + if gConf.Network.ServerHost == "" { + gConf.Network.ServerHost = *serverHost + } + if gConf.Network.Node == "" { + gConf.Network.Node = *node + } + if *token != 0 { + gConf.Network.Token = *token + } + if gConf.LogLevel == IntValueNotSet { + gConf.LogLevel = *logLevel + } + if gConf.Network.ShareBandwidth == IntValueNotSet { + gConf.Network.ShareBandwidth = *shareBandwidth + } + + gConf.Network.ServerPort = 27183 + gConf.Network.UDPPort1 = 27182 + gConf.Network.UDPPort2 = 27183 + gLog.setLevel(LogLevel(gConf.LogLevel)) + gConf.mtx.Unlock() + gConf.save() + if *daemonMode { + d := daemon{} + d.run() + os.Exit(0) + } +} diff --git a/daemon.go b/daemon.go index e34c4f3..7e26d67 100644 --- a/daemon.go +++ b/daemon.go @@ -5,7 +5,9 @@ import ( "fmt" "io" "os" + "os/exec" "path/filepath" + "strings" "time" "github.com/kardianos/service" @@ -64,7 +66,7 @@ func (d *daemon) run() { } for { // start worker - gLog.Println(LevelINFO, "start worker process") + gLog.Println(LevelINFO, "start worker process, args:", args) execSpec := &os.ProcAttr{Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}} p, err := os.StartProcess(binPath, args, execSpec) if err != nil { @@ -104,21 +106,22 @@ func (d *daemon) Control(ctrlComm string, exeAbsPath string, args []string) erro // examples: // listen: -// ./openp2p install -node hhd1207-222 -user tenderiron -password 13760636579 -sharebandwidth 0 +// ./openp2p install -node hhd1207-222 -token YOUR-TOKEN -sharebandwidth -1 // listen and build p2papp: -// ./openp2p install -node hhd1207-222 -user tenderiron -password 13760636579 -sharebandwidth 0 -peernode hhdhome-n1 -dstip 127.0.0.1 -dstport 50022 -protocol tcp -srcport 22 +// ./openp2p install -node hhd1207-222 -token YOUR-TOKEN -sharebandwidth -1 -peernode hhdhome-n1 -dstip 127.0.0.1 -dstport 50022 -protocol tcp -srcport 22 func install() { - gLog = InitLogger(filepath.Dir(os.Args[0]), "openp2p-install", LevelDEBUG, 1024*1024, LogConsole) + gLog.Println(LevelINFO, "install start") + defer gLog.Println(LevelINFO, "install end") + // auto uninstall + + uninstall() // save config file installFlag := flag.NewFlagSet("install", flag.ExitOnError) serverHost := installFlag.String("serverhost", "api.openp2p.cn", "server host ") // serverHost := flag.String("serverhost", "127.0.0.1", "server host ") // for debug - user := installFlag.String("user", "", "user name. 8-31 characters") - node := installFlag.String("node", "", "node name. 8-31 characters") - password := installFlag.String("password", "", "user password. 8-31 characters") + token := installFlag.Uint64("token", 0, "token") + node := installFlag.String("node", "", "node name. 8-31 characters. if not set, it will be hostname") peerNode := installFlag.String("peernode", "", "peer node name that you want to connect") - peerUser := installFlag.String("peeruser", "", "peer node user (default peeruser=user)") - peerPassword := installFlag.String("peerpassword", "", "peer node password (default peerpassword=password)") dstIP := installFlag.String("dstip", "127.0.0.1", "destination ip ") dstPort := installFlag.Int("dstport", 0, "destination port ") srcPort := installFlag.Int("srcport", 0, "source port ") @@ -128,36 +131,48 @@ func install() { shareBandwidth := installFlag.Int("sharebandwidth", 10, "N mbps share bandwidth limit, private node no limit") logLevel := installFlag.Int("loglevel", 1, "0:debug 1:info 2:warn 3:error") installFlag.Parse(os.Args[2:]) - checkParams(*node, *user, *password) + if *node != "" && len(*node) < 8 { + gLog.Println(LevelERROR, "node name too short, it must >=8 charaters") + os.Exit(9) + } + if *node == "" { // if node name not set. use os.Hostname + hostname, _ := os.Hostname() + node = &hostname + } + gConf.load() // load old config. otherwise will clear all apps gConf.LogLevel = *logLevel gConf.Network.ServerHost = *serverHost - gConf.Network.User = *user + gConf.Network.Token = *token gConf.Network.Node = *node - gConf.Network.Password = *password - gConf.Network.ServerPort = 27182 + gConf.Network.ServerPort = 27183 gConf.Network.UDPPort1 = 27182 gConf.Network.UDPPort2 = 27183 gConf.Network.ShareBandwidth = *shareBandwidth - config := AppConfig{} + config := AppConfig{Enabled: 1} config.PeerNode = *peerNode - config.PeerUser = *peerUser - config.PeerPassword = *peerPassword config.DstHost = *dstIP config.DstPort = *dstPort config.SrcPort = *srcPort config.Protocol = *protocol config.AppName = *appName - gConf.add(config) - os.MkdirAll(defaultInstallPath, 0775) - err := os.Chdir(defaultInstallPath) + if config.SrcPort != 0 { + gConf.add(config, true) + } + err := os.MkdirAll(defaultInstallPath, 0775) + if err != nil { + gLog.Printf(LevelERROR, "MkdirAll %s error:%s", defaultInstallPath, err) + return + } + err = os.Chdir(defaultInstallPath) if err != nil { gLog.Println(LevelERROR, "cd error:", err) + return } gConf.save() - + targetPath := filepath.Join(defaultInstallPath, defaultBinName) + d := daemon{} // copy files - targetPath := filepath.Join(defaultInstallPath, defaultBinName) binPath, _ := os.Executable() src, errFiles := os.Open(binPath) // can not use args[0], on Windows call openp2p is ok(=openp2p.exe) if errFiles != nil { @@ -180,14 +195,10 @@ func install() { dst.Close() // install system service - d := daemon{} - // args := []string{""} gLog.Println(LevelINFO, "targetPath:", targetPath) err = d.Control("install", targetPath, []string{"-d"}) - if err != nil { - gLog.Println(LevelERROR, "install system service error:", err) - } else { + if err == nil { gLog.Println(LevelINFO, "install system service ok.") } time.Sleep(time.Second * 2) @@ -199,11 +210,45 @@ func install() { } } +func installByFilename() { + params := strings.Split(filepath.Base(os.Args[0]), "-") + if len(params) < 4 { + return + } + serverHost := params[1] + token := params[2] + gLog.Println(LevelINFO, "install start") + targetPath := os.Args[0] + args := []string{"install"} + args = append(args, "-serverhost") + args = append(args, serverHost) + args = append(args, "-token") + args = append(args, token) + env := os.Environ() + cmd := exec.Command(targetPath, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + cmd.Env = env + err := cmd.Run() + if err != nil { + gLog.Println(LevelERROR, "install by filename, start process error:", err) + return + } + gLog.Println(LevelINFO, "install end") + fmt.Println("Press the Any Key to exit") + fmt.Scanln() + os.Exit(0) +} func uninstall() { - gLog = InitLogger(filepath.Dir(os.Args[0]), "openp2p-install", LevelDEBUG, 1024*1024, LogFileAndConsole) + gLog.Println(LevelINFO, "uninstall start") + defer gLog.Println(LevelINFO, "uninstall end") d := daemon{} - d.Control("stop", "", nil) - err := d.Control("uninstall", "", nil) + err := d.Control("stop", "", nil) + if err != nil { // service maybe not install + return + } + err = d.Control("uninstall", "", nil) if err != nil { gLog.Println(LevelERROR, "uninstall system service error:", err) } else { @@ -211,21 +256,6 @@ func uninstall() { } binPath := filepath.Join(defaultInstallPath, defaultBinName) os.Remove(binPath + "0") - os.Rename(binPath, binPath+"0") - os.RemoveAll(defaultInstallPath) -} - -func checkParams(node, user, password string) { - if len(node) < 8 { - gLog.Println(LevelERROR, "node name too short, it must >=8 charaters") - os.Exit(9) - } - if len(user) < 8 { - gLog.Println(LevelERROR, "user name too short, it must >=8 charaters") - os.Exit(9) - } - if len(password) < 8 { - gLog.Println(LevelERROR, "password too short, it must >=8 charaters") - os.Exit(9) - } + os.Remove(binPath) + // os.RemoveAll(defaultInstallPath) // reserve config.json } diff --git a/handlepush.go b/handlepush.go index f6cb495..d42c6ac 100644 --- a/handlepush.go +++ b/handlepush.go @@ -8,8 +8,6 @@ import ( "os" "os/exec" "path/filepath" - "runtime" - "syscall" "time" ) @@ -30,10 +28,10 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error { } gLog.Printf(LevelINFO, "%s is connecting...", req.From) gLog.Println(LevelDEBUG, "push connect response to ", req.From) - // verify token or name&password - if VerifyTOTP(req.Token, pn.config.User, pn.config.Password, time.Now().Unix()+(pn.serverTs-pn.localTs)) || // localTs may behind, auto adjust ts - VerifyTOTP(req.Token, pn.config.User, pn.config.Password, time.Now().Unix()) || - (req.User == pn.config.User && req.Password == pn.config.Password) { + // verify totp token or token + if VerifyTOTP(req.Token, pn.config.Token, time.Now().Unix()+(pn.serverTs-pn.localTs)) || // localTs may behind, auto adjust ts + VerifyTOTP(req.Token, pn.config.Token, time.Now().Unix()) || + (req.FromToken == pn.config.Token) { gLog.Printf(LevelINFO, "Access Granted\n") config := AppConfig{} config.peerNatType = req.NatType @@ -41,7 +39,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error { config.peerIP = req.FromIP config.PeerNode = req.From // share relay node will limit bandwidth - if req.User != pn.config.User || req.Password != pn.config.Password { + if req.FromToken != pn.config.Token { gLog.Printf(LevelINFO, "set share bandwidth %d mbps", pn.config.ShareBandwidth) config.shareBandwidth = pn.config.ShareBandwidth } @@ -79,9 +77,6 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error { config := AppConfig{} config.PeerNode = req.RelayName config.peerToken = req.RelayToken - // set user password, maybe the relay node is your private node - config.PeerUser = pn.config.User - config.PeerPassword = pn.config.Password go func(r AddRelayTunnelReq) { t, errDt := pn.addDirectTunnel(config, 0) if errDt == nil { @@ -93,23 +88,25 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error { }(req) case MsgPushUpdate: + gLog.Println(LevelINFO, "MsgPushUpdate") + update() // download new version first, then exec ./openp2p update targetPath := filepath.Join(defaultInstallPath, defaultBinName) args := []string{"update"} env := os.Environ() - // Windows does not support exec syscall. - if runtime.GOOS == "windows" { - cmd := exec.Command(targetPath, args...) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Stdin = os.Stdin - cmd.Env = env - err := cmd.Run() - if err == nil { - os.Exit(0) - } - return err + cmd := exec.Command(targetPath, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Stdin = os.Stdin + cmd.Env = env + err := cmd.Run() + if err == nil { + os.Exit(0) } - return syscall.Exec(targetPath, args, env) + return err + case MsgPushRestart: + gLog.Println(LevelINFO, "MsgPushRestart") + os.Exit(0) + return err case MsgPushReportApps: gLog.Println(LevelINFO, "MsgPushReportApps") req := ReportApps{} @@ -117,6 +114,14 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error { gConf.mtx.Lock() defer gConf.mtx.Unlock() for _, config := range gConf.Apps { + appActive := 0 + i, ok := pn.apps.Load(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort)) + if ok { + app := i.(*p2pApp) + if app.isActive() { + appActive = 1 + } + } appInfo := AppInfo{ AppName: config.AppName, Protocol: config.Protocol, @@ -129,29 +134,11 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error { PeerIP: config.peerIP, PeerNatType: config.peerNatType, RetryTime: config.retryTime.String(), - IsActive: 1, + IsActive: appActive, + Enabled: config.Enabled, } req.Apps = append(req.Apps, appInfo) } - // pn.apps.Range(func(_, i interface{}) bool { - // app := i.(*p2pApp) - // appInfo := AppInfo{ - // AppName: app.config.AppName, - // Protocol: app.config.Protocol, - // SrcPort: app.config.SrcPort, - // RelayNode: app.relayNode, - // PeerNode: app.config.PeerNode, - // DstHost: app.config.DstHost, - // DstPort: app.config.DstPort, - // PeerUser: app.config.PeerUser, - // PeerIP: app.config.peerIP, - // PeerNatType: app.config.peerNatType, - // RetryTime: app.config.retryTime.String(), - // IsActive: 1, - // } - // req.Apps = append(req.Apps, appInfo) - // return true - // }) pn.write(MsgReport, MsgReportApps, &req) case MsgPushEditApp: gLog.Println(LevelINFO, "MsgPushEditApp") @@ -161,7 +148,7 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error { gLog.Printf(LevelERROR, "wrong MsgPushEditApp:%s %s", err, string(msg[openP2PHeaderSize:])) return err } - var oldConf AppConfig + oldConf := AppConfig{Enabled: 1} // protocol0+srcPort0 exist, delApp oldConf.AppName = newApp.AppName oldConf.Protocol = newApp.Protocol0 @@ -175,12 +162,42 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error { newConf := oldConf newConf.Protocol = newApp.Protocol newConf.SrcPort = newApp.SrcPort - gConf.add(newConf) - gConf.save() - pn.DeleteApp(oldConf) // save quickly for the next request reportApplist + gConf.add(newConf, false) + gConf.save() // save quickly for the next request reportApplist + pn.DeleteApp(oldConf) // DeleteApp may cost some times, execute at the end // autoReconnect will auto AddApp // pn.AddApp(config) // TODO: report result + case MsgPushEditNode: + gLog.Println(LevelINFO, "MsgPushEditNode") + req := EditNode{} + err := json.Unmarshal(msg[openP2PHeaderSize:], &req) + if err != nil { + gLog.Printf(LevelERROR, "wrong MsgPushEditNode:%s %s", err, string(msg[openP2PHeaderSize:])) + return err + } + gConf.mtx.Lock() + gConf.Network.Node = req.NewName + gConf.Network.ShareBandwidth = req.Bandwidth + gConf.mtx.Unlock() + gConf.save() + // TODO: hot reload + os.Exit(0) + case MsgPushSwitchApp: + gLog.Println(LevelINFO, "MsgPushSwitchApp") + app := AppInfo{} + err := json.Unmarshal(msg[openP2PHeaderSize:], &app) + if err != nil { + gLog.Printf(LevelERROR, "wrong MsgPushSwitchApp:%s %s", err, string(msg[openP2PHeaderSize:])) + return err + } + config := AppConfig{Enabled: app.Enabled, SrcPort: app.SrcPort, Protocol: app.Protocol} + gLog.Println(LevelINFO, app.AppName, " switch to ", app.Enabled) + gConf.switchApp(config, app.Enabled) + if app.Enabled == 0 { + // disable APP + pn.DeleteApp(config) + } default: pn.msgMapMtx.Lock() ch := pn.msgMap[pushHead.From] diff --git a/openp2p.go b/openp2p.go index 6cd626e..61ef2dd 100644 --- a/openp2p.go +++ b/openp2p.go @@ -1,7 +1,6 @@ package main import ( - "flag" "fmt" "math/rand" "os" @@ -14,9 +13,8 @@ func main() { binDir := filepath.Dir(os.Args[0]) os.Chdir(binDir) // for system service gLog = InitLogger(binDir, "openp2p", LevelDEBUG, 1024*1024, LogFileAndConsole) - + gLog.Println(LevelINFO, "openp2p start. version: ", OpenP2PVersion) // TODO: install sub command, deamon process - // groups := flag.String("groups", "", "you could join in several groups. like: GroupName1:Password1;GroupName2:Password2; group name 8-31 characters") if len(os.Args) > 1 { switch os.Args[1] { case "version", "-v", "--version": @@ -24,7 +22,6 @@ func main() { return case "update": gLog = InitLogger(filepath.Dir(os.Args[0]), "openp2p", LevelDEBUG, 1024*1024, LogFileAndConsole) - update() targetPath := filepath.Join(defaultInstallPath, defaultBinName) d := daemon{} err := d.Control("restart", targetPath, nil) @@ -41,95 +38,11 @@ func main() { uninstall() return } - } - serverHost := flag.String("serverhost", "api.openp2p.cn", "server host ") - // serverHost := flag.String("serverhost", "127.0.0.1", "server host ") // for debug - user := flag.String("user", "", "user name. 8-31 characters") - node := flag.String("node", "", "node name. 8-31 characters") - password := flag.String("password", "", "user password. 8-31 characters") - peerNode := flag.String("peernode", "", "peer node name that you want to connect") - peerUser := flag.String("peeruser", "", "peer node user (default peeruser=user)") - peerPassword := flag.String("peerpassword", "", "peer node password (default peerpassword=password)") - dstIP := flag.String("dstip", "127.0.0.1", "destination ip ") - dstPort := flag.Int("dstport", 0, "destination port ") - srcPort := flag.Int("srcport", 0, "source port ") - protocol := flag.String("protocol", "tcp", "tcp or udp") - appName := flag.String("appname", "", "app name") - flag.Bool("noshare", false, "deprecated. uses -sharebandwidth -1") // Deprecated, rm later - shareBandwidth := flag.Int("sharebandwidth", 10, "N mbps share bandwidth limit, private node no limit") - flag.Bool("f", false, "deprecated. config file") // Deprecated, rm later - daemonMode := flag.Bool("d", false, "daemonMode") - flag.Bool("bydaemon", false, "start by daemon") // Deprecated, rm later - logLevel := flag.Int("loglevel", 1, "0:debug 1:info 2:warn 3:error") - flag.Parse() - - config := AppConfig{} - config.PeerNode = *peerNode - config.PeerUser = *peerUser - config.PeerPassword = *peerPassword - config.DstHost = *dstIP - config.DstPort = *dstPort - config.SrcPort = *srcPort - config.Protocol = *protocol - config.AppName = *appName - // add command config first - gConf.add(config) - gConf.load() - gConf.mtx.Lock() - - // spec paramters in commandline will always be used - flag.Visit(func(f *flag.Flag) { - if f.Name == "sharebandwidth" { - gConf.Network.ShareBandwidth = *shareBandwidth - } - if f.Name == "node" { - gConf.Network.Node = *node - } - if f.Name == "user" { - gConf.Network.User = *user - } - if f.Name == "password" { - gConf.Network.Password = *password - } - if f.Name == "serverhost" { - gConf.Network.ServerHost = *serverHost - } - if f.Name == "loglevel" { - gConf.LogLevel = *logLevel - } - }) - - if gConf.Network.ServerHost == "" { - gConf.Network.ServerHost = *serverHost - } - if gConf.Network.Node == "" { - gConf.Network.Node = *node - } - if gConf.Network.User == "" { - gConf.Network.User = *user - } - if gConf.Network.Password == "" { - gConf.Network.Password = *password - } - if gConf.LogLevel == IntValueNotSet { - gConf.LogLevel = *logLevel - } - if gConf.Network.ShareBandwidth == IntValueNotSet { - gConf.Network.ShareBandwidth = *shareBandwidth + } else { + installByFilename() } - gConf.Network.ServerPort = 27182 - gConf.Network.UDPPort1 = 27182 - gConf.Network.UDPPort2 = 27183 - gLog.Println(LevelINFO, "openp2p start. version: ", OpenP2PVersion) - gLog.setLevel(LogLevel(gConf.LogLevel)) - gConf.mtx.Unlock() - gConf.save() - if *daemonMode { - d := daemon{} - d.run() - return - } + parseParams() gLog.Println(LevelINFO, &gConf) setFirewall() network := P2PNetworkInstance(&gConf.Network) diff --git a/p2papp.go b/p2papp.go index beafb1e..bceabbf 100644 --- a/p2papp.go +++ b/p2papp.go @@ -76,8 +76,7 @@ func (app *p2pApp) listenTCP() error { gLog.Printf(LevelDEBUG, "Accept overlayID:%d", otcp.id) // tell peer connect req := OverlayConnectReq{ID: otcp.id, - User: app.config.PeerUser, - Password: app.config.PeerPassword, + Token: app.tunnel.pn.config.Token, DstIP: app.config.DstHost, DstPort: app.config.DstPort, Protocol: app.config.Protocol, @@ -109,7 +108,9 @@ func (app *p2pApp) listen() error { go app.relayHeartbeatLoop() } for app.running { - if app.config.Protocol == "tcp" { + if app.config.Protocol == "udp" { + app.listenTCP() + } else { app.listenTCP() } time.Sleep(time.Second * 5) diff --git a/p2pnetwork.go b/p2pnetwork.go index edef229..23d519c 100644 --- a/p2pnetwork.go +++ b/p2pnetwork.go @@ -97,12 +97,8 @@ func (pn *P2PNetwork) runAll() { gConf.mtx.Lock() defer gConf.mtx.Unlock() for _, config := range gConf.Apps { - // set default peer user password - if config.PeerPassword == "" { - config.PeerPassword = gConf.Network.Password - } - if config.PeerUser == "" { - config.PeerUser = gConf.Network.User + if config.Enabled == 0 { + continue } if config.AppName == "" { config.AppName = fmt.Sprintf("%s%d", config.Protocol, config.SrcPort) @@ -249,7 +245,6 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error { PeerNode: config.PeerNode, DstPort: config.DstPort, DstHost: config.DstHost, - PeerUser: config.PeerUser, PeerNatType: peerNatType, PeerIP: peerIP, ShareBandwidth: pn.config.ShareBandwidth, @@ -257,7 +252,9 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error { Version: OpenP2PVersion, } pn.write(MsgReport, MsgReportConnect, &req) - + if err != nil { + return err + } app := p2pApp{ id: appID, key: appKey, @@ -387,8 +384,7 @@ func (pn *P2PNetwork) init() error { u := url.URL{Scheme: "wss", Host: gatewayURL, Path: forwardPath} q := u.Query() q.Add("node", pn.config.Node) - q.Add("user", pn.config.User) - q.Add("password", pn.config.Password) + q.Add("token", fmt.Sprintf("%d", pn.config.Token)) q.Add("version", OpenP2PVersion) q.Add("nattype", fmt.Sprintf("%d", pn.config.natType)) q.Add("sharebandwidth", fmt.Sprintf("%d", pn.config.ShareBandwidth)) @@ -460,8 +456,15 @@ func (pn *P2PNetwork) handleMessage(t int, msg []byte) { pn.running = false } else { pn.serverTs = rsp.Ts + pn.config.Token = rsp.Token + pn.config.User = rsp.User + gConf.mtx.Lock() + gConf.Network.Token = rsp.Token + gConf.Network.User = rsp.User + gConf.mtx.Unlock() + gConf.save() pn.localTs = time.Now().Unix() - gLog.Printf(LevelINFO, "login ok. Server ts=%d, local ts=%d", rsp.Ts, pn.localTs) + gLog.Printf(LevelINFO, "login ok. user=%s,Server ts=%d, local ts=%d", rsp.User, rsp.Ts, pn.localTs) } case MsgHeartbeat: gLog.Printf(LevelDEBUG, "P2PNetwork heartbeat ok") @@ -561,12 +564,15 @@ func (pn *P2PNetwork) read(node string, mainType uint16, subType uint16, timeout } else { nodeID = nodeNameToID(node) } + pn.msgMapMtx.Lock() + ch := pn.msgMap[nodeID] + pn.msgMapMtx.Unlock() for { select { case <-time.After(timeout): gLog.Printf(LevelERROR, "wait msg%d:%d timeout", mainType, subType) return - case msg := <-pn.msgMap[nodeID]: + case msg := <-ch: head = &openP2PHeader{} err := binary.Read(bytes.NewReader(msg[:openP2PHeaderSize]), binary.LittleEndian, head) if err != nil { diff --git a/p2ptunnel.go b/p2ptunnel.go index 4e324c4..b9e56b4 100644 --- a/p2ptunnel.go +++ b/p2ptunnel.go @@ -55,10 +55,9 @@ func (t *P2PTunnel) connect() error { gLog.Printf(LevelDEBUG, "start p2pTunnel to %s ", t.config.PeerNode) t.isServer = false req := PushConnectReq{ - User: t.config.PeerUser, - Password: t.config.PeerPassword, Token: t.config.peerToken, From: t.pn.config.Node, + FromToken: t.pn.config.Token, FromIP: t.pn.config.publicIP, ConeNatPort: t.coneNatPort, NatType: t.pn.config.natType, @@ -326,9 +325,9 @@ func (t *P2PTunnel) readLoop() { gLog.Printf(LevelERROR, "wrong MsgOverlayConnectReq:%s", err) continue } - // app connect only accept user/password, avoid someone using the share relay node's token - if req.User != t.pn.config.User || req.Password != t.pn.config.Password { - gLog.Println(LevelERROR, "Access Denied:", req.User) + // app connect only accept token(not relay totp token), avoid someone using the share relay node's token + if req.Token != t.pn.config.Token { + gLog.Println(LevelERROR, "Access Denied:", req.Token) continue } diff --git a/protocol.go b/protocol.go index 110d873..b9531fa 100644 --- a/protocol.go +++ b/protocol.go @@ -10,7 +10,7 @@ import ( "time" ) -const OpenP2PVersion = "0.99.0" +const OpenP2PVersion = "1.0.0" const ProducnName string = "openp2p" type openP2PHeader struct { @@ -80,6 +80,9 @@ const ( MsgPushReportApps = 7 MsgPushQuicConnect = 8 MsgPushEditApp = 9 + MsgPushSwitchApp = 10 + MsgPushRestart = 11 + MsgPushEditNode = 12 ) // MsgP2P sub type message @@ -167,9 +170,8 @@ func nodeNameToID(name string) uint64 { type PushConnectReq struct { From string `json:"from,omitempty"` - User string `json:"user,omitempty"` - Password string `json:"password,omitempty"` - Token uint64 `json:"token,omitempty"` + FromToken uint64 `json:"fromToken,omitempty"` //my token + Token uint64 `json:"token,omitempty"` // totp token ConeNatPort int `json:"coneNatPort,omitempty"` NatType int `json:"natType,omitempty"` FromIP string `json:"fromIP,omitempty"` @@ -193,6 +195,8 @@ type PushRsp struct { type LoginRsp struct { Error int `json:"error,omitempty"` Detail string `json:"detail,omitempty"` + User string `json:"user,omitempty"` + Token uint64 `json:"token,omitempty"` Ts int64 `json:"ts,omitempty"` } @@ -213,8 +217,7 @@ type P2PHandshakeReq struct { type OverlayConnectReq struct { ID uint64 `json:"id,omitempty"` - User string `json:"user,omitempty"` - Password string `json:"password,omitempty"` + Token uint64 `json:"token,omitempty"` // not totp token DstIP string `json:"dstIP,omitempty"` DstPort int `json:"dstPort,omitempty"` Protocol string `json:"protocol,omitempty"` @@ -294,6 +297,7 @@ type AppInfo struct { Version string `json:"version,omitempty"` RetryTime string `json:"retryTime,omitempty"` IsActive int `json:"isActive,omitempty"` + Enabled int `json:"enabled,omitempty"` } type ReportApps struct { @@ -324,3 +328,17 @@ type NetInfo struct { ASNOrg string `json:"asn_org,omitempty"` Hostname string `json:"hostname,omitempty"` } + +type ProfileInfo struct { + User string `json:"user,omitempty"` + Password string `json:"password,omitempty"` + Email string `json:"email,omitempty"` + Phone string `json:"phone,omitempty"` + Token string `json:"token,omitempty"` + Addtime string `json:"addtime,omitempty"` +} + +type EditNode struct { + NewName string `json:"newName,omitempty"` + Bandwidth int `json:"bandwidth,omitempty"` +} diff --git a/quic.go b/quic.go index 7a722ad..300843e 100644 --- a/quic.go +++ b/quic.go @@ -99,7 +99,7 @@ func (conn *quicConn) Accept() error { } func listenQuic(addr string, idleTimeout time.Duration) (*quicConn, error) { - gLog.Println(LevelINFO, "quic listen on ", addr) + gLog.Println(LevelDEBUG, "quic listen on ", addr) listener, err := quic.ListenAddr(addr, generateTLSConfig(), &quic.Config{Versions: quicVersion, MaxIdleTimeout: idleTimeout, DisablePathMTUDiscovery: true}) if err != nil { diff --git a/totp.go b/totp.go index cbf29cd..9560ad2 100644 --- a/totp.go +++ b/totp.go @@ -8,9 +8,11 @@ import ( ) const TOTPStep = 30 // 30s -func GenTOTP(user string, password string, ts int64) uint64 { +func GenTOTP(token uint64, ts int64) uint64 { step := ts / TOTPStep - mac := hmac.New(sha256.New, []byte(user+password)) + tbuff := make([]byte, 8) + binary.LittleEndian.PutUint64(tbuff, token) + mac := hmac.New(sha256.New, tbuff) b := make([]byte, 8) binary.LittleEndian.PutUint64(b, uint64(step)) mac.Write(b) @@ -19,11 +21,11 @@ func GenTOTP(user string, password string, ts int64) uint64 { return num } -func VerifyTOTP(code uint64, user string, password string, ts int64) bool { +func VerifyTOTP(code uint64, token uint64, ts int64) bool { if code == 0 { return false } - if code == GenTOTP(user, password, ts) || code == GenTOTP(user, password, ts-TOTPStep) || code == GenTOTP(user, password, ts+TOTPStep) { + if code == GenTOTP(token, ts) || code == GenTOTP(token, ts-TOTPStep) || code == GenTOTP(token, ts+TOTPStep) { return true } return false diff --git a/totp_test.go b/totp_test.go index f641637..b014479 100644 --- a/totp_test.go +++ b/totp_test.go @@ -9,24 +9,24 @@ import ( func TestTOTP(t *testing.T) { for i := 0; i < 20; i++ { ts := time.Now().Unix() - code := GenTOTP("testuser1", "testpassword1", ts) + code := GenTOTP(13666999958022769123, ts) t.Log(code) - if !VerifyTOTP(code, "testuser1", "testpassword1", ts) { + if !VerifyTOTP(code, 13666999958022769123, ts) { t.Error("TOTP error") } - if !VerifyTOTP(code, "testuser1", "testpassword1", ts-10) { + if !VerifyTOTP(code, 13666999958022769123, ts-10) { t.Error("TOTP error") } - if !VerifyTOTP(code, "testuser1", "testpassword1", ts+10) { + if !VerifyTOTP(code, 13666999958022769123, ts+10) { t.Error("TOTP error") } - if VerifyTOTP(code, "testuser1", "testpassword1", ts+60) { + if VerifyTOTP(code, 13666999958022769123, ts+60) { t.Error("TOTP error") } - if VerifyTOTP(code, "testuser2", "testpassword1", ts+1) { + if VerifyTOTP(code, 13666999958022769124, ts+1) { t.Error("TOTP error") } - if VerifyTOTP(code, "testuser1", "testpassword2", ts+1) { + if VerifyTOTP(code, 13666999958022769125, ts+1) { t.Error("TOTP error") } time.Sleep(time.Second) diff --git a/update.go b/update.go index 9c9d094..b5ed136 100644 --- a/update.go +++ b/update.go @@ -27,7 +27,7 @@ func update() { } goos := runtime.GOOS goarch := runtime.GOARCH - rsp, err := c.Get(fmt.Sprintf("https://openp2p.cn:27182/api/v1/update?fromver=%s&os=%s&arch=%s", OpenP2PVersion, goos, goarch)) + rsp, err := c.Get(fmt.Sprintf("https://openp2p.cn:27183/api/v1/update?fromver=%s&os=%s&arch=%s", OpenP2PVersion, goos, goarch)) if err != nil { gLog.Println(LevelERROR, "update:query update list failed:", err) return