This commit is contained in:
TenderIronh
2022-04-27 23:26:23 +08:00
parent 037f3cc34e
commit b2d35c6f97
28 changed files with 1810 additions and 608 deletions
+1
View File
@@ -95,6 +95,7 @@ Windows默认会阻止没有花钱买它家证书签名过的程序,选择“
服务端有个调度模型,根据带宽、ping值、稳定性、服务时长,尽可能地使共享节点均匀地提供服务。连接共享节点使用TOTP密码,hmac-sha256算法校验,它是一次性密码,和我们平时使用的手机验证码或银行密码器一样的原理。 服务端有个调度模型,根据带宽、ping值、稳定性、服务时长,尽可能地使共享节点均匀地提供服务。连接共享节点使用TOTP密码,hmac-sha256算法校验,它是一次性密码,和我们平时使用的手机验证码或银行密码器一样的原理。
## 编译 ## 编译
go version go1.18.1+
cd到代码根目录,执行 cd到代码根目录,执行
``` ```
export GOPROXY=https://goproxy.io,direct export GOPROXY=https://goproxy.io,direct
+1
View File
@@ -103,6 +103,7 @@ That's right, the relay node is naturally an man-in-middle, so AES encryption is
The server side has a scheduling model, which calculate bandwith, ping value,stability and service duration to provide a well-proportioned service to every share node. It uses TOTP(Time-based One-time Password) with hmac-sha256 algorithem, its theory as same as the cellphone validation code or bank cipher coder. The server side has a scheduling model, which calculate bandwith, ping value,stability and service duration to provide a well-proportioned service to every share node. It uses TOTP(Time-based One-time Password) with hmac-sha256 algorithem, its theory as same as the cellphone validation code or bank cipher coder.
## Build ## Build
go version go1.18.1+
cd root directory of the socure code and execute cd root directory of the socure code and execute
``` ```
export GOPROXY=https://goproxy.io,direct export GOPROXY=https://goproxy.io,direct
+36 -3
View File
@@ -12,6 +12,8 @@ import (
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
"strconv"
"strings"
"time" "time"
) )
@@ -77,6 +79,7 @@ func pkcs7UnPadding(origData []byte, dataLen int) ([]byte, error) {
return origData[:(dataLen - unPadLen)], nil return origData[:(dataLen - unPadLen)], nil
} }
// AES-CBC
func encryptBytes(key []byte, out, in []byte, plainLen int) ([]byte, error) { func encryptBytes(key []byte, out, in []byte, plainLen int) ([]byte, error) {
if len(key) == 0 { if len(key) == 0 {
return in[:plainLen], nil return in[:plainLen], nil
@@ -122,20 +125,20 @@ func netInfo() *NetInfo {
client := &http.Client{Transport: tr, Timeout: time.Second * 10} client := &http.Client{Transport: tr, Timeout: time.Second * 10}
r, err := client.Get("https://ifconfig.co/json") r, err := client.Get("https://ifconfig.co/json")
if err != nil { if err != nil {
gLog.Println(LevelINFO, "netInfo error:", err) gLog.Println(LvINFO, "netInfo error:", err)
continue continue
} }
defer r.Body.Close() defer r.Body.Close()
buf := make([]byte, 1024*64) buf := make([]byte, 1024*64)
n, err := r.Body.Read(buf) n, err := r.Body.Read(buf)
if err != nil { if err != nil {
gLog.Println(LevelINFO, "netInfo error:", err) gLog.Println(LvINFO, "netInfo error:", err)
continue continue
} }
rsp := NetInfo{} rsp := NetInfo{}
err = json.Unmarshal(buf[:n], &rsp) err = json.Unmarshal(buf[:n], &rsp)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong NetInfo:%s", err) gLog.Printf(LvERROR, "wrong NetInfo:%s", err)
continue continue
} }
return &rsp return &rsp
@@ -158,3 +161,33 @@ func defaultNodeName() string {
} }
return name return name
} }
const EQUAL int = 0
const GREATER int = 1
const LESS int = -1
func compareVersion(v1, v2 string) int {
if v1 == v2 {
return EQUAL
}
v1Arr := strings.Split(v1, ".")
v2Arr := strings.Split(v2, ".")
for i, subVer := range v1Arr {
if len(v2Arr) <= i {
return GREATER
}
subv1, _ := strconv.Atoi(subVer)
subv2, _ := strconv.Atoi(v2Arr[i])
if subv1 > subv2 {
return GREATER
}
if subv1 < subv2 {
return LESS
}
}
return LESS
}
func IsIPv6(address string) bool {
return strings.Count(address, ":") >= 2
}
+26
View File
@@ -43,3 +43,29 @@ func TestAESCBC(t *testing.T) {
func TestNetInfo(t *testing.T) { func TestNetInfo(t *testing.T) {
log.Println(netInfo()) log.Println(netInfo())
} }
func assertCompareVersion(t *testing.T, v1 string, v2 string, result int) {
if compareVersion(v1, v2) != result {
t.Errorf("compare version %s %s fail\n", v1, v2)
}
}
func TestCompareVersion(t *testing.T) {
// test =
assertCompareVersion(t, "0.98.0", "0.98.0", EQUAL)
assertCompareVersion(t, "0.98", "0.98", EQUAL)
assertCompareVersion(t, "1.4.0", "1.4.0", EQUAL)
assertCompareVersion(t, "1.5.0", "1.5.0", EQUAL)
// test >
assertCompareVersion(t, "0.98.0.22345", "0.98.0.12345", GREATER)
assertCompareVersion(t, "1.98.0.12345", "0.98", GREATER)
assertCompareVersion(t, "10.98.0.12345", "9.98.0.12345", GREATER)
assertCompareVersion(t, "1.4.0", "0.98.0.12345", GREATER)
assertCompareVersion(t, "1.4", "0.98.0.12345", GREATER)
assertCompareVersion(t, "1", "0.98.0.12345", GREATER)
// test <
assertCompareVersion(t, "0.98.0.12345", "0.98.0.12346", LESS)
assertCompareVersion(t, "9.98.0.12345", "10.98.0.12345", LESS)
assertCompareVersion(t, "1.4.2", "1.5.0", LESS)
assertCompareVersion(t, "", "1.5.0", LESS)
}
+48 -27
View File
@@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"flag" "flag"
"io/ioutil" "io/ioutil"
"os"
"sync" "sync"
"time" "time"
) )
@@ -23,8 +24,12 @@ type AppConfig struct {
PeerUser string PeerUser string
Enabled int // default:1 Enabled int // default:1
// runtime info // runtime info
peerVersion string
peerToken uint64 peerToken uint64
peerNatType int peerNatType int
hasIPv4 int
IPv6 string
hasUPNPorNATPMP int
peerIP string peerIP string
peerConeNatPort int peerConeNatPort int
retryNum int retryNum int
@@ -61,7 +66,7 @@ func (c *Config) add(app AppConfig, override bool) {
c.mtx.Lock() c.mtx.Lock()
defer c.mtx.Unlock() defer c.mtx.Unlock()
if app.SrcPort == 0 || app.DstPort == 0 { if app.SrcPort == 0 || app.DstPort == 0 {
gLog.Println(LevelERROR, "invalid app ", app) gLog.Println(LvERROR, "invalid app ", app)
return return
} }
if override { if override {
@@ -95,7 +100,7 @@ func (c *Config) save() {
data, _ := json.MarshalIndent(c, "", " ") data, _ := json.MarshalIndent(c, "", " ")
err := ioutil.WriteFile("config.json", data, 0644) err := ioutil.WriteFile("config.json", data, 0644)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "save config.json error:", err) gLog.Println(LvERROR, "save config.json error:", err)
} }
} }
@@ -111,7 +116,7 @@ func (c *Config) load() error {
} }
err = json.Unmarshal(data, &c) err = json.Unmarshal(data, &c)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "parse config.json error:", err) gLog.Println(LvERROR, "parse config.json error:", err)
} }
return err return err
} }
@@ -148,6 +153,9 @@ type NetworkConfig struct {
os string os string
publicIP string publicIP string
natType int natType int
hasIPv4 int
IPv6 string
hasUPNPorNATPMP int
ShareBandwidth int ShareBandwidth int
// server info // server info
ServerHost string ServerHost string
@@ -156,22 +164,28 @@ type NetworkConfig struct {
UDPPort2 int UDPPort2 int
} }
func parseParams() { func parseParams(subCommand string) {
serverHost := flag.String("serverhost", "api.openp2p.cn", "server host ") fset := flag.NewFlagSet(subCommand, flag.ExitOnError)
serverHost := fset.String("serverhost", "api.openp2p.cn", "server host ")
// serverHost := flag.String("serverhost", "127.0.0.1", "server host ") // for debug // serverHost := flag.String("serverhost", "127.0.0.1", "server host ") // for debug
node := flag.String("node", "", "node name. 8-31 characters") token := fset.Uint64("token", 0, "token")
token := flag.Uint64("token", 0, "token") node := fset.String("node", "", "node name. 8-31 characters. if not set, it will be hostname")
peerNode := flag.String("peernode", "", "peer node name that you want to connect") peerNode := fset.String("peernode", "", "peer node name that you want to connect")
dstIP := flag.String("dstip", "127.0.0.1", "destination ip ") dstIP := fset.String("dstip", "127.0.0.1", "destination ip ")
dstPort := flag.Int("dstport", 0, "destination port ") dstPort := fset.Int("dstport", 0, "destination port ")
srcPort := flag.Int("srcport", 0, "source port ") srcPort := fset.Int("srcport", 0, "source port ")
protocol := flag.String("protocol", "tcp", "tcp or udp") protocol := fset.String("protocol", "tcp", "tcp or udp")
appName := flag.String("appname", "", "app name") appName := fset.String("appname", "", "app name")
shareBandwidth := flag.Int("sharebandwidth", 10, "N mbps share bandwidth limit, private network no limit") shareBandwidth := fset.Int("sharebandwidth", 10, "N mbps share bandwidth limit, private network no limit")
daemonMode := flag.Bool("d", false, "daemonMode") daemonMode := fset.Bool("d", false, "daemonMode")
notVerbose := flag.Bool("nv", false, "not log console") notVerbose := fset.Bool("nv", false, "not log console")
logLevel := flag.Int("loglevel", 1, "0:debug 1:info 2:warn 3:error") newconfig := fset.Bool("newconfig", false, "not load existing config.json")
flag.Parse() logLevel := fset.Int("loglevel", 1, "0:debug 1:info 2:warn 3:error")
if subCommand == "" { // no subcommand
fset.Parse(os.Args[1:])
} else {
fset.Parse(os.Args[2:])
}
config := AppConfig{Enabled: 1} config := AppConfig{Enabled: 1}
config.PeerNode = *peerNode config.PeerNode = *peerNode
@@ -180,14 +194,17 @@ func parseParams() {
config.SrcPort = *srcPort config.SrcPort = *srcPort
config.Protocol = *protocol config.Protocol = *protocol
config.AppName = *appName config.AppName = *appName
gConf.load() if !*newconfig {
gConf.load() // load old config. otherwise will clear all apps
}
gConf.LogLevel = *logLevel
if config.SrcPort != 0 { if config.SrcPort != 0 {
gConf.add(config, true) gConf.add(config, true)
} }
// gConf.mtx.Lock() // when calling this func it's single-thread no lock // gConf.mtx.Lock() // when calling this func it's single-thread no lock
gConf.daemonMode = *daemonMode gConf.daemonMode = *daemonMode
// spec paramters in commandline will always be used // spec paramters in commandline will always be used
flag.Visit(func(f *flag.Flag) { fset.Visit(func(f *flag.Flag) {
if f.Name == "sharebandwidth" { if f.Name == "sharebandwidth" {
gConf.Network.ShareBandwidth = *shareBandwidth gConf.Network.ShareBandwidth = *shareBandwidth
} }
@@ -205,16 +222,20 @@ func parseParams() {
if gConf.Network.ServerHost == "" { if gConf.Network.ServerHost == "" {
gConf.Network.ServerHost = *serverHost gConf.Network.ServerHost = *serverHost
} }
if gConf.Network.Node == "" {
if *node == "" { // config and param's node both empty
hostname := defaultNodeName()
node = &hostname
}
gConf.Network.Node = *node
}
if *token != 0 { if *token != 0 {
gConf.Network.Token = *token gConf.Network.Token = *token
} }
if *node != "" {
if len(*node) < 8 {
gLog.Println(LvERROR, ErrNodeTooShort)
os.Exit(9)
}
gConf.Network.Node = *node
} else {
if gConf.Network.Node == "" { // if node name not set. use os.Hostname
gConf.Network.Node = defaultNodeName()
}
}
if gConf.LogLevel == IntValueNotSet { if gConf.LogLevel == IntValueNotSet {
gConf.LogLevel = *logLevel gConf.LogLevel = *logLevel
} }
+12 -176
View File
@@ -1,13 +1,9 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
"io"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"strings"
"time" "time"
"github.com/kardianos/service" "github.com/kardianos/service"
@@ -19,34 +15,34 @@ type daemon struct {
} }
func (d *daemon) Start(s service.Service) error { func (d *daemon) Start(s service.Service) error {
gLog.Println(LevelINFO, "daemon start") gLog.Println(LvINFO, "daemon start")
return nil return nil
} }
func (d *daemon) Stop(s service.Service) error { func (d *daemon) Stop(s service.Service) error {
gLog.Println(LevelINFO, "service stop") gLog.Println(LvINFO, "service stop")
d.running = false d.running = false
if d.proc != nil { if d.proc != nil {
gLog.Println(LevelINFO, "stop worker") gLog.Println(LvINFO, "stop worker")
d.proc.Kill() d.proc.Kill()
} }
if service.Interactive() { if service.Interactive() {
gLog.Println(LevelINFO, "stop daemon") gLog.Println(LvINFO, "stop daemon")
os.Exit(0) os.Exit(0)
} }
return nil return nil
} }
func (d *daemon) run() { func (d *daemon) run() {
gLog.Println(LevelINFO, "daemon run start") gLog.Println(LvINFO, "daemon run start")
defer gLog.Println(LevelINFO, "daemon run end") defer gLog.Println(LvINFO, "daemon run end")
d.running = true d.running = true
binPath, _ := os.Executable() binPath, _ := os.Executable()
mydir, err := os.Getwd() mydir, err := os.Getwd()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
gLog.Println(LevelINFO, mydir) gLog.Println(LvINFO, mydir)
conf := &service.Config{ conf := &service.Config{
Name: ProducnName, Name: ProducnName,
DisplayName: ProducnName, DisplayName: ProducnName,
@@ -71,14 +67,14 @@ func (d *daemon) run() {
dumpFile := filepath.Join("log", "dump.log") dumpFile := filepath.Join("log", "dump.log")
f, err := os.Create(filepath.Join(tmpDump)) f, err := os.Create(filepath.Join(tmpDump))
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "start worker error:%s", err) gLog.Printf(LvERROR, "start worker error:%s", err)
return return
} }
gLog.Println(LevelINFO, "start worker process, args:", args) gLog.Println(LvINFO, "start worker process, args:", args)
execSpec := &os.ProcAttr{Env: append(os.Environ(), "GOTRACEBACK=crash"), Files: []*os.File{os.Stdin, os.Stdout, f}} execSpec := &os.ProcAttr{Env: append(os.Environ(), "GOTRACEBACK=crash"), Files: []*os.File{os.Stdin, os.Stdout, f}}
p, err := os.StartProcess(binPath, args, execSpec) p, err := os.StartProcess(binPath, args, execSpec)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "start worker error:%s", err) gLog.Printf(LvERROR, "start worker error:%s", err)
return return
} }
d.proc = p d.proc = p
@@ -87,12 +83,12 @@ func (d *daemon) run() {
time.Sleep(time.Second) time.Sleep(time.Second)
err = os.Rename(tmpDump, dumpFile) err = os.Rename(tmpDump, dumpFile)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "rename dump error:%s", err) gLog.Printf(LvERROR, "rename dump error:%s", err)
} }
if !d.running { if !d.running {
return return
} }
gLog.Printf(LevelERROR, "worker stop, restart it after 10s") gLog.Printf(LvERROR, "worker stop, restart it after 10s")
time.Sleep(time.Second * 10) time.Sleep(time.Second * 10)
} }
} }
@@ -117,163 +113,3 @@ func (d *daemon) Control(ctrlComm string, exeAbsPath string, args []string) erro
return nil return nil
} }
// examples:
// listen:
// ./openp2p install -node hhd1207-222 -token YOUR-TOKEN -sharebandwidth 0
// listen and build p2papp:
// ./openp2p install -node hhd1207-222 -token YOUR-TOKEN -sharebandwidth 0 -peernode hhdhome-n1 -dstip 127.0.0.1 -dstport 50022 -protocol tcp -srcport 22
func install() {
gLog.Println(LevelINFO, "openp2p start. version: ", OpenP2PVersion)
gLog.Println(LevelINFO, "Contact: QQ Group: 16947733, Email: [email protected]")
gLog.Println(LevelINFO, "install start")
defer gLog.Println(LevelINFO, "install end")
// auto uninstall
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
}
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
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")
dstIP := installFlag.String("dstip", "127.0.0.1", "destination ip ")
dstPort := installFlag.Int("dstport", 0, "destination port ")
srcPort := installFlag.Int("srcport", 0, "source port ")
protocol := installFlag.String("protocol", "tcp", "tcp or udp")
appName := flag.String("appname", "", "app name")
shareBandwidth := installFlag.Int("sharebandwidth", 10, "N mbps share bandwidth limit, private network no limit")
logLevel := installFlag.Int("loglevel", 1, "0:debug 1:info 2:warn 3:error")
installFlag.Parse(os.Args[2:])
gConf.load() // load old config. otherwise will clear all apps
gConf.LogLevel = *logLevel
gConf.Network.ServerHost = *serverHost
gConf.Network.Token = *token
if *node != "" {
if len(*node) < 8 {
gLog.Println(LevelERROR, ErrNodeTooShort)
os.Exit(9)
}
gConf.Network.Node = *node
} else {
if gConf.Network.Node == "" { // if node name not set. use os.Hostname
gConf.Network.Node = defaultNodeName()
}
}
gConf.Network.ServerPort = 27183
gConf.Network.UDPPort1 = 27182
gConf.Network.UDPPort2 = 27183
gConf.Network.ShareBandwidth = *shareBandwidth
config := AppConfig{Enabled: 1}
config.PeerNode = *peerNode
config.DstHost = *dstIP
config.DstPort = *dstPort
config.SrcPort = *srcPort
config.Protocol = *protocol
config.AppName = *appName
if config.SrcPort != 0 {
gConf.add(config, true)
}
gConf.save()
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
d := daemon{}
// copy files
binPath, _ := os.Executable()
src, errFiles := os.Open(binPath) // can not use args[0], on Windows call openp2p is ok(=openp2p.exe)
if errFiles != nil {
gLog.Printf(LevelERROR, "os.OpenFile %s error:%s", os.Args[0], errFiles)
return
}
dst, errFiles := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0775)
if errFiles != nil {
gLog.Printf(LevelERROR, "os.OpenFile %s error:%s", targetPath, errFiles)
return
}
_, errFiles = io.Copy(dst, src)
if errFiles != nil {
gLog.Printf(LevelERROR, "io.Copy error:%s", errFiles)
return
}
src.Close()
dst.Close()
// install system service
gLog.Println(LevelINFO, "targetPath:", targetPath)
err = d.Control("install", targetPath, []string{"-d"})
if err == nil {
gLog.Println(LevelINFO, "install system service ok.")
}
time.Sleep(time.Second * 2)
err = d.Control("start", targetPath, []string{"-d"})
if err != nil {
gLog.Println(LevelERROR, "start openp2p service error:", err)
} else {
gLog.Println(LevelINFO, "start openp2p service ok.")
}
}
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.Println(LevelINFO, "uninstall start")
defer gLog.Println(LevelINFO, "uninstall end")
d := daemon{}
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 {
gLog.Println(LevelINFO, "uninstall system service ok.")
}
binPath := filepath.Join(defaultInstallPath, defaultBinName)
os.Remove(binPath + "0")
os.Remove(binPath)
// os.RemoveAll(defaultInstallPath) // reserve config.json
}
+19 -2
View File
@@ -1,10 +1,27 @@
module openp2p module openp2p
go 1.16 go 1.18
require ( require (
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/kardianos/service v1.2.0 github.com/kardianos/service v1.2.0
github.com/lucas-clemente/quic-go v0.24.0 github.com/lucas-clemente/quic-go v0.27.0
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34
) )
require (
github.com/cheekybits/genny v1.0.0 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo v1.16.4 // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect
golang.org/x/tools v0.1.1 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
)
+30 -22
View File
@@ -17,37 +17,38 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
if err != nil { if err != nil {
return err return err
} }
gLog.Printf(LevelDEBUG, "handle push msg type:%d, push header:%+v", subType, pushHead) gLog.Printf(LvDEBUG, "handle push msg type:%d, push header:%+v", subType, pushHead)
switch subType { switch subType {
case MsgPushConnectReq: case MsgPushConnectReq:
req := PushConnectReq{} req := PushConnectReq{}
err := json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req) err := json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong MsgPushConnectReq:%s", err) gLog.Printf(LvERROR, "wrong MsgPushConnectReq:%s", err)
return err return err
} }
gLog.Printf(LevelINFO, "%s is connecting...", req.From) gLog.Printf(LvINFO, "%s is connecting...", req.From)
gLog.Println(LevelDEBUG, "push connect response to ", req.From) gLog.Println(LvDEBUG, "push connect response to ", req.From)
// verify totp token or token // 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 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()) || VerifyTOTP(req.Token, pn.config.Token, time.Now().Unix()) ||
(req.FromToken == pn.config.Token) { (req.FromToken == pn.config.Token) {
gLog.Printf(LevelINFO, "Access Granted\n") gLog.Printf(LvINFO, "Access Granted\n")
config := AppConfig{} config := AppConfig{}
config.peerNatType = req.NatType config.peerNatType = req.NatType
config.peerConeNatPort = req.ConeNatPort config.peerConeNatPort = req.ConeNatPort
config.peerIP = req.FromIP config.peerIP = req.FromIP
config.PeerNode = req.From config.PeerNode = req.From
config.peerVersion = req.Version
// share relay node will limit bandwidth // share relay node will limit bandwidth
if req.FromToken != pn.config.Token { if req.FromToken != pn.config.Token {
gLog.Printf(LevelINFO, "set share bandwidth %d mbps", pn.config.ShareBandwidth) gLog.Printf(LvINFO, "set share bandwidth %d mbps", pn.config.ShareBandwidth)
config.shareBandwidth = pn.config.ShareBandwidth config.shareBandwidth = pn.config.ShareBandwidth
} }
// go pn.AddTunnel(config, req.ID) // go pn.AddTunnel(config, req.ID)
go pn.addDirectTunnel(config, req.ID) go pn.addDirectTunnel(config, req.ID)
break break
} }
gLog.Println(LevelERROR, "Access Denied:", req.From) gLog.Println(LvERROR, "Access Denied:", req.From)
rsp := PushConnectRsp{ rsp := PushConnectRsp{
Error: 1, Error: 1,
Detail: fmt.Sprintf("connect to %s error: Access Denied", pn.config.Node), Detail: fmt.Sprintf("connect to %s error: Access Denied", pn.config.Node),
@@ -59,19 +60,19 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
rsp := PushRsp{} rsp := PushRsp{}
err := json.Unmarshal(msg[openP2PHeaderSize:], &rsp) err := json.Unmarshal(msg[openP2PHeaderSize:], &rsp)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong pushRsp:%s", err) gLog.Printf(LvERROR, "wrong pushRsp:%s", err)
return err return err
} }
if rsp.Error == 0 { if rsp.Error == 0 {
gLog.Printf(LevelDEBUG, "push ok, detail:%s", rsp.Detail) gLog.Printf(LvDEBUG, "push ok, detail:%s", rsp.Detail)
} else { } else {
gLog.Printf(LevelERROR, "push error:%d, detail:%s", rsp.Error, rsp.Detail) gLog.Printf(LvERROR, "push error:%d, detail:%s", rsp.Error, rsp.Detail)
} }
case MsgPushAddRelayTunnelReq: case MsgPushAddRelayTunnelReq:
req := AddRelayTunnelReq{} req := AddRelayTunnelReq{}
err := json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req) err := json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong RelayNodeRsp:%s", err) gLog.Printf(LvERROR, "wrong RelayNodeRsp:%s", err)
return err return err
} }
config := AppConfig{} config := AppConfig{}
@@ -83,12 +84,19 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
// notify peer relay ready // notify peer relay ready
msg := TunnelMsg{ID: t.id} msg := TunnelMsg{ID: t.id}
pn.push(r.From, MsgPushAddRelayTunnelRsp, msg) pn.push(r.From, MsgPushAddRelayTunnelRsp, msg)
SaveKey(req.AppID, req.AppKey)
} }
}(req) }(req)
case MsgPushAPPKey:
req := APPKeySync{}
err := json.Unmarshal(msg[openP2PHeaderSize+PushHeaderSize:], &req)
if err != nil {
gLog.Printf(LvERROR, "wrong APPKeySync:%s", err)
return err
}
SaveKey(req.AppID, req.AppKey)
case MsgPushUpdate: case MsgPushUpdate:
gLog.Println(LevelINFO, "MsgPushUpdate") gLog.Println(LvINFO, "MsgPushUpdate")
update() // download new version first, then exec ./openp2p update update() // download new version first, then exec ./openp2p update
targetPath := filepath.Join(defaultInstallPath, defaultBinName) targetPath := filepath.Join(defaultInstallPath, defaultBinName)
args := []string{"update"} args := []string{"update"}
@@ -104,11 +112,11 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
} }
return err return err
case MsgPushRestart: case MsgPushRestart:
gLog.Println(LevelINFO, "MsgPushRestart") gLog.Println(LvINFO, "MsgPushRestart")
os.Exit(0) os.Exit(0)
return err return err
case MsgPushReportApps: case MsgPushReportApps:
gLog.Println(LevelINFO, "MsgPushReportApps") gLog.Println(LvINFO, "MsgPushReportApps")
req := ReportApps{} req := ReportApps{}
gConf.mtx.Lock() gConf.mtx.Lock()
defer gConf.mtx.Unlock() defer gConf.mtx.Unlock()
@@ -147,11 +155,11 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
} }
pn.write(MsgReport, MsgReportApps, &req) pn.write(MsgReport, MsgReportApps, &req)
case MsgPushEditApp: case MsgPushEditApp:
gLog.Println(LevelINFO, "MsgPushEditApp") gLog.Println(LvINFO, "MsgPushEditApp")
newApp := AppInfo{} newApp := AppInfo{}
err := json.Unmarshal(msg[openP2PHeaderSize:], &newApp) err := json.Unmarshal(msg[openP2PHeaderSize:], &newApp)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong MsgPushEditApp:%s %s", err, string(msg[openP2PHeaderSize:])) gLog.Printf(LvERROR, "wrong MsgPushEditApp:%s %s", err, string(msg[openP2PHeaderSize:]))
return err return err
} }
oldConf := AppConfig{Enabled: 1} oldConf := AppConfig{Enabled: 1}
@@ -175,11 +183,11 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
// pn.AddApp(config) // pn.AddApp(config)
// TODO: report result // TODO: report result
case MsgPushEditNode: case MsgPushEditNode:
gLog.Println(LevelINFO, "MsgPushEditNode") gLog.Println(LvINFO, "MsgPushEditNode")
req := EditNode{} req := EditNode{}
err := json.Unmarshal(msg[openP2PHeaderSize:], &req) err := json.Unmarshal(msg[openP2PHeaderSize:], &req)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong MsgPushEditNode:%s %s", err, string(msg[openP2PHeaderSize:])) gLog.Printf(LvERROR, "wrong MsgPushEditNode:%s %s", err, string(msg[openP2PHeaderSize:]))
return err return err
} }
gConf.setNode(req.NewName) gConf.setNode(req.NewName)
@@ -188,15 +196,15 @@ func handlePush(pn *P2PNetwork, subType uint16, msg []byte) error {
// TODO: hot reload // TODO: hot reload
os.Exit(0) os.Exit(0)
case MsgPushSwitchApp: case MsgPushSwitchApp:
gLog.Println(LevelINFO, "MsgPushSwitchApp") gLog.Println(LvINFO, "MsgPushSwitchApp")
app := AppInfo{} app := AppInfo{}
err := json.Unmarshal(msg[openP2PHeaderSize:], &app) err := json.Unmarshal(msg[openP2PHeaderSize:], &app)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong MsgPushSwitchApp:%s %s", err, string(msg[openP2PHeaderSize:])) gLog.Printf(LvERROR, "wrong MsgPushSwitchApp:%s %s", err, string(msg[openP2PHeaderSize:]))
return err return err
} }
config := AppConfig{Enabled: app.Enabled, SrcPort: app.SrcPort, Protocol: app.Protocol} config := AppConfig{Enabled: app.Enabled, SrcPort: app.SrcPort, Protocol: app.Protocol}
gLog.Println(LevelINFO, app.AppName, " switch to ", app.Enabled) gLog.Println(LvINFO, app.AppName, " switch to ", app.Enabled)
gConf.switchApp(config, app.Enabled) gConf.switchApp(config, app.Enabled)
if app.Enabled == 0 { if app.Enabled == 0 {
// disable APP // disable APP
+29 -29
View File
@@ -11,8 +11,8 @@ import (
) )
func handshakeC2C(t *P2PTunnel) (err error) { func handshakeC2C(t *P2PTunnel) (err error) {
gLog.Printf(LevelDEBUG, "handshakeC2C %s:%d:%d to %s:%d", t.pn.config.Node, t.coneLocalPort, t.coneNatPort, t.config.peerIP, t.config.peerConeNatPort) gLog.Printf(LvDEBUG, "handshakeC2C %s:%d:%d to %s:%d", t.pn.config.Node, t.coneLocalPort, t.coneNatPort, t.config.peerIP, t.config.peerConeNatPort)
defer gLog.Printf(LevelDEBUG, "handshakeC2C ok") defer gLog.Printf(LvDEBUG, "handshakeC2C ok")
conn, err := net.ListenUDP("udp", t.la) conn, err := net.ListenUDP("udp", t.la)
if err != nil { if err != nil {
return err return err
@@ -20,40 +20,40 @@ func handshakeC2C(t *P2PTunnel) (err error) {
defer conn.Close() defer conn.Close()
_, err = UDPWrite(conn, t.ra, MsgP2P, MsgPunchHandshake, P2PHandshakeReq{ID: t.id}) _, err = UDPWrite(conn, t.ra, MsgP2P, MsgPunchHandshake, P2PHandshakeReq{ID: t.id})
if err != nil { if err != nil {
gLog.Println(LevelDEBUG, "handshakeC2C write MsgPunchHandshake error:", err) gLog.Println(LvDEBUG, "handshakeC2C write MsgPunchHandshake error:", err)
return err return err
} }
ra, head, _, _, err := UDPRead(conn, 5000) ra, head, _, _, err := UDPRead(conn, 5000)
if err != nil { if err != nil {
time.Sleep(time.Millisecond * 200) time.Sleep(time.Millisecond * 200)
gLog.Println(LevelDEBUG, err, ", return this error when ip was not reachable, retry read") gLog.Println(LvDEBUG, err, ", return this error when ip was not reachable, retry read")
ra, head, _, _, err = UDPRead(conn, 5000) ra, head, _, _, err = UDPRead(conn, 5000)
if err != nil { if err != nil {
gLog.Println(LevelDEBUG, "handshakeC2C read MsgPunchHandshake error:", err) gLog.Println(LvDEBUG, "handshakeC2C read MsgPunchHandshake error:", err)
return err return err
} }
} }
t.ra, _ = net.ResolveUDPAddr("udp", ra.String()) t.ra, _ = net.ResolveUDPAddr("udp", ra.String())
// cone server side // cone server side
if head.MainType == MsgP2P && head.SubType == MsgPunchHandshake { if head.MainType == MsgP2P && head.SubType == MsgPunchHandshake {
gLog.Printf(LevelDEBUG, "read %d handshake ", t.id) gLog.Printf(LvDEBUG, "read %d handshake ", t.id)
UDPWrite(conn, t.ra, MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id}) UDPWrite(conn, t.ra, MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
_, head, _, _, err = UDPRead(conn, 5000) _, head, _, _, err = UDPRead(conn, 5000)
if err != nil { if err != nil {
gLog.Println(LevelDEBUG, "handshakeC2C write MsgPunchHandshakeAck error", err) gLog.Println(LvDEBUG, "handshakeC2C write MsgPunchHandshakeAck error", err)
return err return err
} }
if head.MainType == MsgP2P && head.SubType == MsgPunchHandshakeAck { if head.MainType == MsgP2P && head.SubType == MsgPunchHandshakeAck {
gLog.Printf(LevelDEBUG, "read %d handshake ack ", t.id) gLog.Printf(LvDEBUG, "read %d handshake ack ", t.id)
return nil return nil
} }
} }
// cone client side will only read handshake ack // cone client side will only read handshake ack
if head.MainType == MsgP2P && head.SubType == MsgPunchHandshakeAck { if head.MainType == MsgP2P && head.SubType == MsgPunchHandshakeAck {
gLog.Printf(LevelDEBUG, "read %d handshake ack ", t.id) gLog.Printf(LvDEBUG, "read %d handshake ack ", t.id)
_, err = UDPWrite(conn, t.ra, MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id}) _, err = UDPWrite(conn, t.ra, MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
if err != nil { if err != nil {
gLog.Println(LevelDEBUG, "handshakeC2C write MsgPunchHandshakeAck error", err) gLog.Println(LvDEBUG, "handshakeC2C write MsgPunchHandshakeAck error", err)
} }
return err return err
} }
@@ -61,8 +61,8 @@ func handshakeC2C(t *P2PTunnel) (err error) {
} }
func handshakeC2S(t *P2PTunnel) error { func handshakeC2S(t *P2PTunnel) error {
gLog.Printf(LevelDEBUG, "handshakeC2S start") gLog.Printf(LvDEBUG, "handshakeC2S start")
defer gLog.Printf(LevelDEBUG, "handshakeC2S end") defer gLog.Printf(LvDEBUG, "handshakeC2S end")
// even if read timeout, continue handshake // even if read timeout, continue handshake
t.pn.read(t.config.PeerNode, MsgPush, MsgPushHandshakeStart, SymmetricHandshakeAckTimeout) t.pn.read(t.config.PeerNode, MsgPush, MsgPushHandshakeStart, SymmetricHandshakeAckTimeout)
r := rand.New(rand.NewSource(time.Now().UnixNano())) r := rand.New(rand.NewSource(time.Now().UnixNano()))
@@ -73,7 +73,7 @@ func handshakeC2S(t *P2PTunnel) error {
} }
defer conn.Close() defer conn.Close()
go func() error { go func() error {
gLog.Printf(LevelDEBUG, "send symmetric handshake to %s from %d:%d start", t.config.peerIP, t.coneLocalPort, t.coneNatPort) gLog.Printf(LvDEBUG, "send symmetric handshake to %s from %d:%d start", t.config.peerIP, t.coneLocalPort, t.coneNatPort)
for i := 0; i < SymmetricHandshakeNum; i++ { for i := 0; i < SymmetricHandshakeNum; i++ {
// TODO: auto calc cost time // TODO: auto calc cost time
time.Sleep(SymmetricHandshakeInterval) time.Sleep(SymmetricHandshakeInterval)
@@ -83,35 +83,35 @@ func handshakeC2S(t *P2PTunnel) error {
} }
_, err = UDPWrite(conn, dst, MsgP2P, MsgPunchHandshake, P2PHandshakeReq{ID: t.id}) _, err = UDPWrite(conn, dst, MsgP2P, MsgPunchHandshake, P2PHandshakeReq{ID: t.id})
if err != nil { if err != nil {
gLog.Println(LevelDEBUG, "handshakeC2S write MsgPunchHandshake error:", err) gLog.Println(LvDEBUG, "handshakeC2S write MsgPunchHandshake error:", err)
return err return err
} }
} }
gLog.Println(LevelDEBUG, "send symmetric handshake end") gLog.Println(LvDEBUG, "send symmetric handshake end")
return nil return nil
}() }()
deadline := time.Now().Add(SymmetricHandshakeAckTimeout) deadline := time.Now().Add(SymmetricHandshakeAckTimeout)
err = conn.SetReadDeadline(deadline) err = conn.SetReadDeadline(deadline)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "SymmetricHandshakeAckTimeout SetReadDeadline error") gLog.Println(LvERROR, "SymmetricHandshakeAckTimeout SetReadDeadline error")
return err return err
} }
// read response of the punching hole ok port // read response of the punching hole ok port
result := make([]byte, 1024) result := make([]byte, 1024)
_, dst, err := conn.ReadFrom(result) _, dst, err := conn.ReadFrom(result)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "handshakeC2S wait timeout") gLog.Println(LvERROR, "handshakeC2S wait timeout")
return err return err
} }
head := &openP2PHeader{} head := &openP2PHeader{}
err = binary.Read(bytes.NewReader(result[:openP2PHeaderSize]), binary.LittleEndian, head) err = binary.Read(bytes.NewReader(result[:openP2PHeaderSize]), binary.LittleEndian, head)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "parse p2pheader error:", err) gLog.Println(LvERROR, "parse p2pheader error:", err)
return err return err
} }
t.ra, _ = net.ResolveUDPAddr("udp", dst.String()) t.ra, _ = net.ResolveUDPAddr("udp", dst.String())
if head.MainType == MsgP2P && head.SubType == MsgPunchHandshakeAck { if head.MainType == MsgP2P && head.SubType == MsgPunchHandshakeAck {
gLog.Printf(LevelDEBUG, "handshakeC2S read %d handshake ack %s", t.id, dst.String()) gLog.Printf(LvDEBUG, "handshakeC2S read %d handshake ack %s", t.id, dst.String())
_, err = UDPWrite(conn, dst, MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id}) _, err = UDPWrite(conn, dst, MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
return err return err
} }
@@ -119,11 +119,11 @@ func handshakeC2S(t *P2PTunnel) error {
} }
func handshakeS2C(t *P2PTunnel) error { func handshakeS2C(t *P2PTunnel) error {
gLog.Printf(LevelDEBUG, "handshakeS2C start") gLog.Printf(LvDEBUG, "handshakeS2C start")
defer gLog.Printf(LevelDEBUG, "handshakeS2C end") defer gLog.Printf(LvDEBUG, "handshakeS2C end")
gotCh := make(chan *net.UDPAddr, 5) gotCh := make(chan *net.UDPAddr, 5)
// sequencely udp send handshake, do not parallel send // sequencely udp send handshake, do not parallel send
gLog.Printf(LevelDEBUG, "send symmetric handshake to %s:%d start", t.config.peerIP, t.config.peerConeNatPort) gLog.Printf(LvDEBUG, "send symmetric handshake to %s:%d start", t.config.peerIP, t.config.peerConeNatPort)
gotIt := false gotIt := false
gotMtx := sync.Mutex{} gotMtx := sync.Mutex{}
for i := 0; i < SymmetricHandshakeNum; i++ { for i := 0; i < SymmetricHandshakeNum; i++ {
@@ -132,7 +132,7 @@ func handshakeS2C(t *P2PTunnel) error {
go func(t *P2PTunnel) error { go func(t *P2PTunnel) error {
conn, err := net.ListenUDP("udp", nil) conn, err := net.ListenUDP("udp", nil)
if err != nil { if err != nil {
gLog.Printf(LevelDEBUG, "listen error") gLog.Printf(LvDEBUG, "listen error")
return err return err
} }
defer conn.Close() defer conn.Close()
@@ -150,15 +150,15 @@ func handshakeS2C(t *P2PTunnel) error {
gotIt = true gotIt = true
t.la, _ = net.ResolveUDPAddr("udp", conn.LocalAddr().String()) t.la, _ = net.ResolveUDPAddr("udp", conn.LocalAddr().String())
if head.MainType == MsgP2P && head.SubType == MsgPunchHandshake { if head.MainType == MsgP2P && head.SubType == MsgPunchHandshake {
gLog.Printf(LevelDEBUG, "handshakeS2C read %d handshake ", t.id) gLog.Printf(LvDEBUG, "handshakeS2C read %d handshake ", t.id)
UDPWrite(conn, t.ra, MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id}) UDPWrite(conn, t.ra, MsgP2P, MsgPunchHandshakeAck, P2PHandshakeReq{ID: t.id})
_, head, _, _, err = UDPRead(conn, 5000) _, head, _, _, err = UDPRead(conn, 5000)
if err != nil { if err != nil {
gLog.Println(LevelDEBUG, "handshakeS2C handshake error") gLog.Println(LvDEBUG, "handshakeS2C handshake error")
return err return err
} }
if head.MainType == MsgP2P && head.SubType == MsgPunchHandshakeAck { if head.MainType == MsgP2P && head.SubType == MsgPunchHandshakeAck {
gLog.Printf(LevelDEBUG, "handshakeS2C read %d handshake ack %s", t.id, conn.LocalAddr().String()) gLog.Printf(LvDEBUG, "handshakeS2C read %d handshake ack %s", t.id, conn.LocalAddr().String())
gotCh <- t.la gotCh <- t.la
return nil return nil
} }
@@ -166,15 +166,15 @@ func handshakeS2C(t *P2PTunnel) error {
return nil return nil
}(t) }(t)
} }
gLog.Printf(LevelDEBUG, "send symmetric handshake end") gLog.Printf(LvDEBUG, "send symmetric handshake end")
gLog.Println(LevelDEBUG, "handshakeS2C ready, notify peer connect") gLog.Println(LvDEBUG, "handshakeS2C ready, notify peer connect")
t.pn.push(t.config.PeerNode, MsgPushHandshakeStart, TunnelMsg{ID: t.id}) t.pn.push(t.config.PeerNode, MsgPushHandshakeStart, TunnelMsg{ID: t.id})
select { select {
case <-time.After(SymmetricHandshakeAckTimeout): case <-time.After(SymmetricHandshakeAckTimeout):
return fmt.Errorf("wait handshake failed") return fmt.Errorf("wait handshake failed")
case la := <-gotCh: case la := <-gotCh:
gLog.Println(LevelDEBUG, "symmetric handshake ok", la) gLog.Println(LvDEBUG, "symmetric handshake ok", la)
} }
return nil return nil
} }
+127
View File
@@ -0,0 +1,127 @@
package main
import (
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
// examples:
// listen:
// ./openp2p install -node hhd1207-222 -token YOUR-TOKEN -sharebandwidth 0
// listen and build p2papp:
// ./openp2p install -node hhd1207-222 -token YOUR-TOKEN -sharebandwidth 0 -peernode hhdhome-n1 -dstip 127.0.0.1 -dstport 50022 -protocol tcp -srcport 22
func install() {
gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
gLog.Println(LvINFO, "Contact: QQ Group: 16947733, Email: [email protected]")
gLog.Println(LvINFO, "install start")
defer gLog.Println(LvINFO, "install end")
// auto uninstall
err := os.MkdirAll(defaultInstallPath, 0775)
if err != nil {
gLog.Printf(LvERROR, "MkdirAll %s error:%s", defaultInstallPath, err)
return
}
err = os.Chdir(defaultInstallPath)
if err != nil {
gLog.Println(LvERROR, "cd error:", err)
return
}
uninstall()
// save config file
parseParams("install")
targetPath := filepath.Join(defaultInstallPath, defaultBinName)
d := daemon{}
// copy files
binPath, _ := os.Executable()
src, errFiles := os.Open(binPath) // can not use args[0], on Windows call openp2p is ok(=openp2p.exe)
if errFiles != nil {
gLog.Printf(LvERROR, "os.OpenFile %s error:%s", os.Args[0], errFiles)
return
}
dst, errFiles := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0775)
if errFiles != nil {
gLog.Printf(LvERROR, "os.OpenFile %s error:%s", targetPath, errFiles)
return
}
_, errFiles = io.Copy(dst, src)
if errFiles != nil {
gLog.Printf(LvERROR, "io.Copy error:%s", errFiles)
return
}
src.Close()
dst.Close()
// install system service
gLog.Println(LvINFO, "targetPath:", targetPath)
err = d.Control("install", targetPath, []string{"-d"})
if err == nil {
gLog.Println(LvINFO, "install system service ok.")
}
time.Sleep(time.Second * 2)
err = d.Control("start", targetPath, []string{"-d"})
if err != nil {
gLog.Println(LvERROR, "start openp2p service error:", err)
} else {
gLog.Println(LvINFO, "start openp2p service ok.")
}
}
func installByFilename() {
params := strings.Split(filepath.Base(os.Args[0]), "-")
if len(params) < 4 {
return
}
serverHost := params[1]
token := params[2]
gLog.Println(LvINFO, "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(LvERROR, "install by filename, start process error:", err)
return
}
gLog.Println(LvINFO, "install end")
fmt.Println("Press the Any Key to exit")
fmt.Scanln()
os.Exit(0)
}
func uninstall() {
gLog.Println(LvINFO, "uninstall start")
defer gLog.Println(LvINFO, "uninstall end")
d := daemon{}
err := d.Control("stop", "", nil)
if err != nil { // service maybe not install
return
}
err = d.Control("uninstall", "", nil)
if err != nil {
gLog.Println(LvERROR, "uninstall system service error:", err)
} else {
gLog.Println(LvINFO, "uninstall system service ok.")
}
binPath := filepath.Join(defaultInstallPath, defaultBinName)
os.Remove(binPath + "0")
os.Remove(binPath)
// os.RemoveAll(defaultInstallPath) // reserve config.json
}
+55 -74
View File
@@ -8,17 +8,15 @@ import (
"time" "time"
) )
// LogLevel ...
type LogLevel int type LogLevel int
var gLog *V8log var gLog *logger
// LevelDEBUG ...
const ( const (
LevelDEBUG LogLevel = iota LvDEBUG LogLevel = iota
LevelINFO LvINFO
LevelWARN LvWARN
LevelERROR LvERROR
) )
var ( var (
@@ -30,10 +28,10 @@ func init() {
logFileNames = make(map[LogLevel]string) logFileNames = make(map[LogLevel]string)
loglevel = make(map[LogLevel]string) loglevel = make(map[LogLevel]string)
logFileNames[0] = ".log" logFileNames[0] = ".log"
loglevel[LevelDEBUG] = "DEBUG" loglevel[LvDEBUG] = "DEBUG"
loglevel[LevelINFO] = "INFO" loglevel[LvINFO] = "INFO"
loglevel[LevelWARN] = "WARN" loglevel[LvWARN] = "WARN"
loglevel[LevelERROR] = "ERROR" loglevel[LvERROR] = "ERROR"
} }
@@ -43,25 +41,21 @@ const (
LogFileAndConsole LogFileAndConsole
) )
// V8log ... type logger struct {
type V8log struct {
loggers map[LogLevel]*log.Logger loggers map[LogLevel]*log.Logger
files map[LogLevel]*os.File files map[LogLevel]*os.File
level LogLevel level LogLevel
stopSig chan bool
logDir string logDir string
mtx *sync.Mutex mtx *sync.Mutex
stoped bool
lineEnding string lineEnding string
pid int pid int
maxLogSize int64 maxLogSize int64
mode int mode int
} }
// InitLogger ... func NewLogger(path string, filePrefix string, level LogLevel, maxLogSize int64, mode int) *logger {
func InitLogger(path string, filePrefix string, level LogLevel, maxLogSize int64, mode int) *V8log { loggers := make(map[LogLevel]*log.Logger)
logger := make(map[LogLevel]*log.Logger) logfiles := make(map[LogLevel]*os.File)
openedfile := make(map[LogLevel]*os.File)
var ( var (
logdir string logdir string
) )
@@ -71,15 +65,15 @@ func InitLogger(path string, filePrefix string, level LogLevel, maxLogSize int64
logdir = path + "/log/" logdir = path + "/log/"
} }
os.MkdirAll(logdir, 0777) os.MkdirAll(logdir, 0777)
for l := range logFileNames { for lv := range logFileNames {
logFilePath := logdir + filePrefix + logFileNames[l] logFilePath := logdir + filePrefix + logFileNames[lv]
f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
os.Chmod(logFilePath, 0666) os.Chmod(logFilePath, 0666)
openedfile[l] = f logfiles[lv] = f
logger[l] = log.New(f, "", log.LstdFlags) loggers[lv] = log.New(f, "", log.LstdFlags)
} }
var le string var le string
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
@@ -87,97 +81,84 @@ func InitLogger(path string, filePrefix string, level LogLevel, maxLogSize int64
} else { } else {
le = "\n" le = "\n"
} }
pLog := &V8log{logger, openedfile, level, make(chan bool, 10), logdir, &sync.Mutex{}, false, le, os.Getpid(), maxLogSize, mode} pLog := &logger{loggers, logfiles, level, logdir, &sync.Mutex{}, le, os.Getpid(), maxLogSize, mode}
go pLog.checkFile() go pLog.checkFile()
return pLog return pLog
} }
func (vl *V8log) setLevel(level LogLevel) { func (l *logger) setLevel(level LogLevel) {
vl.mtx.Lock() l.mtx.Lock()
defer vl.mtx.Unlock() defer l.mtx.Unlock()
vl.level = level l.level = level
} }
func (vl *V8log) setMode(mode int) { func (l *logger) setMode(mode int) {
vl.mtx.Lock() l.mtx.Lock()
defer vl.mtx.Unlock() defer l.mtx.Unlock()
vl.mode = mode l.mode = mode
} }
func (vl *V8log) checkFile() { func (l *logger) checkFile() {
if vl.maxLogSize <= 0 { if l.maxLogSize <= 0 {
return return
} }
ticker := time.NewTicker(time.Minute) ticker := time.NewTicker(time.Minute)
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
vl.mtx.Lock() l.mtx.Lock()
for l, logFile := range vl.files { for lv, logFile := range l.files {
f, e := logFile.Stat() f, e := logFile.Stat()
if e != nil { if e != nil {
continue continue
} }
if f.Size() <= vl.maxLogSize { if f.Size() <= l.maxLogSize {
continue continue
} }
logFile.Close() logFile.Close()
fname := f.Name() fname := f.Name()
backupPath := vl.logDir + fname + ".0" backupPath := l.logDir + fname + ".0"
os.Remove(backupPath) os.Remove(backupPath)
os.Rename(vl.logDir+fname, backupPath) os.Rename(l.logDir+fname, backupPath)
newFile, e := os.OpenFile(vl.logDir+fname, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) newFile, e := os.OpenFile(l.logDir+fname, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
if e == nil { if e == nil {
vl.loggers[l].SetOutput(newFile) l.loggers[lv].SetOutput(newFile)
vl.files[l] = newFile l.files[lv] = newFile
} }
} }
vl.mtx.Unlock() l.mtx.Unlock()
case <-vl.stopSig:
}
if vl.stoped {
break
} }
} }
} }
// Printf Warning: report error log depends on this Print format. func (l *logger) Printf(level LogLevel, format string, params ...interface{}) {
func (vl *V8log) Printf(level LogLevel, format string, params ...interface{}) { l.mtx.Lock()
vl.mtx.Lock() defer l.mtx.Unlock()
defer vl.mtx.Unlock() if level < l.level {
if vl.stoped {
return return
} }
if level < vl.level { pidAndLevel := []interface{}{l.pid, loglevel[level]}
return
}
pidAndLevel := []interface{}{vl.pid, loglevel[level]}
params = append(pidAndLevel, params...) params = append(pidAndLevel, params...)
if vl.mode == LogFile || vl.mode == LogFileAndConsole { if l.mode == LogFile || l.mode == LogFileAndConsole {
vl.loggers[0].Printf("%d %s "+format+vl.lineEnding, params...) l.loggers[0].Printf("%d %s "+format+l.lineEnding, params...)
} }
if vl.mode == LogConsole || vl.mode == LogFileAndConsole { if l.mode == LogConsole || l.mode == LogFileAndConsole {
log.Printf("%d %s "+format+vl.lineEnding, params...) log.Printf("%d %s "+format+l.lineEnding, params...)
} }
} }
// Println ... func (l *logger) Println(level LogLevel, params ...interface{}) {
func (vl *V8log) Println(level LogLevel, params ...interface{}) { l.mtx.Lock()
vl.mtx.Lock() defer l.mtx.Unlock()
defer vl.mtx.Unlock() if level < l.level {
if vl.stoped {
return return
} }
if level < vl.level { pidAndLevel := []interface{}{l.pid, " ", loglevel[level], " "}
return
}
pidAndLevel := []interface{}{vl.pid, " ", loglevel[level], " "}
params = append(pidAndLevel, params...) params = append(pidAndLevel, params...)
params = append(params, vl.lineEnding) params = append(params, l.lineEnding)
if vl.mode == LogFile || vl.mode == LogFileAndConsole { if l.mode == LogFile || l.mode == LogFileAndConsole {
vl.loggers[0].Print(params...) l.loggers[0].Print(params...)
} }
if vl.mode == LogConsole || vl.mode == LogFileAndConsole { if l.mode == LogConsole || l.mode == LogFileAndConsole {
log.Print(params...) log.Print(params...)
} }
} }
+52 -27
View File
@@ -3,47 +3,69 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"math/rand" "math/rand"
"net" "net"
"time" "time"
) )
func natTest(serverHost string, serverPort int, localPort int, echoPort int) (publicIP string, isPublicIP int, publicPort int, err error) { func natTest(serverHost string, serverPort int, localPort int, echoPort int) (publicIP string, hasPublicIP int, hasUPNPorNATPMP int, publicPort int, err error) {
conn, err := net.ListenPacket("udp", fmt.Sprintf(":%d", localPort)) conn, err := net.ListenPacket("udp", fmt.Sprintf(":%d", localPort))
if err != nil { if err != nil {
return "", 0, 0, err return "", 0, 0, 0, err
} }
defer conn.Close() defer conn.Close()
dst, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", serverHost, serverPort)) dst, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", serverHost, serverPort))
if err != nil { if err != nil {
return "", 0, 0, err return "", 0, 0, 0, err
} }
// The connection can write data to the desired address. // The connection can write data to the desired address.
msg, err := newMessage(MsgNATDetect, 0, &NatDetectReq{SrcPort: localPort, EchoPort: echoPort}) msg, err := newMessage(MsgNATDetect, 0, &NatDetectReq{SrcPort: localPort, EchoPort: echoPort})
_, err = conn.WriteTo(msg, dst) _, err = conn.WriteTo(msg, dst)
if err != nil { if err != nil {
return "", 0, 0, err return "", 0, 0, 0, err
} }
deadline := time.Now().Add(NatTestTimeout) deadline := time.Now().Add(NatTestTimeout)
err = conn.SetReadDeadline(deadline) err = conn.SetReadDeadline(deadline)
if err != nil { if err != nil {
return "", 0, 0, err return "", 0, 0, 0, err
} }
buffer := make([]byte, 1024) buffer := make([]byte, 1024)
nRead, _, err := conn.ReadFrom(buffer) nRead, _, err := conn.ReadFrom(buffer)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "NAT detect error:", err) gLog.Println(LvERROR, "NAT detect error:", err)
return "", 0, 0, err return "", 0, 0, 0, err
} }
natRsp := NatDetectRsp{} natRsp := NatDetectRsp{}
err = json.Unmarshal(buffer[openP2PHeaderSize:nRead], &natRsp) err = json.Unmarshal(buffer[openP2PHeaderSize:nRead], &natRsp)
hasPublicIP = 0
hasUPNPorNATPMP = 0
// testing for public ip // testing for public ip
if echoPort != 0 { if echoPort != 0 {
for { for i := 0; i < 2; i++ {
gLog.Printf(LevelDEBUG, "public ip test start %s:%d", natRsp.IP, echoPort) if i == 1 {
// test upnp or nat-pmp
nat, err := Discover()
if err != nil {
gLog.Println(LvDEBUG, "could not perform UPNP discover:", err)
break
}
ext, err := nat.GetExternalAddress()
if err != nil {
gLog.Println(LvDEBUG, "could not perform UPNP external address:", err)
break
}
log.Println("PublicIP:", ext)
externalPort, err := nat.AddPortMapping("udp", echoPort, echoPort, "openp2p", 60)
if err != nil {
gLog.Println(LvDEBUG, "could not add udp UPNP port mapping", externalPort)
break
}
}
gLog.Printf(LvDEBUG, "public ip test start %s:%d", natRsp.IP, echoPort)
conn, err := net.ListenUDP("udp", nil) conn, err := net.ListenUDP("udp", nil)
if err != nil { if err != nil {
break break
@@ -60,56 +82,59 @@ func natTest(serverHost string, serverPort int, localPort int, echoPort int) (pu
conn.SetReadDeadline(time.Now().Add(PublicIPEchoTimeout)) conn.SetReadDeadline(time.Now().Add(PublicIPEchoTimeout))
_, _, err = conn.ReadFromUDP(buf) _, _, err = conn.ReadFromUDP(buf)
if err == nil { if err == nil {
gLog.Println(LevelDEBUG, "public ip:YES") if i == 1 {
natRsp.IsPublicIP = 1 gLog.Println(LvDEBUG, "UPNP or NAT-PMP:YES")
hasUPNPorNATPMP = 1
} else { } else {
gLog.Println(LevelDEBUG, "public ip:NO") gLog.Println(LvDEBUG, "public ip:YES")
hasPublicIP = 1
} }
break break
} }
} }
return natRsp.IP, natRsp.IsPublicIP, natRsp.Port, nil }
return natRsp.IP, hasPublicIP, hasUPNPorNATPMP, natRsp.Port, nil
} }
func getNATType(host string, udp1 int, udp2 int) (publicIP string, NATType int, err error) { func getNATType(host string, udp1 int, udp2 int) (publicIP string, NATType int, hasUPNPorNATPMP int, err error) {
// the random local port may be used by other. // the random local port may be used by other.
localPort := int(rand.Uint32()%10000 + 50000) localPort := int(rand.Uint32()%10000 + 50000)
echoPort := int(rand.Uint32()%10000 + 50000) echoPort := int(rand.Uint32()%10000 + 50000)
go echo(echoPort) go echo(echoPort)
ip1, isPublicIP, port1, err := natTest(host, udp1, localPort, echoPort) ip1, hasPublicIP, hasUPNPorNATPMP, port1, err := natTest(host, udp1, localPort, echoPort)
gLog.Printf(LevelDEBUG, "local port:%d nat port:%d", localPort, port1) gLog.Printf(LvDEBUG, "local port:%d nat port:%d", localPort, port1)
if err != nil { if err != nil {
return "", 0, err return "", 0, hasUPNPorNATPMP, err
} }
if isPublicIP == 1 { if hasPublicIP == 1 || hasUPNPorNATPMP == 1 {
return ip1, NATNone, nil return ip1, NATNone, hasUPNPorNATPMP, nil
} }
ip2, _, port2, err := natTest(host, udp2, localPort, 0) // 2rd nat test not need testing publicip ip2, _, _, port2, err := natTest(host, udp2, localPort, 0) // 2rd nat test not need testing publicip
gLog.Printf(LevelDEBUG, "local port:%d nat port:%d", localPort, port2) gLog.Printf(LvDEBUG, "local port:%d nat port:%d", localPort, port2)
if err != nil { if err != nil {
return "", 0, err return "", 0, hasUPNPorNATPMP, err
} }
if ip1 != ip2 { if ip1 != ip2 {
return "", 0, fmt.Errorf("ip have changed, please retry again") return "", 0, hasUPNPorNATPMP, fmt.Errorf("ip have changed, please retry again")
} }
natType := NATSymmetric natType := NATSymmetric
if port1 == port2 { if port1 == port2 {
natType = NATCone natType = NATCone
} }
//TODO: NATNone //TODO: NATNone
return ip1, natType, nil return ip1, natType, hasUPNPorNATPMP, nil
} }
func echo(echoPort int) { func echo(echoPort int) {
conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: echoPort}) conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: echoPort})
if err != nil { if err != nil {
gLog.Println(LevelERROR, "echo server listen error:", err) gLog.Println(LvERROR, "echo server listen error:", err)
return return
} }
buf := make([]byte, 1600) buf := make([]byte, 1600)
defer conn.Close() defer conn.Close()
// wait 5s for echo testing // wait 5s for echo testing
conn.SetReadDeadline(time.Now().Add(time.Second * 5)) conn.SetReadDeadline(time.Now().Add(time.Second * 30))
n, addr, err := conn.ReadFromUDP(buf) n, addr, err := conn.ReadFromUDP(buf)
if err != nil { if err != nil {
return return
+10 -10
View File
@@ -12,7 +12,7 @@ func main() {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
binDir := filepath.Dir(os.Args[0]) binDir := filepath.Dir(os.Args[0])
os.Chdir(binDir) // for system service os.Chdir(binDir) // for system service
gLog = InitLogger(binDir, "openp2p", LevelDEBUG, 1024*1024, LogFileAndConsole) gLog = NewLogger(binDir, "openp2p", LvDEBUG, 1024*1024, LogFileAndConsole)
// TODO: install sub command, deamon process // TODO: install sub command, deamon process
if len(os.Args) > 1 { if len(os.Args) > 1 {
switch os.Args[1] { switch os.Args[1] {
@@ -20,14 +20,14 @@ func main() {
fmt.Println(OpenP2PVersion) fmt.Println(OpenP2PVersion)
return return
case "update": case "update":
gLog = InitLogger(filepath.Dir(os.Args[0]), "openp2p", LevelDEBUG, 1024*1024, LogFileAndConsole) gLog = NewLogger(filepath.Dir(os.Args[0]), "openp2p", LvDEBUG, 1024*1024, LogFileAndConsole)
targetPath := filepath.Join(defaultInstallPath, defaultBinName) targetPath := filepath.Join(defaultInstallPath, defaultBinName)
d := daemon{} d := daemon{}
err := d.Control("restart", targetPath, nil) err := d.Control("restart", targetPath, nil)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "restart service error:", err) gLog.Println(LvERROR, "restart service error:", err)
} else { } else {
gLog.Println(LevelINFO, "restart service ok.") gLog.Println(LvINFO, "restart service ok.")
} }
return return
case "install": case "install":
@@ -40,9 +40,9 @@ func main() {
} else { } else {
installByFilename() installByFilename()
} }
parseParams() parseParams("")
gLog.Println(LevelINFO, "openp2p start. version: ", OpenP2PVersion) gLog.Println(LvINFO, "openp2p start. version: ", OpenP2PVersion)
gLog.Println(LevelINFO, "Contact: QQ Group: 16947733, Email: [email protected]") gLog.Println(LvINFO, "Contact: QQ Group: 16947733, Email: [email protected]")
if gConf.daemonMode { if gConf.daemonMode {
d := daemon{} d := daemon{}
@@ -50,14 +50,14 @@ func main() {
return return
} }
gLog.Println(LevelINFO, &gConf) gLog.Println(LvINFO, &gConf)
setFirewall() setFirewall()
network := P2PNetworkInstance(&gConf.Network) network := P2PNetworkInstance(&gConf.Network)
if ok := network.Connect(30000); !ok { if ok := network.Connect(30000); !ok {
gLog.Println(LevelERROR, "P2PNetwork login error") gLog.Println(LvERROR, "P2PNetwork login error")
return return
} }
gLog.Println(LevelINFO, "waiting for connection...") gLog.Println(LvINFO, "waiting for connection...")
forever := make(chan bool) forever := make(chan bool)
<-forever <-forever
} }
+5 -5
View File
@@ -40,8 +40,8 @@ type overlayConn struct {
} }
func (oConn *overlayConn) run() { func (oConn *overlayConn) run() {
gLog.Printf(LevelDEBUG, "%d overlayConn run start", oConn.id) gLog.Printf(LvDEBUG, "%d overlayConn run start", oConn.id)
defer gLog.Printf(LevelDEBUG, "%d overlayConn run end", oConn.id) defer gLog.Printf(LvDEBUG, "%d overlayConn run end", oConn.id)
oConn.running = true oConn.running = true
oConn.lastReadUDPTs = time.Now() oConn.lastReadUDPTs = time.Now()
buffer := make([]byte, ReadBuffLen+PaddingSize) buffer := make([]byte, ReadBuffLen+PaddingSize)
@@ -58,7 +58,7 @@ func (oConn *overlayConn) run() {
continue continue
} }
// overlay tcp connection normal close, debug log // overlay tcp connection normal close, debug log
gLog.Printf(LevelDEBUG, "overlayConn %d read error:%s,close it", oConn.id, err) gLog.Printf(LvDEBUG, "overlayConn %d read error:%s,close it", oConn.id, err)
break break
} }
payload := buff[:dataLen] payload := buff[:dataLen]
@@ -68,13 +68,13 @@ func (oConn *overlayConn) run() {
writeBytes := append(tunnelHead.Bytes(), payload...) writeBytes := append(tunnelHead.Bytes(), payload...)
if oConn.rtid == 0 { if oConn.rtid == 0 {
oConn.tunnel.conn.WriteBytes(MsgP2P, MsgOverlayData, writeBytes) oConn.tunnel.conn.WriteBytes(MsgP2P, MsgOverlayData, writeBytes)
gLog.Printf(LevelDEBUG, "write overlay data to %d:%d bodylen=%d", oConn.rtid, oConn.id, len(writeBytes)) gLog.Printf(LvDEBUG, "write overlay data to %d:%d bodylen=%d", oConn.rtid, oConn.id, len(writeBytes))
} else { } else {
// write raley data // write raley data
all := append(relayHead.Bytes(), encodeHeader(MsgP2P, MsgOverlayData, uint32(len(writeBytes)))...) all := append(relayHead.Bytes(), encodeHeader(MsgP2P, MsgOverlayData, uint32(len(writeBytes)))...)
all = append(all, writeBytes...) all = append(all, writeBytes...)
oConn.tunnel.conn.WriteBytes(MsgP2P, MsgRelayData, all) oConn.tunnel.conn.WriteBytes(MsgP2P, MsgRelayData, all)
gLog.Printf(LevelDEBUG, "write relay data to %d:%d bodylen=%d", oConn.rtid, oConn.id, len(writeBytes)) gLog.Printf(LvDEBUG, "write relay data to %d:%d bodylen=%d", oConn.rtid, oConn.id, len(writeBytes))
} }
} }
if oConn.connTCP != nil { if oConn.connTCP != nil {
+15 -15
View File
@@ -17,7 +17,7 @@ type p2pApp struct {
listener net.Listener listener net.Listener
listenerUDP *net.UDPConn listenerUDP *net.UDPConn
tunnel *P2PTunnel tunnel *P2PTunnel
rtid uint64 rtid uint64 // relay tunnelID
relayNode string relayNode string
relayMode string relayMode string
hbTime time.Time hbTime time.Time
@@ -48,19 +48,19 @@ func (app *p2pApp) updateHeartbeat() {
} }
func (app *p2pApp) listenTCP() error { func (app *p2pApp) listenTCP() error {
gLog.Printf(LevelDEBUG, "tcp accept on port %d start", app.config.SrcPort) gLog.Printf(LvDEBUG, "tcp accept on port %d start", app.config.SrcPort)
defer gLog.Printf(LevelDEBUG, "tcp accept on port %d end", app.config.SrcPort) defer gLog.Printf(LvDEBUG, "tcp accept on port %d end", app.config.SrcPort)
var err error var err error
app.listener, err = net.Listen("tcp4", fmt.Sprintf("0.0.0.0:%d", app.config.SrcPort)) app.listener, err = net.Listen("tcp4", fmt.Sprintf("0.0.0.0:%d", app.config.SrcPort))
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "listen error:%s", err) gLog.Printf(LvERROR, "listen error:%s", err)
return err return err
} }
for app.running { for app.running {
conn, err := app.listener.Accept() conn, err := app.listener.Accept()
if err != nil { if err != nil {
if app.running { if app.running {
gLog.Printf(LevelERROR, "%d accept error:%s", app.tunnel.id, err) gLog.Printf(LvERROR, "%d accept error:%s", app.id, err)
} }
break break
} }
@@ -81,7 +81,7 @@ func (app *p2pApp) listenTCP() error {
oConn.appKeyBytes = encryptKey oConn.appKeyBytes = encryptKey
} }
app.tunnel.overlayConns.Store(oConn.id, &oConn) app.tunnel.overlayConns.Store(oConn.id, &oConn)
gLog.Printf(LevelDEBUG, "Accept TCP overlayID:%d", oConn.id) gLog.Printf(LvDEBUG, "Accept TCP overlayID:%d", oConn.id)
// tell peer connect // tell peer connect
req := OverlayConnectReq{ID: oConn.id, req := OverlayConnectReq{ID: oConn.id,
Token: app.tunnel.pn.config.Token, Token: app.tunnel.pn.config.Token,
@@ -106,12 +106,12 @@ func (app *p2pApp) listenTCP() error {
} }
func (app *p2pApp) listenUDP() error { func (app *p2pApp) listenUDP() error {
gLog.Printf(LevelDEBUG, "udp accept on port %d start", app.config.SrcPort) gLog.Printf(LvDEBUG, "udp accept on port %d start", app.config.SrcPort)
defer gLog.Printf(LevelDEBUG, "udp accept on port %d end", app.config.SrcPort) defer gLog.Printf(LvDEBUG, "udp accept on port %d end", app.config.SrcPort)
var err error var err error
app.listenerUDP, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: app.config.SrcPort}) app.listenerUDP, err = net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: app.config.SrcPort})
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "listen error:%s", err) gLog.Printf(LvERROR, "listen error:%s", err)
return err return err
} }
buffer := make([]byte, 64*1024) buffer := make([]byte, 64*1024)
@@ -123,7 +123,7 @@ func (app *p2pApp) listenUDP() error {
if ne, ok := err.(net.Error); ok && ne.Timeout() { if ne, ok := err.(net.Error); ok && ne.Timeout() {
continue continue
} else { } else {
gLog.Printf(LevelERROR, "udp read failed:%s", err) gLog.Printf(LvERROR, "udp read failed:%s", err)
break break
} }
} else { } else {
@@ -161,7 +161,7 @@ func (app *p2pApp) listenUDP() error {
oConn.appKeyBytes = encryptKey oConn.appKeyBytes = encryptKey
} }
app.tunnel.overlayConns.Store(oConn.id, &oConn) app.tunnel.overlayConns.Store(oConn.id, &oConn)
gLog.Printf(LevelDEBUG, "Accept UDP overlayID:%d", oConn.id) gLog.Printf(LvDEBUG, "Accept UDP overlayID:%d", oConn.id)
// tell peer connect // tell peer connect
req := OverlayConnectReq{ID: oConn.id, req := OverlayConnectReq{ID: oConn.id,
Token: app.tunnel.pn.config.Token, Token: app.tunnel.pn.config.Token,
@@ -196,8 +196,8 @@ func (app *p2pApp) listenUDP() error {
} }
func (app *p2pApp) listen() error { func (app *p2pApp) listen() error {
gLog.Printf(LevelINFO, "LISTEN ON PORT %s:%d START", app.config.Protocol, app.config.SrcPort) gLog.Printf(LvINFO, "LISTEN ON PORT %s:%d START", app.config.Protocol, app.config.SrcPort)
defer gLog.Printf(LevelINFO, "LISTEN ON PORT %s:%d END", app.config.Protocol, app.config.SrcPort) defer gLog.Printf(LvINFO, "LISTEN ON PORT %s:%d END", app.config.Protocol, app.config.SrcPort)
app.wg.Add(1) app.wg.Add(1)
defer app.wg.Done() defer app.wg.Done()
app.running = true app.running = true
@@ -233,8 +233,8 @@ func (app *p2pApp) close() {
func (app *p2pApp) relayHeartbeatLoop() { func (app *p2pApp) relayHeartbeatLoop() {
app.wg.Add(1) app.wg.Add(1)
defer app.wg.Done() defer app.wg.Done()
gLog.Printf(LevelDEBUG, "relayHeartbeat to %d start", app.rtid) gLog.Printf(LvDEBUG, "relayHeartbeat to %d start", app.rtid)
defer gLog.Printf(LevelDEBUG, "relayHeartbeat to %d end", app.rtid) defer gLog.Printf(LvDEBUG, "relayHeartbeat to %d end", app.rtid)
relayHead := new(bytes.Buffer) relayHead := new(bytes.Buffer)
binary.Write(relayHead, binary.LittleEndian, app.rtid) binary.Write(relayHead, binary.LittleEndian, app.rtid)
req := RelayHeartbeat{RelayTunnelID: app.tunnel.id, req := RelayHeartbeat{RelayTunnelID: app.tunnel.id,
+66 -65
View File
@@ -9,7 +9,6 @@ import (
"fmt" "fmt"
"math" "math"
"math/rand" "math/rand"
"net"
"net/url" "net/url"
"strings" "strings"
"sync" "sync"
@@ -76,7 +75,7 @@ func (pn *P2PNetwork) run() {
time.Sleep(NetworkHeartbeatTime) time.Sleep(NetworkHeartbeatTime)
err := pn.init() err := pn.init()
if err != nil { if err != nil {
gLog.Println(LevelERROR, "P2PNetwork init error:", err) gLog.Println(LvERROR, "P2PNetwork init error:", err)
} }
} }
} }
@@ -123,7 +122,7 @@ func (pn *P2PNetwork) runAll() {
pn.DeleteApp(*config) pn.DeleteApp(*config)
} }
if config.retryNum > 0 { if config.retryNum > 0 {
gLog.Printf(LevelINFO, "detect app %s(%d) disconnect, reconnecting the %d times...", config.AppName, appID, config.retryNum) gLog.Printf(LvINFO, "detect app %s(%d) disconnect, reconnecting the %d times...", config.AppName, appID, config.retryNum)
if time.Now().Add(-time.Minute * 15).After(config.retryTime) { // normal lasts 15min if time.Now().Add(-time.Minute * 15).After(config.retryTime) { // normal lasts 15min
config.retryNum = 0 config.retryNum = 0
} }
@@ -145,7 +144,7 @@ func (pn *P2PNetwork) runAll() {
} }
} }
func (pn *P2PNetwork) autorunApp() { func (pn *P2PNetwork) autorunApp() {
gLog.Println(LevelINFO, "autorunApp start") gLog.Println(LvINFO, "autorunApp start")
for pn.running { for pn.running {
time.Sleep(time.Second) time.Sleep(time.Second)
if !pn.online { if !pn.online {
@@ -154,12 +153,12 @@ func (pn *P2PNetwork) autorunApp() {
pn.runAll() pn.runAll()
time.Sleep(time.Second * 10) time.Sleep(time.Second * 10)
} }
gLog.Println(LevelINFO, "autorunApp end") gLog.Println(LvINFO, "autorunApp end")
} }
func (pn *P2PNetwork) addRelayTunnel(config AppConfig, appid uint64, appkey uint64) (*P2PTunnel, uint64, string, error) { func (pn *P2PNetwork) addRelayTunnel(config AppConfig) (*P2PTunnel, uint64, string, error) {
gLog.Printf(LevelINFO, "addRelayTunnel to %s start", config.PeerNode) gLog.Printf(LvINFO, "addRelayTunnel to %s start", config.PeerNode)
defer gLog.Printf(LevelINFO, "addRelayTunnel to %s end", config.PeerNode) defer gLog.Printf(LvINFO, "addRelayTunnel to %s end", config.PeerNode)
pn.write(MsgRelay, MsgRelayNodeReq, &RelayNodeReq{config.PeerNode}) pn.write(MsgRelay, MsgRelayNodeReq, &RelayNodeReq{config.PeerNode})
head, body := pn.read("", MsgRelay, MsgRelayNodeRsp, time.Second*10) head, body := pn.read("", MsgRelay, MsgRelayNodeRsp, time.Second*10)
if head == nil { if head == nil {
@@ -168,20 +167,20 @@ func (pn *P2PNetwork) addRelayTunnel(config AppConfig, appid uint64, appkey uint
rsp := RelayNodeRsp{} rsp := RelayNodeRsp{}
err := json.Unmarshal(body, &rsp) err := json.Unmarshal(body, &rsp)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong RelayNodeRsp:%s", err) gLog.Printf(LvERROR, "wrong RelayNodeRsp:%s", err)
return nil, 0, "", errors.New("unmarshal MsgRelayNodeRsp error") return nil, 0, "", errors.New("unmarshal MsgRelayNodeRsp error")
} }
if rsp.RelayName == "" || rsp.RelayToken == 0 { if rsp.RelayName == "" || rsp.RelayToken == 0 {
gLog.Printf(LevelERROR, "MsgRelayNodeReq error") gLog.Printf(LvERROR, "MsgRelayNodeReq error")
return nil, 0, "", errors.New("MsgRelayNodeReq error") return nil, 0, "", errors.New("MsgRelayNodeReq error")
} }
gLog.Printf(LevelINFO, "got relay node:%s", rsp.RelayName) gLog.Printf(LvINFO, "got relay node:%s", rsp.RelayName)
relayConfig := config relayConfig := config
relayConfig.PeerNode = rsp.RelayName relayConfig.PeerNode = rsp.RelayName
relayConfig.peerToken = rsp.RelayToken relayConfig.peerToken = rsp.RelayToken
t, err := pn.addDirectTunnel(relayConfig, 0) t, err := pn.addDirectTunnel(relayConfig, 0)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "direct connect error:", err) gLog.Println(LvERROR, "direct connect error:", err)
return nil, 0, "", err return nil, 0, "", err
} }
// notify peer addRelayTunnel // notify peer addRelayTunnel
@@ -189,22 +188,20 @@ func (pn *P2PNetwork) addRelayTunnel(config AppConfig, appid uint64, appkey uint
From: pn.config.Node, From: pn.config.Node,
RelayName: rsp.RelayName, RelayName: rsp.RelayName,
RelayToken: rsp.RelayToken, RelayToken: rsp.RelayToken,
AppID: appid,
AppKey: appkey,
} }
gLog.Printf(LevelINFO, "push relay %s---------%s", config.PeerNode, rsp.RelayName) gLog.Printf(LvINFO, "push relay %s---------%s", config.PeerNode, rsp.RelayName)
pn.push(config.PeerNode, MsgPushAddRelayTunnelReq, &req) pn.push(config.PeerNode, MsgPushAddRelayTunnelReq, &req)
// wait relay ready // wait relay ready
head, body = pn.read(config.PeerNode, MsgPush, MsgPushAddRelayTunnelRsp, PeerAddRelayTimeount) // TODO: const value head, body = pn.read(config.PeerNode, MsgPush, MsgPushAddRelayTunnelRsp, PeerAddRelayTimeount) // TODO: const value
if head == nil { if head == nil {
gLog.Printf(LevelERROR, "read MsgPushAddRelayTunnelRsp error") gLog.Printf(LvERROR, "read MsgPushAddRelayTunnelRsp error")
return nil, 0, "", errors.New("read MsgPushAddRelayTunnelRsp error") return nil, 0, "", errors.New("read MsgPushAddRelayTunnelRsp error")
} }
rspID := TunnelMsg{} rspID := TunnelMsg{}
err = json.Unmarshal(body, &rspID) err = json.Unmarshal(body, &rspID)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong RelayNodeRsp:%s", err) gLog.Printf(LvERROR, "wrong RelayNodeRsp:%s", err)
return nil, 0, "", errors.New("unmarshal MsgRelayNodeRsp error") return nil, 0, "", errors.New("unmarshal MsgRelayNodeRsp error")
} }
return t, rspID.ID, rsp.Mode, err return t, rspID.ID, rsp.Mode, err
@@ -212,8 +209,8 @@ func (pn *P2PNetwork) addRelayTunnel(config AppConfig, appid uint64, appkey uint
// use *AppConfig to save status // use *AppConfig to save status
func (pn *P2PNetwork) AddApp(config AppConfig) error { func (pn *P2PNetwork) AddApp(config AppConfig) error {
gLog.Printf(LevelINFO, "addApp %s to %s:%s:%d start", config.AppName, config.PeerNode, config.DstHost, config.DstPort) gLog.Printf(LvINFO, "addApp %s to %s:%s:%d start", config.AppName, config.PeerNode, config.DstHost, config.DstPort)
defer gLog.Printf(LevelINFO, "addApp %s to %s:%s:%d end", config.AppName, config.PeerNode, config.DstHost, config.DstPort) defer gLog.Printf(LvINFO, "addApp %s to %s:%s:%d end", config.AppName, config.PeerNode, config.DstHost, config.DstPort)
if !pn.online { if !pn.online {
return errors.New("P2PNetwork offline") return errors.New("P2PNetwork offline")
} }
@@ -240,9 +237,8 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error {
peerIP = t.config.peerIP peerIP = t.config.peerIP
} }
if err != nil && err == ErrorHandshake { if err != nil && err == ErrorHandshake {
gLog.Println(LevelERROR, "direct connect failed, try to relay") gLog.Println(LvERROR, "direct connect failed, try to relay")
appKey = rand.Uint64() t, rtid, relayMode, err = pn.addRelayTunnel(config)
t, rtid, relayMode, err = pn.addRelayTunnel(config, appID, appKey)
if t != nil { if t != nil {
relayNode = t.config.PeerNode relayNode = t.config.PeerNode
} }
@@ -269,6 +265,16 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error {
if err != nil { if err != nil {
return err return err
} }
if rtid != 0 || t.conn.Protocol() == "tcp" {
// sync appkey
appKey = rand.Uint64()
req := APPKeySync{
AppID: appID,
AppKey: appKey,
}
gLog.Printf(LvINFO, "sync appkey to %s", config.PeerNode)
pn.push(config.PeerNode, MsgPushAPPKey, &req)
}
app := p2pApp{ app := p2pApp{
id: appID, id: appID,
key: appKey, key: appKey,
@@ -286,21 +292,21 @@ func (pn *P2PNetwork) AddApp(config AppConfig) error {
} }
func (pn *P2PNetwork) DeleteApp(config AppConfig) { func (pn *P2PNetwork) DeleteApp(config AppConfig) {
gLog.Printf(LevelINFO, "DeleteApp %s%d start", config.Protocol, config.SrcPort) gLog.Printf(LvINFO, "DeleteApp %s%d start", config.Protocol, config.SrcPort)
defer gLog.Printf(LevelINFO, "DeleteApp %s%d end", config.Protocol, config.SrcPort) defer gLog.Printf(LvINFO, "DeleteApp %s%d end", config.Protocol, config.SrcPort)
// close the apps of this config // close the apps of this config
i, ok := pn.apps.Load(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort)) i, ok := pn.apps.Load(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort))
if ok { if ok {
app := i.(*p2pApp) app := i.(*p2pApp)
gLog.Printf(LevelINFO, "app %s exist, delete it", fmt.Sprintf("%s%d", config.Protocol, config.SrcPort)) gLog.Printf(LvINFO, "app %s exist, delete it", fmt.Sprintf("%s%d", config.Protocol, config.SrcPort))
app.close() app.close()
pn.apps.Delete(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort)) pn.apps.Delete(fmt.Sprintf("%s%d", config.Protocol, config.SrcPort))
} }
} }
func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (*P2PTunnel, error) { func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (*P2PTunnel, error) {
gLog.Printf(LevelDEBUG, "addDirectTunnel %s%d to %s:%s:%d start", config.Protocol, config.SrcPort, config.PeerNode, config.DstHost, config.DstPort) gLog.Printf(LvDEBUG, "addDirectTunnel %s%d to %s:%s:%d start", config.Protocol, config.SrcPort, config.PeerNode, config.DstHost, config.DstPort)
defer gLog.Printf(LevelDEBUG, "addDirectTunnel %s%d to %s:%s:%d end", config.Protocol, config.SrcPort, config.PeerNode, config.DstHost, config.DstPort) defer gLog.Printf(LvDEBUG, "addDirectTunnel %s%d to %s:%s:%d end", config.Protocol, config.SrcPort, config.PeerNode, config.DstHost, config.DstPort)
isClient := false isClient := false
// client side tid=0, assign random uint64 // client side tid=0, assign random uint64
if tid == 0 { if tid == 0 {
@@ -320,11 +326,11 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (*P2PTunnel,
} }
// client side checking // client side checking
gLog.Println(LevelINFO, "tunnel already exist ", config.PeerNode) gLog.Println(LvINFO, "tunnel already exist ", config.PeerNode)
isActive := t.checkActive() isActive := t.checkActive()
// inactive, close it // inactive, close it
if !isActive { if !isActive {
gLog.Println(LevelINFO, "but it's not active, close it ", config.PeerNode) gLog.Println(LvINFO, "but it's not active, close it ", config.PeerNode)
t.close() t.close()
} else { } else {
// active // active
@@ -346,47 +352,40 @@ func (pn *P2PNetwork) addDirectTunnel(config AppConfig, tid uint64) (*P2PTunnel,
t.init() t.init()
if isClient { if isClient {
if err := t.connect(); err != nil { if err := t.connect(); err != nil {
gLog.Println(LevelERROR, "p2pTunnel connect error:", err) gLog.Println(LvERROR, "p2pTunnel connect error:", err)
return t, err return t, err
} }
} else { } else {
rsp := PushConnectRsp{
Error: 0,
Detail: "connect ok",
To: t.config.PeerNode,
From: pn.config.Node,
NatType: pn.config.natType,
FromIP: pn.config.publicIP,
ConeNatPort: t.coneNatPort,
ID: t.id}
t.pn.push(t.config.PeerNode, MsgPushConnectRsp, rsp)
if err := t.listen(); err != nil { if err := t.listen(); err != nil {
gLog.Println(LevelERROR, "p2pTunnel listen error:", err) gLog.Println(LvERROR, "p2pTunnel listen error:", err)
return t, err return t, err
} }
} }
} }
// store it when success // store it when success
gLog.Printf(LevelDEBUG, "store tunnel %d", tid) gLog.Printf(LvDEBUG, "store tunnel %d", tid)
pn.allTunnels.Store(tid, t) pn.allTunnels.Store(tid, t)
return t, nil return t, nil
} }
func (pn *P2PNetwork) init() error { func (pn *P2PNetwork) init() error {
gLog.Println(LevelINFO, "init start") gLog.Println(LvINFO, "init start")
var err error var err error
for { for {
// detect nat type // detect nat type
pn.config.publicIP, pn.config.natType, err = getNATType(pn.config.ServerHost, pn.config.UDPPort1, pn.config.UDPPort2) pn.config.publicIP, pn.config.natType, pn.config.hasUPNPorNATPMP, err = getNATType(pn.config.ServerHost, pn.config.UDPPort1, pn.config.UDPPort2)
// TODO rm test s2s // for testcase
if strings.Contains(pn.config.Node, "openp2pS2STest") { if strings.Contains(pn.config.Node, "openp2pS2STest") {
pn.config.natType = NATSymmetric pn.config.natType = NATSymmetric
} }
if strings.Contains(pn.config.Node, "openp2pC2CTest") {
pn.config.natType = NATCone
}
if err != nil { if err != nil {
gLog.Println(LevelDEBUG, "detect NAT type error:", err) gLog.Println(LvDEBUG, "detect NAT type error:", err)
break break
} }
gLog.Println(LevelDEBUG, "detect NAT type:", pn.config.natType, " publicIP:", pn.config.publicIP) gLog.Println(LvDEBUG, "detect NAT type:", pn.config.natType, " publicIP:", pn.config.publicIP)
gatewayURL := fmt.Sprintf("%s:%d", pn.config.ServerHost, pn.config.ServerPort) gatewayURL := fmt.Sprintf("%s:%d", pn.config.ServerHost, pn.config.ServerPort)
forwardPath := "/openp2p/v1/login" forwardPath := "/openp2p/v1/login"
config := tls.Config{InsecureSkipVerify: true} // let's encrypt root cert "DST Root CA X3" expired at 2021/09/29. many old system(windows server 2008 etc) will not trust our cert config := tls.Config{InsecureSkipVerify: true} // let's encrypt root cert "DST Root CA X3" expired at 2021/09/29. many old system(windows server 2008 etc) will not trust our cert
@@ -422,25 +421,27 @@ func (pn *P2PNetwork) init() error {
Mac: pn.config.mac, Mac: pn.config.mac,
LanIP: pn.config.localIP, LanIP: pn.config.localIP,
OS: pn.config.os, OS: pn.config.os,
HasIPv4: pn.config.hasIPv4,
HasUPNPorNATPMP: pn.config.hasUPNPorNATPMP,
Version: OpenP2PVersion, Version: OpenP2PVersion,
} }
rsp := netInfo() rsp := netInfo()
gLog.Println(LevelDEBUG, "netinfo:", rsp) gLog.Println(LvDEBUG, "netinfo:", rsp)
if rsp != nil && rsp.Country != "" { if rsp != nil && rsp.Country != "" {
if len(rsp.IP) == net.IPv6len { if IsIPv6(rsp.IP.String()) {
pn.config.ipv6 = rsp.IP.String() pn.config.ipv6 = rsp.IP.String()
req.IPv6 = rsp.IP.String() req.IPv6 = rsp.IP.String()
} }
req.NetInfo = *rsp req.NetInfo = *rsp
} }
pn.write(MsgReport, MsgReportBasic, &req) pn.write(MsgReport, MsgReportBasic, &req)
gLog.Println(LevelDEBUG, "P2PNetwork init ok") gLog.Println(LvDEBUG, "P2PNetwork init ok")
break break
} }
if err != nil { if err != nil {
// init failed, retry // init failed, retry
pn.restartCh <- true pn.restartCh <- true
gLog.Println(LevelERROR, "P2PNetwork init error:", err) gLog.Println(LvERROR, "P2PNetwork init error:", err)
} }
return err return err
} }
@@ -449,7 +450,7 @@ func (pn *P2PNetwork) handleMessage(t int, msg []byte) {
head := openP2PHeader{} head := openP2PHeader{}
err := binary.Read(bytes.NewReader(msg[:openP2PHeaderSize]), binary.LittleEndian, &head) err := binary.Read(bytes.NewReader(msg[:openP2PHeaderSize]), binary.LittleEndian, &head)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "handleMessage error:", err) gLog.Println(LvERROR, "handleMessage error:", err)
return return
} }
switch head.MainType { switch head.MainType {
@@ -458,11 +459,11 @@ func (pn *P2PNetwork) handleMessage(t int, msg []byte) {
rsp := LoginRsp{} rsp := LoginRsp{}
err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp) err = json.Unmarshal(msg[openP2PHeaderSize:], &rsp)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong login response:%s", err) gLog.Printf(LvERROR, "wrong login response:%s", err)
return return
} }
if rsp.Error != 0 { if rsp.Error != 0 {
gLog.Printf(LevelERROR, "login error:%d, detail:%s", rsp.Error, rsp.Detail) gLog.Printf(LvERROR, "login error:%d, detail:%s", rsp.Error, rsp.Detail)
pn.running = false pn.running = false
} else { } else {
pn.serverTs = rsp.Ts pn.serverTs = rsp.Ts
@@ -472,10 +473,10 @@ func (pn *P2PNetwork) handleMessage(t int, msg []byte) {
gConf.setUser(rsp.User) gConf.setUser(rsp.User)
gConf.save() gConf.save()
pn.localTs = time.Now().Unix() pn.localTs = time.Now().Unix()
gLog.Printf(LevelINFO, "login ok. user=%s,Server ts=%d, local ts=%d", rsp.User, rsp.Ts, pn.localTs) gLog.Printf(LvINFO, "login ok. user=%s,Server ts=%d, local ts=%d", rsp.User, rsp.Ts, pn.localTs)
} }
case MsgHeartbeat: case MsgHeartbeat:
gLog.Printf(LevelDEBUG, "P2PNetwork heartbeat ok") gLog.Printf(LvDEBUG, "P2PNetwork heartbeat ok")
case MsgPush: case MsgPush:
handlePush(pn, head.SubType, msg) handlePush(pn, head.SubType, msg)
default: default:
@@ -488,21 +489,21 @@ func (pn *P2PNetwork) handleMessage(t int, msg []byte) {
} }
func (pn *P2PNetwork) readLoop() { func (pn *P2PNetwork) readLoop() {
gLog.Printf(LevelDEBUG, "P2PNetwork readLoop start") gLog.Printf(LvDEBUG, "P2PNetwork readLoop start")
pn.wg.Add(1) pn.wg.Add(1)
defer pn.wg.Done() defer pn.wg.Done()
for pn.running { for pn.running {
pn.conn.SetReadDeadline(time.Now().Add(NetworkHeartbeatTime + 10*time.Second)) pn.conn.SetReadDeadline(time.Now().Add(NetworkHeartbeatTime + 10*time.Second))
t, msg, err := pn.conn.ReadMessage() t, msg, err := pn.conn.ReadMessage()
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "P2PNetwork read error:%s", err) gLog.Printf(LvERROR, "P2PNetwork read error:%s", err)
pn.conn.Close() pn.conn.Close()
pn.restartCh <- true pn.restartCh <- true
break break
} }
pn.handleMessage(t, msg) pn.handleMessage(t, msg)
} }
gLog.Printf(LevelDEBUG, "P2PNetwork readLoop end") gLog.Printf(LvDEBUG, "P2PNetwork readLoop end")
} }
func (pn *P2PNetwork) write(mainType uint16, subType uint16, packet interface{}) error { func (pn *P2PNetwork) write(mainType uint16, subType uint16, packet interface{}) error {
@@ -516,14 +517,14 @@ func (pn *P2PNetwork) write(mainType uint16, subType uint16, packet interface{})
pn.writeMtx.Lock() pn.writeMtx.Lock()
defer pn.writeMtx.Unlock() defer pn.writeMtx.Unlock()
if err = pn.conn.WriteMessage(websocket.BinaryMessage, msg); err != nil { if err = pn.conn.WriteMessage(websocket.BinaryMessage, msg); err != nil {
gLog.Printf(LevelERROR, "write msgType %d,%d error:%s", mainType, subType, err) gLog.Printf(LvERROR, "write msgType %d,%d error:%s", mainType, subType, err)
pn.conn.Close() pn.conn.Close()
} }
return err return err
} }
func (pn *P2PNetwork) relay(to uint64, body []byte) error { func (pn *P2PNetwork) relay(to uint64, body []byte) error {
gLog.Printf(LevelDEBUG, "relay data to %d", to) gLog.Printf(LvDEBUG, "relay data to %d", to)
i, ok := pn.allTunnels.Load(to) i, ok := pn.allTunnels.Load(to)
if !ok { if !ok {
return nil return nil
@@ -537,7 +538,7 @@ func (pn *P2PNetwork) relay(to uint64, body []byte) error {
} }
func (pn *P2PNetwork) push(to string, subType uint16, packet interface{}) error { func (pn *P2PNetwork) push(to string, subType uint16, packet interface{}) error {
gLog.Printf(LevelDEBUG, "push msgType %d to %s", subType, to) gLog.Printf(LvDEBUG, "push msgType %d to %s", subType, to)
if !pn.online { if !pn.online {
return errors.New("client offline") return errors.New("client offline")
} }
@@ -559,7 +560,7 @@ func (pn *P2PNetwork) push(to string, subType uint16, packet interface{}) error
pn.writeMtx.Lock() pn.writeMtx.Lock()
defer pn.writeMtx.Unlock() defer pn.writeMtx.Unlock()
if err = pn.conn.WriteMessage(websocket.BinaryMessage, pushMsg); err != nil { if err = pn.conn.WriteMessage(websocket.BinaryMessage, pushMsg); err != nil {
gLog.Printf(LevelERROR, "push to %s error:%s", to, err) gLog.Printf(LvERROR, "push to %s error:%s", to, err)
pn.conn.Close() pn.conn.Close()
} }
return err return err
@@ -578,13 +579,13 @@ func (pn *P2PNetwork) read(node string, mainType uint16, subType uint16, timeout
for { for {
select { select {
case <-time.After(timeout): case <-time.After(timeout):
gLog.Printf(LevelERROR, "wait msg%d:%d timeout", mainType, subType) gLog.Printf(LvERROR, "wait msg%d:%d timeout", mainType, subType)
return return
case msg := <-ch: case msg := <-ch:
head = &openP2PHeader{} head = &openP2PHeader{}
err := binary.Read(bytes.NewReader(msg[:openP2PHeaderSize]), binary.LittleEndian, head) err := binary.Read(bytes.NewReader(msg[:openP2PHeaderSize]), binary.LittleEndian, head)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "read msg error:", err) gLog.Println(LvERROR, "read msg error:", err)
break break
} }
if head.MainType != mainType || head.SubType != subType { if head.MainType != mainType || head.SubType != subType {
+271 -88
View File
@@ -14,7 +14,7 @@ import (
type P2PTunnel struct { type P2PTunnel struct {
pn *P2PNetwork pn *P2PNetwork
conn p2pConn conn underlay
hbTime time.Time hbTime time.Time
hbMtx sync.Mutex hbMtx sync.Mutex
hbTimeRelay time.Time hbTimeRelay time.Time
@@ -25,7 +25,7 @@ type P2PTunnel struct {
id uint64 id uint64
running bool running bool
runMtx sync.Mutex runMtx sync.Mutex
isServer bool // 0:server 1:client tunnelServer bool // different from underlayServer
coneLocalPort int coneLocalPort int
coneNatPort int coneNatPort int
} }
@@ -39,21 +39,33 @@ func (t *P2PTunnel) init() {
localPort := int(rand.Uint32()%10000 + 50000) localPort := int(rand.Uint32()%10000 + 50000)
if t.pn.config.natType == NATCone { if t.pn.config.natType == NATCone {
// prepare one random cone hole // prepare one random cone hole
_, _, port1, _ := natTest(t.pn.config.ServerHost, t.pn.config.UDPPort1, localPort, 0) _, _, _, port1, _ := natTest(t.pn.config.ServerHost, t.pn.config.UDPPort1, localPort, 0)
t.coneLocalPort = localPort t.coneLocalPort = localPort
t.coneNatPort = port1 t.coneNatPort = port1
t.la = &net.UDPAddr{IP: net.ParseIP(t.pn.config.localIP), Port: t.coneLocalPort} t.la = &net.UDPAddr{IP: net.ParseIP(t.pn.config.localIP), Port: t.coneLocalPort}
} else { } else {
t.coneLocalPort = localPort t.coneLocalPort = localPort
t.coneNatPort = localPort // NATNONE or symmetric doesn't need coneNatPort t.coneNatPort = localPort // symmetric doesn't need coneNatPort
if t.pn.config.hasUPNPorNATPMP == 1 {
nat, err := Discover()
if err != nil {
gLog.Println(LvDEBUG, "could not perform UPNP discover:", err)
} else {
externalPort, err := nat.AddPortMapping("tcp", localPort, localPort, "openp2p", 30) // timeout the connection still alive, make the timeout short
if err != nil {
gLog.Println(LvDEBUG, "could not add udp UPNP port mapping", externalPort)
}
}
}
t.la = &net.UDPAddr{IP: net.ParseIP(t.pn.config.localIP), Port: t.coneLocalPort} t.la = &net.UDPAddr{IP: net.ParseIP(t.pn.config.localIP), Port: t.coneLocalPort}
} }
gLog.Printf(LevelDEBUG, "prepare punching port %d:%d", t.coneLocalPort, t.coneNatPort) gLog.Printf(LvDEBUG, "prepare punching port %d:%d", t.coneLocalPort, t.coneNatPort)
} }
func (t *P2PTunnel) connect() error { func (t *P2PTunnel) connect() error {
gLog.Printf(LevelDEBUG, "start p2pTunnel to %s ", t.config.PeerNode) gLog.Printf(LvDEBUG, "start p2pTunnel to %s ", t.config.PeerNode)
t.isServer = false t.tunnelServer = false
appKey := uint64(0)
req := PushConnectReq{ req := PushConnectReq{
Token: t.config.peerToken, Token: t.config.peerToken,
From: t.pn.config.Node, From: t.pn.config.Node,
@@ -61,7 +73,13 @@ func (t *P2PTunnel) connect() error {
FromIP: t.pn.config.publicIP, FromIP: t.pn.config.publicIP,
ConeNatPort: t.coneNatPort, ConeNatPort: t.coneNatPort,
NatType: t.pn.config.natType, NatType: t.pn.config.natType,
ID: t.id} HasIPv4: t.pn.config.hasIPv4,
IPv6: t.pn.config.IPv6,
HasUPNPorNATPMP: t.pn.config.hasUPNPorNATPMP,
ID: t.id,
AppKey: appKey,
Version: OpenP2PVersion,
}
t.pn.push(t.config.PeerNode, MsgPushConnectReq, req) t.pn.push(t.config.PeerNode, MsgPushConnectReq, req)
head, body := t.pn.read(t.config.PeerNode, MsgPush, MsgPushConnectRsp, time.Second*10) head, body := t.pn.read(t.config.PeerNode, MsgPush, MsgPushConnectRsp, time.Second*10)
if head == nil { if head == nil {
@@ -70,19 +88,23 @@ func (t *P2PTunnel) connect() error {
rsp := PushConnectRsp{} rsp := PushConnectRsp{}
err := json.Unmarshal(body, &rsp) err := json.Unmarshal(body, &rsp)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong MsgPushConnectRsp:%s", err) gLog.Printf(LvERROR, "wrong MsgPushConnectRsp:%s", err)
return err return err
} }
// gLog.Println(LevelINFO, rsp) // gLog.Println(LevelINFO, rsp)
if rsp.Error != 0 { if rsp.Error != 0 {
return errors.New(rsp.Detail) return errors.New(rsp.Detail)
} }
t.config.peerNatType = int(rsp.NatType) t.config.peerNatType = rsp.NatType
t.config.hasIPv4 = rsp.HasIPv4
t.config.IPv6 = rsp.IPv6
t.config.hasUPNPorNATPMP = rsp.HasUPNPorNATPMP
t.config.peerVersion = rsp.Version
t.config.peerConeNatPort = rsp.ConeNatPort t.config.peerConeNatPort = rsp.ConeNatPort
t.config.peerIP = rsp.FromIP t.config.peerIP = rsp.FromIP
err = t.handshake() err = t.start()
if err != nil { if err != nil {
gLog.Println(LevelERROR, "handshake error:", err) gLog.Println(LvERROR, "handshake error:", err)
err = ErrorHandshake err = ErrorHandshake
} }
return err return err
@@ -135,6 +157,20 @@ func (t *P2PTunnel) close() {
t.pn.allTunnels.Delete(t.id) t.pn.allTunnels.Delete(t.id)
} }
func (t *P2PTunnel) start() error {
if !t.isSupportTCP() {
if err := t.handshake(); err != nil {
return err
}
}
err := t.connectUnderlay()
if err != nil {
gLog.Println(LvERROR, err)
return err
}
return nil
}
func (t *P2PTunnel) handshake() error { func (t *P2PTunnel) handshake() error {
if t.config.peerConeNatPort > 0 { if t.config.peerConeNatPort > 0 {
var err error var err error
@@ -143,7 +179,7 @@ func (t *P2PTunnel) handshake() error {
return err return err
} }
} }
gLog.Println(LevelDEBUG, "handshake to ", t.config.PeerNode) gLog.Println(LvDEBUG, "handshake to ", t.config.PeerNode)
var err error var err error
// TODO: handle NATNone, nodes with public ip has no punching // TODO: handle NATNone, nodes with public ip has no punching
if (t.pn.config.natType == NATCone && t.config.peerNatType == NATCone) || (t.pn.config.natType == NATNone || t.config.peerNatType == NATNone) { if (t.pn.config.natType == NATCone && t.config.peerNatType == NATCone) || (t.pn.config.natType == NATNone || t.config.peerNatType == NATNone) {
@@ -159,96 +195,205 @@ func (t *P2PTunnel) handshake() error {
return errors.New("unknown error") return errors.New("unknown error")
} }
if err != nil { if err != nil {
gLog.Println(LevelERROR, "punch handshake error:", err) gLog.Println(LvERROR, "punch handshake error:", err)
return err
}
gLog.Printf(LevelDEBUG, "handshake to %s ok", t.config.PeerNode)
err = t.run()
if err != nil {
gLog.Println(LevelERROR, err)
return err return err
} }
gLog.Printf(LvDEBUG, "handshake to %s ok", t.config.PeerNode)
return nil return nil
} }
func (t *P2PTunnel) run() error { func (t *P2PTunnel) connectUnderlay() (err error) {
if t.isServer { if !t.isSupportTCP() {
qConn, e := listenQuic(t.la.String(), TunnelIdleTimeout) t.conn, err = t.connectUnderlayQuic()
if e != nil { if err != nil {
gLog.Println(LevelINFO, "listen quic error:", e, ", retry...") return err
time.Sleep(time.Millisecond * 10)
qConn, e = listenQuic(t.la.String(), TunnelIdleTimeout)
if e != nil {
return fmt.Errorf("listen quic error:%s", e)
} }
} else {
// TODO: udp or tcp first?
// prepare a la ra for udp
// t.conn, err = t.connectUnderlayQuic()
// TODO: support ipv6
// if t.pn.config.hasIPv4 == 1 || t.config.hasIPv4 == 1 {
t.conn, err = t.connectUnderlayTCP()
if err != nil {
return err
} }
t.pn.push(t.config.PeerNode, MsgPushQuicConnect, nil) // }
e = qConn.Accept() // if IsIPv6(t.pn.config.IPv6) && IsIPv6(t.config.IPv6) { // both have ipv6
if e != nil { // t.conn, err = t.connectUnderlayTCP6()
qConn.CloseListener() // if err != nil {
return fmt.Errorf("accept quic error:%s", e) // return err
// }
// }
} }
_, buff, err := qConn.ReadMessage()
if e != nil {
qConn.listener.Close()
return fmt.Errorf("read start msg error:%s", err)
}
if buff != nil {
gLog.Println(LevelDEBUG, string(buff))
}
qConn.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
gLog.Println(LevelDEBUG, "quic connection ok")
t.conn = qConn
t.setRun(true) t.setRun(true)
go t.readLoop() go t.readLoop()
go t.writeLoop() go t.heartbeatLoop()
return nil return nil
} }
func (t *P2PTunnel) connectUnderlayQuic() (c underlay, err error) {
gLog.Println(LvINFO, "connectUnderlayQuic start")
defer gLog.Println(LvINFO, "connectUnderlayQuic end")
var qConn *underlayQUIC
if t.isUnderlayServer() {
time.Sleep(time.Millisecond * 10) // punching udp port will need some times in some env
qConn, err = listenQuic(t.la.String(), TunnelIdleTimeout)
if err != nil {
gLog.Println(LvINFO, "listen quic error:", err, ", retry...")
}
t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
err = qConn.Accept()
if err != nil {
qConn.CloseListener()
return nil, fmt.Errorf("accept quic error:%s", err)
}
_, buff, err := qConn.ReadBuffer()
if err != nil {
qConn.listener.Close()
return nil, fmt.Errorf("read start msg error:%s", err)
}
if buff != nil {
gLog.Println(LvDEBUG, string(buff))
}
qConn.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
gLog.Println(LvDEBUG, "quic connection ok")
return qConn, nil
}
//else //else
conn, e := net.ListenUDP("udp", t.la) conn, e := net.ListenUDP("udp", t.la)
if e != nil { if e != nil {
time.Sleep(time.Millisecond * 10) time.Sleep(time.Millisecond * 10)
conn, e = net.ListenUDP("udp", t.la) conn, e = net.ListenUDP("udp", t.la)
if e != nil { if e != nil {
return fmt.Errorf("quic listen error:%s", e) return nil, fmt.Errorf("quic listen error:%s", e)
} }
} }
t.pn.read(t.config.PeerNode, MsgPush, MsgPushQuicConnect, time.Second*5) t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, time.Second*5)
gLog.Println(LevelDEBUG, "quic dial to ", t.ra.String()) gLog.Println(LvDEBUG, "quic dial to ", t.ra.String())
qConn, e := dialQuic(conn, t.ra, TunnelIdleTimeout) qConn, e = dialQuic(conn, t.ra, TunnelIdleTimeout)
if e != nil { if e != nil {
return fmt.Errorf("quic dial to %s error:%s", t.ra.String(), e) return nil, fmt.Errorf("quic dial to %s error:%s", t.ra.String(), e)
} }
handshakeBegin := time.Now() handshakeBegin := time.Now()
qConn.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello")) qConn.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
_, buff, err := qConn.ReadMessage() _, buff, err := qConn.ReadBuffer()
if e != nil { if e != nil {
qConn.listener.Close() qConn.listener.Close()
return fmt.Errorf("read MsgTunnelHandshake error:%s", err) return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
} }
if buff != nil { if buff != nil {
gLog.Println(LevelDEBUG, string(buff)) gLog.Println(LvDEBUG, string(buff))
} }
gLog.Println(LevelINFO, "rtt=", time.Since(handshakeBegin)) gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
gLog.Println(LevelDEBUG, "quic connection ok") gLog.Println(LvDEBUG, "quic connection ok")
t.conn = qConn return qConn, nil
t.setRun(true) }
go t.readLoop()
go t.writeLoop() // websocket
return nil func (t *P2PTunnel) connectUnderlayTCP() (c underlay, err error) {
gLog.Println(LvINFO, "connectUnderlayTCP start")
defer gLog.Println(LvINFO, "connectUnderlayTCP end")
var qConn *underlayTCP
if t.isUnderlayServer() {
t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
qConn, err = listenTCP(t.coneNatPort, TunnelIdleTimeout)
if err != nil {
return nil, fmt.Errorf("listen TCP error:%s", err)
}
_, buff, err := qConn.ReadBuffer()
if err != nil {
qConn.listener.Close()
return nil, fmt.Errorf("read start msg error:%s", err)
}
if buff != nil {
gLog.Println(LvDEBUG, string(buff))
}
qConn.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
gLog.Println(LvDEBUG, "TCP connection ok")
return qConn, nil
}
//else
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, time.Second*5)
gLog.Println(LvDEBUG, "TCP dial to ", t.ra.String())
qConn, err = dialTCP(t.config.peerIP, t.config.peerConeNatPort)
if err != nil {
return nil, fmt.Errorf("TCP dial to %s error:%s", t.ra.String(), err)
}
handshakeBegin := time.Now()
qConn.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
_, buff, err := qConn.ReadBuffer()
if err != nil {
qConn.listener.Close()
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
}
if buff != nil {
gLog.Println(LvDEBUG, string(buff))
}
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
gLog.Println(LvDEBUG, "TCP connection ok")
return qConn, nil
}
func (t *P2PTunnel) connectUnderlayTCP6() (c underlay, err error) {
gLog.Println(LvINFO, "connectUnderlayTCP start")
defer gLog.Println(LvINFO, "connectUnderlayTCP end")
var qConn *underlayTCP6
if t.isUnderlayServer() {
t.pn.push(t.config.PeerNode, MsgPushUnderlayConnect, nil)
qConn, err = listenTCP6(t.coneNatPort, TunnelIdleTimeout)
if err != nil {
return nil, fmt.Errorf("listen TCP error:%s", err)
}
_, buff, err := qConn.ReadBuffer()
if err != nil {
qConn.listener.Close()
return nil, fmt.Errorf("read start msg error:%s", err)
}
if buff != nil {
gLog.Println(LvDEBUG, string(buff))
}
qConn.WriteBytes(MsgP2P, MsgTunnelHandshakeAck, []byte("OpenP2P,hello2"))
gLog.Println(LvDEBUG, "TCP connection ok")
return qConn, nil
}
//else
t.pn.read(t.config.PeerNode, MsgPush, MsgPushUnderlayConnect, time.Second*5)
gLog.Println(LvDEBUG, "TCP dial to ", t.ra.String())
qConn, err = dialTCP6(t.config.IPv6, t.config.peerConeNatPort)
if err != nil {
return nil, fmt.Errorf("TCP dial to %s error:%s", t.ra.String(), err)
}
handshakeBegin := time.Now()
qConn.WriteBytes(MsgP2P, MsgTunnelHandshake, []byte("OpenP2P,hello"))
_, buff, err := qConn.ReadBuffer()
if err != nil {
qConn.listener.Close()
return nil, fmt.Errorf("read MsgTunnelHandshake error:%s", err)
}
if buff != nil {
gLog.Println(LvDEBUG, string(buff))
}
gLog.Println(LvINFO, "rtt=", time.Since(handshakeBegin))
gLog.Println(LvDEBUG, "TCP connection ok")
return qConn, nil
} }
func (t *P2PTunnel) readLoop() { func (t *P2PTunnel) readLoop() {
decryptData := make([]byte, ReadBuffLen+PaddingSize) // 16 bytes for padding decryptData := make([]byte, ReadBuffLen+PaddingSize) // 16 bytes for padding
gLog.Printf(LevelDEBUG, "%d tunnel readloop start", t.id) gLog.Printf(LvDEBUG, "%d tunnel readloop start", t.id)
for t.isRuning() { for t.isRuning() {
t.conn.SetReadDeadline(time.Now().Add(TunnelIdleTimeout)) t.conn.SetReadDeadline(time.Now().Add(TunnelIdleTimeout))
head, body, err := t.conn.ReadMessage() head, body, err := t.conn.ReadBuffer()
if err != nil { if err != nil {
if t.isRuning() { if t.isRuning() {
gLog.Printf(LevelERROR, "%d tunnel read error:%s", t.id, err) gLog.Printf(LvERROR, "%d tunnel read error:%s", t.id, err)
} }
break break
} }
@@ -258,22 +403,22 @@ func (t *P2PTunnel) readLoop() {
switch head.SubType { switch head.SubType {
case MsgTunnelHeartbeat: case MsgTunnelHeartbeat:
t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeatAck, nil) t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeatAck, nil)
gLog.Printf(LevelDEBUG, "%d read tunnel heartbeat", t.id) gLog.Printf(LvDEBUG, "%d read tunnel heartbeat", t.id)
case MsgTunnelHeartbeatAck: case MsgTunnelHeartbeatAck:
t.hbMtx.Lock() t.hbMtx.Lock()
t.hbTime = time.Now() t.hbTime = time.Now()
t.hbMtx.Unlock() t.hbMtx.Unlock()
gLog.Printf(LevelDEBUG, "%d read tunnel heartbeat ack", t.id) gLog.Printf(LvDEBUG, "%d read tunnel heartbeat ack", t.id)
case MsgOverlayData: case MsgOverlayData:
if len(body) < overlayHeaderSize { if len(body) < overlayHeaderSize {
continue continue
} }
overlayID := binary.LittleEndian.Uint64(body[:8]) overlayID := binary.LittleEndian.Uint64(body[:8])
gLog.Printf(LevelDEBUG, "%d tunnel read overlay data %d", t.id, overlayID) gLog.Printf(LvDEBUG, "%d tunnel read overlay data %d", t.id, overlayID)
s, ok := t.overlayConns.Load(overlayID) s, ok := t.overlayConns.Load(overlayID)
if !ok { if !ok {
// debug level, when overlay connection closed, always has some packet not found tunnel // debug level, when overlay connection closed, always has some packet not found tunnel
gLog.Printf(LevelDEBUG, "%d tunnel not found overlay connection %d", t.id, overlayID) gLog.Printf(LvDEBUG, "%d tunnel not found overlay connection %d", t.id, overlayID)
continue continue
} }
overlayConn, ok := s.(*overlayConn) overlayConn, ok := s.(*overlayConn)
@@ -287,10 +432,10 @@ func (t *P2PTunnel) readLoop() {
} }
_, err = overlayConn.Write(payload) _, err = overlayConn.Write(payload)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "overlay write error:", err) gLog.Println(LvERROR, "overlay write error:", err)
} }
case MsgRelayData: case MsgRelayData:
gLog.Printf(LevelDEBUG, "got relay data datalen=%d", head.DataLen) gLog.Printf(LvDEBUG, "got relay data datalen=%d", head.DataLen)
if len(body) < 8 { if len(body) < 8 {
continue continue
} }
@@ -300,10 +445,10 @@ func (t *P2PTunnel) readLoop() {
req := RelayHeartbeat{} req := RelayHeartbeat{}
err := json.Unmarshal(body, &req) err := json.Unmarshal(body, &req)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong RelayHeartbeat:%s", err) gLog.Printf(LvERROR, "wrong RelayHeartbeat:%s", err)
continue continue
} }
gLog.Printf(LevelDEBUG, "got MsgRelayHeartbeat from %d:%d", req.RelayTunnelID, req.AppID) gLog.Printf(LvDEBUG, "got MsgRelayHeartbeat from %d:%d", req.RelayTunnelID, req.AppID)
relayHead := new(bytes.Buffer) relayHead := new(bytes.Buffer)
binary.Write(relayHead, binary.LittleEndian, req.RelayTunnelID) binary.Write(relayHead, binary.LittleEndian, req.RelayTunnelID)
msg, _ := newMessage(MsgP2P, MsgRelayHeartbeatAck, &req) msg, _ := newMessage(MsgP2P, MsgRelayHeartbeatAck, &req)
@@ -313,26 +458,26 @@ func (t *P2PTunnel) readLoop() {
req := RelayHeartbeat{} req := RelayHeartbeat{}
err := json.Unmarshal(body, &req) err := json.Unmarshal(body, &req)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong RelayHeartbeat:%s", err) gLog.Printf(LvERROR, "wrong RelayHeartbeat:%s", err)
continue continue
} }
gLog.Printf(LevelDEBUG, "got MsgRelayHeartbeatAck to %d", req.AppID) gLog.Printf(LvDEBUG, "got MsgRelayHeartbeatAck to %d", req.AppID)
t.pn.updateAppHeartbeat(req.AppID) t.pn.updateAppHeartbeat(req.AppID)
case MsgOverlayConnectReq: case MsgOverlayConnectReq:
req := OverlayConnectReq{} req := OverlayConnectReq{}
err := json.Unmarshal(body, &req) err := json.Unmarshal(body, &req)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong MsgOverlayConnectReq:%s", err) gLog.Printf(LvERROR, "wrong MsgOverlayConnectReq:%s", err)
continue continue
} }
// app connect only accept token(not relay totp token), avoid someone using the share relay node's token // 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 { if req.Token != t.pn.config.Token {
gLog.Println(LevelERROR, "Access Denied:", req.Token) gLog.Println(LvERROR, "Access Denied:", req.Token)
continue continue
} }
overlayID := req.ID overlayID := req.ID
gLog.Printf(LevelDEBUG, "App:%d overlayID:%d connect %+v", req.AppID, overlayID, req) gLog.Printf(LvDEBUG, "App:%d overlayID:%d connect %+v", req.AppID, overlayID, req)
oConn := overlayConn{ oConn := overlayConn{
tunnel: t, tunnel: t,
id: overlayID, id: overlayID,
@@ -347,7 +492,7 @@ func (t *P2PTunnel) readLoop() {
oConn.connTCP, err = net.DialTimeout("tcp", fmt.Sprintf("%s:%d", req.DstIP, req.DstPort), time.Second*5) oConn.connTCP, err = net.DialTimeout("tcp", fmt.Sprintf("%s:%d", req.DstIP, req.DstPort), time.Second*5)
} }
if err != nil { if err != nil {
gLog.Println(LevelERROR, err) gLog.Println(LvERROR, err)
continue continue
} }
@@ -365,11 +510,11 @@ func (t *P2PTunnel) readLoop() {
req := OverlayDisconnectReq{} req := OverlayDisconnectReq{}
err := json.Unmarshal(body, &req) err := json.Unmarshal(body, &req)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "wrong OverlayDisconnectRequest:%s", err) gLog.Printf(LvERROR, "wrong OverlayDisconnectRequest:%s", err)
continue continue
} }
overlayID := req.ID overlayID := req.ID
gLog.Printf(LevelDEBUG, "%d disconnect overlay connection %d", t.id, overlayID) gLog.Printf(LvDEBUG, "%d disconnect overlay connection %d", t.id, overlayID)
i, ok := t.overlayConns.Load(overlayID) i, ok := t.overlayConns.Load(overlayID)
if ok { if ok {
oConn := i.(*overlayConn) oConn := i.(*overlayConn)
@@ -380,32 +525,49 @@ func (t *P2PTunnel) readLoop() {
} }
t.setRun(false) t.setRun(false)
t.conn.Close() t.conn.Close()
gLog.Printf(LevelDEBUG, "%d tunnel readloop end", t.id) gLog.Printf(LvDEBUG, "%d tunnel readloop end", t.id)
} }
func (t *P2PTunnel) writeLoop() { func (t *P2PTunnel) heartbeatLoop() {
tc := time.NewTicker(TunnelHeartbeatTime) tc := time.NewTicker(TunnelHeartbeatTime)
defer tc.Stop() defer tc.Stop()
defer gLog.Printf(LevelDEBUG, "%d tunnel writeloop end", t.id) gLog.Printf(LvDEBUG, "%d tunnel heartbeatLoop start", t.id)
defer gLog.Printf(LvDEBUG, "%d tunnel heartbeatLoop end", t.id)
for t.isRuning() { for t.isRuning() {
select { select {
case <-tc.C: case <-tc.C:
// tunnel send // tunnel send
err := t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeat, nil) err := t.conn.WriteBytes(MsgP2P, MsgTunnelHeartbeat, nil)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "%d write tunnel heartbeat error %s", t.id, err) gLog.Printf(LvERROR, "%d write tunnel heartbeat error %s", t.id, err)
t.setRun(false) t.setRun(false)
return return
} }
gLog.Printf(LevelDEBUG, "%d write tunnel heartbeat ok", t.id) gLog.Printf(LvDEBUG, "%d write tunnel heartbeat ok", t.id)
} }
} }
} }
func (t *P2PTunnel) listen() error { func (t *P2PTunnel) listen() error {
gLog.Printf(LevelDEBUG, "p2ptunnel wait for connecting") // notify client to connect
t.isServer = true rsp := PushConnectRsp{
return t.handshake() Error: 0,
Detail: "connect ok",
To: t.config.PeerNode,
From: t.pn.config.Node,
NatType: t.pn.config.natType,
HasIPv4: t.pn.config.hasIPv4,
IPv6: t.pn.config.IPv6,
HasUPNPorNATPMP: t.pn.config.hasUPNPorNATPMP,
FromIP: t.pn.config.publicIP,
ConeNatPort: t.coneNatPort,
ID: t.id,
Version: OpenP2PVersion,
}
t.pn.push(t.config.PeerNode, MsgPushConnectRsp, rsp)
gLog.Printf(LvDEBUG, "p2ptunnel wait for connecting")
t.tunnelServer = true
return t.start()
} }
func (t *P2PTunnel) closeOverlayConns(appID uint64) { func (t *P2PTunnel) closeOverlayConns(appID uint64) {
@@ -424,3 +586,24 @@ func (t *P2PTunnel) closeOverlayConns(appID uint64) {
return true return true
}) })
} }
func (t *P2PTunnel) isUnderlayServer() bool {
if t.pn.config.natType == NATNone && t.config.peerNatType != NATNone {
return true
}
if t.pn.config.natType != NATNone && t.config.peerNatType == NATNone {
return false
}
// NAT or both has public IP
return t.tunnelServer
}
func (t *P2PTunnel) isSupportTCP() bool {
if t.config.peerVersion == "" || compareVersion(t.config.peerVersion, LeastSupportTCPVersion) == LESS {
return false
}
if t.pn.config.natType == NATNone || t.config.peerNatType == NATNone {
return true
}
return false
}
+31 -5
View File
@@ -10,8 +10,9 @@ import (
"time" "time"
) )
const OpenP2PVersion = "1.4.2" const OpenP2PVersion = "1.5.6"
const ProducnName string = "openp2p" const ProducnName string = "openp2p"
const LeastSupportTCPVersion = "1.5.0"
type openP2PHeader struct { type openP2PHeader struct {
DataLen uint32 DataLen uint32
@@ -69,6 +70,7 @@ const (
MsgReport = 6 MsgReport = 6
) )
// TODO: seperate node push and web push.
const ( const (
MsgPushRsp = 0 MsgPushRsp = 0
MsgPushConnectReq = 1 MsgPushConnectReq = 1
@@ -78,11 +80,12 @@ const (
MsgPushAddRelayTunnelRsp = 5 MsgPushAddRelayTunnelRsp = 5
MsgPushUpdate = 6 MsgPushUpdate = 6
MsgPushReportApps = 7 MsgPushReportApps = 7
MsgPushQuicConnect = 8 MsgPushUnderlayConnect = 8
MsgPushEditApp = 9 MsgPushEditApp = 9
MsgPushSwitchApp = 10 MsgPushSwitchApp = 10
MsgPushRestart = 11 MsgPushRestart = 11
MsgPushEditNode = 12 MsgPushEditNode = 12
MsgPushAPPKey = 13
) )
// MsgP2P sub type message // MsgP2P sub type message
@@ -131,7 +134,7 @@ const (
AESKeySize = 16 AESKeySize = 16
MaxRetry = 10 MaxRetry = 10
RetryInterval = time.Second * 30 RetryInterval = time.Second * 30
PublicIPEchoTimeout = time.Second * 3 PublicIPEchoTimeout = time.Second * 1
NatTestTimeout = time.Second * 10 NatTestTimeout = time.Second * 10
ClientAPITimeout = time.Second * 10 ClientAPITimeout = time.Second * 10
MaxDirectTry = 5 MaxDirectTry = 5
@@ -145,6 +148,13 @@ const (
NATUnknown = 314 NATUnknown = 314
) )
// underlay protocol
const (
UderlayAuto = "auto"
UderlayQUIC = "quic"
UderlayTCP = "tcp"
)
func newMessage(mainType uint16, subType uint16, packet interface{}) ([]byte, error) { func newMessage(mainType uint16, subType uint16, packet interface{}) ([]byte, error) {
data, err := json.Marshal(packet) data, err := json.Marshal(packet)
if err != nil { if err != nil {
@@ -172,11 +182,16 @@ func nodeNameToID(name string) uint64 {
type PushConnectReq struct { type PushConnectReq struct {
From string `json:"from,omitempty"` From string `json:"from,omitempty"`
FromToken uint64 `json:"fromToken,omitempty"` //my token FromToken uint64 `json:"fromToken,omitempty"` //my token
Version string `json:"version,omitempty"`
Token uint64 `json:"token,omitempty"` // totp token Token uint64 `json:"token,omitempty"` // totp token
ConeNatPort int `json:"coneNatPort,omitempty"` ConeNatPort int `json:"coneNatPort,omitempty"` // if isPublic, is public port
NatType int `json:"natType,omitempty"` NatType int `json:"natType,omitempty"`
HasIPv4 int `json:"hasIPv4,omitempty"`
IPv6 string `json:"IPv6,omitempty"`
HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"`
FromIP string `json:"fromIP,omitempty"` FromIP string `json:"fromIP,omitempty"`
ID uint64 `json:"id,omitempty"` ID uint64 `json:"id,omitempty"`
AppKey uint64 `json:"appKey,omitempty"` // for underlay tcp
} }
type PushConnectRsp struct { type PushConnectRsp struct {
Error int `json:"error,omitempty"` Error int `json:"error,omitempty"`
@@ -184,9 +199,13 @@ type PushConnectRsp struct {
To string `json:"to,omitempty"` To string `json:"to,omitempty"`
Detail string `json:"detail,omitempty"` Detail string `json:"detail,omitempty"`
NatType int `json:"natType,omitempty"` NatType int `json:"natType,omitempty"`
ConeNatPort int `json:"coneNatPort,omitempty"` HasIPv4 int `json:"hasIPv4,omitempty"`
IPv6 string `json:"IPv6,omitempty"`
HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"`
ConeNatPort int `json:"coneNatPort,omitempty"` //it's not only cone, but also upnp or nat-pmp hole
FromIP string `json:"fromIP,omitempty"` FromIP string `json:"fromIP,omitempty"`
ID uint64 `json:"id,omitempty"` ID uint64 `json:"id,omitempty"`
Version string `json:"version,omitempty"`
} }
type PushRsp struct { type PushRsp struct {
Error int `json:"error,omitempty"` Error int `json:"error,omitempty"`
@@ -246,6 +265,11 @@ type AddRelayTunnelReq struct {
From string `json:"from,omitempty"` From string `json:"from,omitempty"`
RelayName string `json:"relayName,omitempty"` RelayName string `json:"relayName,omitempty"`
RelayToken uint64 `json:"relayToken,omitempty"` RelayToken uint64 `json:"relayToken,omitempty"`
AppID uint64 `json:"appID,omitempty"` // deprecated
AppKey uint64 `json:"appKey,omitempty"` // deprecated
}
type APPKeySync struct {
AppID uint64 `json:"appID,omitempty"` AppID uint64 `json:"appID,omitempty"`
AppKey uint64 `json:"appKey,omitempty"` AppKey uint64 `json:"appKey,omitempty"`
} }
@@ -259,7 +283,9 @@ type ReportBasic struct {
OS string `json:"os,omitempty"` OS string `json:"os,omitempty"`
Mac string `json:"mac,omitempty"` Mac string `json:"mac,omitempty"`
LanIP string `json:"lanIP,omitempty"` LanIP string `json:"lanIP,omitempty"`
HasIPv4 int `json:"hasIPv4,omitempty"`
IPv6 string `json:"IPv6,omitempty"` IPv6 string `json:"IPv6,omitempty"`
HasUPNPorNATPMP int `json:"hasUPNPorNATPMP,omitempty"`
Version string `json:"version,omitempty"` Version string `json:"version,omitempty"`
NetInfo NetInfo `json:"netInfo,omitempty"` NetInfo NetInfo `json:"netInfo,omitempty"`
} }
+2 -2
View File
@@ -23,7 +23,7 @@ func UDPRead(conn *net.UDPConn, timeout int) (ra net.Addr, head *openP2PHeader,
deadline := time.Now().Add(time.Millisecond * time.Duration(timeout)) deadline := time.Now().Add(time.Millisecond * time.Duration(timeout))
err = conn.SetReadDeadline(deadline) err = conn.SetReadDeadline(deadline)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "SetReadDeadline error") gLog.Println(LvERROR, "SetReadDeadline error")
return nil, nil, nil, 0, err return nil, nil, nil, 0, err
} }
} }
@@ -37,7 +37,7 @@ func UDPRead(conn *net.UDPConn, timeout int) (ra net.Addr, head *openP2PHeader,
head = &openP2PHeader{} head = &openP2PHeader{}
err = binary.Read(bytes.NewReader(result[:openP2PHeaderSize]), binary.LittleEndian, head) err = binary.Read(bytes.NewReader(result[:openP2PHeaderSize]), binary.LittleEndian, head)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "parse p2pheader error:", err) gLog.Println(LvERROR, "parse p2pheader error:", err)
return nil, nil, nil, 0, err return nil, nil, nil, 0, err
} }
return return
+16
View File
@@ -0,0 +1,16 @@
package main
import (
"time"
)
type underlay interface {
ReadBuffer() (*openP2PHeader, []byte, error)
WriteBytes(uint16, uint16, []byte) error
WriteBuffer([]byte) error
WriteMessage(uint16, uint16, interface{}) error
Close() error
SetReadDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error
Protocol() string
}
+155
View File
@@ -0,0 +1,155 @@
package main
import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"io"
"math/big"
"net"
"sync"
"time"
"github.com/lucas-clemente/quic-go"
)
//quic.DialContext do not support version 44,disable it
var quicVersion []quic.VersionNumber
type underlayQUIC struct {
listener quic.Listener
writeMtx *sync.Mutex
quic.Stream
quic.Connection
}
func (conn *underlayQUIC) Protocol() string {
return "quic"
}
func (conn *underlayQUIC) ReadBuffer() (*openP2PHeader, []byte, error) {
headBuf := make([]byte, openP2PHeaderSize)
_, err := io.ReadFull(conn, headBuf)
if err != nil {
return nil, nil, err
}
head, err := decodeHeader(headBuf)
if err != nil {
return nil, nil, err
}
dataBuf := make([]byte, head.DataLen)
_, err = io.ReadFull(conn, dataBuf)
return head, dataBuf, err
}
func (conn *underlayQUIC) WriteBytes(mainType uint16, subType uint16, data []byte) error {
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
conn.writeMtx.Lock()
_, err := conn.Write(writeBytes)
conn.writeMtx.Unlock()
return err
}
func (conn *underlayQUIC) WriteBuffer(data []byte) error {
conn.writeMtx.Lock()
_, err := conn.Write(data)
conn.writeMtx.Unlock()
return err
}
func (conn *underlayQUIC) WriteMessage(mainType uint16, subType uint16, packet interface{}) error {
// TODO: call newMessage
data, err := json.Marshal(packet)
if err != nil {
return err
}
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
conn.writeMtx.Lock()
_, err = conn.Write(writeBytes)
conn.writeMtx.Unlock()
return err
}
func (conn *underlayQUIC) Close() error {
conn.Stream.CancelRead(1)
conn.Connection.CloseWithError(0, "")
return nil
}
func (conn *underlayQUIC) CloseListener() {
if conn.listener != nil {
conn.listener.Close()
}
}
func (conn *underlayQUIC) Accept() error {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
sess, err := conn.listener.Accept(ctx)
if err != nil {
return err
}
stream, err := sess.AcceptStream(context.Background())
if err != nil {
return err
}
conn.Stream = stream
conn.Connection = sess
return nil
}
func listenQuic(addr string, idleTimeout time.Duration) (*underlayQUIC, error) {
gLog.Println(LvDEBUG, "quic listen on ", addr)
listener, err := quic.ListenAddr(addr, generateTLSConfig(),
&quic.Config{Versions: quicVersion, MaxIdleTimeout: idleTimeout, DisablePathMTUDiscovery: true})
if err != nil {
return nil, fmt.Errorf("quic.ListenAddr error:%s", err)
}
return &underlayQUIC{listener: listener, writeMtx: &sync.Mutex{}}, nil
}
func dialQuic(conn *net.UDPConn, remoteAddr *net.UDPAddr, idleTimeout time.Duration) (*underlayQUIC, error) {
tlsConf := &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{"openp2pv1"},
}
Connection, err := quic.DialContext(context.Background(), conn, remoteAddr, conn.LocalAddr().String(), tlsConf,
&quic.Config{Versions: quicVersion, MaxIdleTimeout: idleTimeout, DisablePathMTUDiscovery: true})
if err != nil {
return nil, fmt.Errorf("quic.DialContext error:%s", err)
}
stream, err := Connection.OpenStreamSync(context.Background())
if err != nil {
return nil, fmt.Errorf("OpenStreamSync error:%s", err)
}
qConn := &underlayQUIC{nil, &sync.Mutex{}, stream, Connection}
return qConn, nil
}
// Setup a bare-bones TLS config for the server
func generateTLSConfig() *tls.Config {
key, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
panic(err)
}
template := x509.Certificate{SerialNumber: big.NewInt(1)}
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
if err != nil {
panic(err)
}
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
if err != nil {
panic(err)
}
return &tls.Config{
Certificates: []tls.Certificate{tlsCert},
NextProtos: []string{"openp2pv1"},
}
}
+92
View File
@@ -0,0 +1,92 @@
package main
import (
"encoding/json"
"fmt"
"io"
"net"
"sync"
"time"
)
type underlayTCP struct {
listener net.Listener
writeMtx *sync.Mutex
net.Conn
}
func (conn *underlayTCP) Protocol() string {
return "tcp"
}
func (conn *underlayTCP) ReadBuffer() (*openP2PHeader, []byte, error) {
headBuf := make([]byte, openP2PHeaderSize)
_, err := io.ReadFull(conn, headBuf)
if err != nil {
return nil, nil, err
}
head, err := decodeHeader(headBuf)
if err != nil {
return nil, nil, err
}
dataBuf := make([]byte, head.DataLen)
_, err = io.ReadFull(conn, dataBuf)
return head, dataBuf, err
}
func (conn *underlayTCP) WriteBytes(mainType uint16, subType uint16, data []byte) error {
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
conn.writeMtx.Lock()
_, err := conn.Write(writeBytes)
conn.writeMtx.Unlock()
return err
}
func (conn *underlayTCP) WriteBuffer(data []byte) error {
conn.writeMtx.Lock()
_, err := conn.Write(data)
conn.writeMtx.Unlock()
return err
}
func (conn *underlayTCP) WriteMessage(mainType uint16, subType uint16, packet interface{}) error {
// TODO: call newMessage
data, err := json.Marshal(packet)
if err != nil {
return err
}
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
conn.writeMtx.Lock()
_, err = conn.Write(writeBytes)
conn.writeMtx.Unlock()
return err
}
func (conn *underlayTCP) Close() error {
return conn.Conn.Close()
}
func listenTCP(port int, idleTimeout time.Duration) (*underlayTCP, error) {
addr, _ := net.ResolveTCPAddr("tcp", fmt.Sprintf("0.0.0.0:%d", port))
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return nil, err
}
defer l.Close()
l.SetDeadline(time.Now().Add(SymmetricHandshakeAckTimeout))
c, err := l.Accept()
defer l.Close()
if err != nil {
return nil, err
}
return &underlayTCP{writeMtx: &sync.Mutex{}, Conn: c}, nil
}
func dialTCP(host string, port int) (*underlayTCP, error) {
c, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), SymmetricHandshakeAckTimeout)
if err != nil {
fmt.Printf("Dial %s:%d error:%s", host, port, err)
return nil, err
}
return &underlayTCP{writeMtx: &sync.Mutex{}, Conn: c}, nil
}
+92
View File
@@ -0,0 +1,92 @@
package main
import (
"encoding/json"
"fmt"
"io"
"net"
"sync"
"time"
)
type underlayTCP6 struct {
listener net.Listener
writeMtx *sync.Mutex
net.Conn
}
func (conn *underlayTCP6) Protocol() string {
return "tcp6"
}
func (conn *underlayTCP6) ReadBuffer() (*openP2PHeader, []byte, error) {
headBuf := make([]byte, openP2PHeaderSize)
_, err := io.ReadFull(conn, headBuf)
if err != nil {
return nil, nil, err
}
head, err := decodeHeader(headBuf)
if err != nil {
return nil, nil, err
}
dataBuf := make([]byte, head.DataLen)
_, err = io.ReadFull(conn, dataBuf)
return head, dataBuf, err
}
func (conn *underlayTCP6) WriteBytes(mainType uint16, subType uint16, data []byte) error {
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
conn.writeMtx.Lock()
_, err := conn.Write(writeBytes)
conn.writeMtx.Unlock()
return err
}
func (conn *underlayTCP6) WriteBuffer(data []byte) error {
conn.writeMtx.Lock()
_, err := conn.Write(data)
conn.writeMtx.Unlock()
return err
}
func (conn *underlayTCP6) WriteMessage(mainType uint16, subType uint16, packet interface{}) error {
// TODO: call newMessage
data, err := json.Marshal(packet)
if err != nil {
return err
}
writeBytes := append(encodeHeader(mainType, subType, uint32(len(data))), data...)
conn.writeMtx.Lock()
_, err = conn.Write(writeBytes)
conn.writeMtx.Unlock()
return err
}
func (conn *underlayTCP6) Close() error {
return conn.Conn.Close()
}
func listenTCP6(port int, idleTimeout time.Duration) (*underlayTCP6, error) {
addr, _ := net.ResolveTCPAddr("tcp6", fmt.Sprintf("0.0.0.0:%d", port))
l, err := net.ListenTCP("tcp6", addr)
if err != nil {
return nil, err
}
defer l.Close()
l.SetDeadline(time.Now().Add(SymmetricHandshakeAckTimeout))
c, err := l.Accept()
defer l.Close()
if err != nil {
return nil, err
}
return &underlayTCP6{writeMtx: &sync.Mutex{}, Conn: c}, nil
}
func dialTCP6(host string, port int) (*underlayTCP6, error) {
c, err := net.DialTimeout("tcp6", fmt.Sprintf("%s:%d", host, port), SymmetricHandshakeAckTimeout)
if err != nil {
fmt.Printf("Dial %s:%d error:%s", host, port, err)
return nil, err
}
return &underlayTCP6{writeMtx: &sync.Mutex{}, Conn: c}, nil
}
+17 -17
View File
@@ -17,8 +17,8 @@ import (
) )
func update() { func update() {
gLog.Println(LevelINFO, "update start") gLog.Println(LvINFO, "update start")
defer gLog.Println(LevelINFO, "update end") defer gLog.Println(LvINFO, "update end")
c := http.Client{ c := http.Client{
Transport: &http.Transport{ Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
@@ -29,43 +29,43 @@ func update() {
goarch := runtime.GOARCH goarch := runtime.GOARCH
rsp, err := c.Get(fmt.Sprintf("https://openp2p.cn:27183/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 { if err != nil {
gLog.Println(LevelERROR, "update:query update list failed:", err) gLog.Println(LvERROR, "update:query update list failed:", err)
return return
} }
defer rsp.Body.Close() defer rsp.Body.Close()
if rsp.StatusCode != http.StatusOK { if rsp.StatusCode != http.StatusOK {
gLog.Println(LevelERROR, "get update info error:", rsp.Status) gLog.Println(LvERROR, "get update info error:", rsp.Status)
return return
} }
rspBuf, err := ioutil.ReadAll(rsp.Body) rspBuf, err := ioutil.ReadAll(rsp.Body)
if err != nil { if err != nil {
gLog.Println(LevelERROR, "update:read update list failed:", err) gLog.Println(LvERROR, "update:read update list failed:", err)
return return
} }
updateInfo := UpdateInfo{} updateInfo := UpdateInfo{}
err = json.Unmarshal(rspBuf, &updateInfo) err = json.Unmarshal(rspBuf, &updateInfo)
if err != nil { if err != nil {
gLog.Println(LevelERROR, rspBuf, " update info decode error:", err) gLog.Println(LvERROR, rspBuf, " update info decode error:", err)
return return
} }
if updateInfo.Error != 0 { if updateInfo.Error != 0 {
gLog.Println(LevelERROR, "update error:", updateInfo.Error, updateInfo.ErrorDetail) gLog.Println(LvERROR, "update error:", updateInfo.Error, updateInfo.ErrorDetail)
return return
} }
err = updateFile(updateInfo.Url, "", "openp2p") err = updateFile(updateInfo.Url, "", "openp2p")
if err != nil { if err != nil {
gLog.Println(LevelERROR, "update: download failed:", err) gLog.Println(LvERROR, "update: download failed:", err)
return return
} }
} }
// todo rollback on error // todo rollback on error
func updateFile(url string, checksum string, dst string) error { func updateFile(url string, checksum string, dst string) error {
gLog.Println(LevelINFO, "download ", url) gLog.Println(LvINFO, "download ", url)
tmpFile := filepath.Dir(os.Args[0]) + "/openp2p.tmp" tmpFile := filepath.Dir(os.Args[0]) + "/openp2p.tmp"
output, err := os.OpenFile(tmpFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0776) output, err := os.OpenFile(tmpFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0776)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "OpenFile %s error:%s", tmpFile, err) gLog.Printf(LvERROR, "OpenFile %s error:%s", tmpFile, err)
return err return err
} }
tr := &http.Transport{ tr := &http.Transport{
@@ -74,31 +74,31 @@ func updateFile(url string, checksum string, dst string) error {
client := &http.Client{Transport: tr} client := &http.Client{Transport: tr}
response, err := client.Get(url) response, err := client.Get(url)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "download url %s error:%s", url, err) gLog.Printf(LvERROR, "download url %s error:%s", url, err)
output.Close() output.Close()
return err return err
} }
defer response.Body.Close() defer response.Body.Close()
n, err := io.Copy(output, response.Body) n, err := io.Copy(output, response.Body)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "io.Copy error:%s", err) gLog.Printf(LvERROR, "io.Copy error:%s", err)
output.Close() output.Close()
return err return err
} }
output.Sync() output.Sync()
output.Close() output.Close()
gLog.Println(LevelINFO, "download ", url, " ok") gLog.Println(LvINFO, "download ", url, " ok")
gLog.Printf(LevelINFO, "size: %d bytes", n) gLog.Printf(LvINFO, "size: %d bytes", n)
err = os.Rename(os.Args[0], os.Args[0]+"0") err = os.Rename(os.Args[0], os.Args[0]+"0")
if err != nil && os.IsExist(err) { if err != nil && os.IsExist(err) {
gLog.Printf(LevelINFO, " rename %s error:%s", os.Args[0], err) gLog.Printf(LvINFO, " rename %s error:%s", os.Args[0], err)
} }
// extract // extract
gLog.Println(LevelINFO, "extract files") gLog.Println(LvINFO, "extract files")
err = extract(filepath.Dir(os.Args[0]), tmpFile) err = extract(filepath.Dir(os.Args[0]), tmpFile)
if err != nil { if err != nil {
gLog.Printf(LevelERROR, "extract error:%s. revert rename", err) gLog.Printf(LvERROR, "extract error:%s. revert rename", err)
os.Rename(os.Args[0]+"0", os.Args[0]) os.Rename(os.Args[0]+"0", os.Args[0])
return err return err
} }
+404
View File
@@ -0,0 +1,404 @@
/*
Taken from taipei-torrent
Just enough UPnP to be able to forward ports
*/
package main
// BUG(jae): TODO: use syscalls to get actual ourIP. http://pastebin.com/9exZG4rh
import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"strconv"
"strings"
"time"
)
type upnpNAT struct {
serviceURL string
ourIP string
urnDomain string
}
// protocol is either "udp" or "tcp"
type NAT interface {
GetExternalAddress() (addr net.IP, err error)
AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error)
DeletePortMapping(protocol string, externalPort, internalPort int) (err error)
}
func Discover() (nat NAT, err error) {
ssdp, err := net.ResolveUDPAddr("udp4", "239.255.255.250:1900")
if err != nil {
return
}
conn, err := net.ListenPacket("udp4", ":0")
if err != nil {
return
}
socket := conn.(*net.UDPConn)
defer socket.Close() // nolint: errcheck
if err := socket.SetDeadline(time.Now().Add(3 * time.Second)); err != nil {
return nil, err
}
st := "InternetGatewayDevice:1"
buf := bytes.NewBufferString(
"M-SEARCH * HTTP/1.1\r\n" +
"HOST: 239.255.255.250:1900\r\n" +
"ST: ssdp:all\r\n" +
"MAN: \"ssdp:discover\"\r\n" +
"MX: 2\r\n\r\n")
message := buf.Bytes()
answerBytes := make([]byte, 1024)
for i := 0; i < 3; i++ {
_, err = socket.WriteToUDP(message, ssdp)
if err != nil {
return
}
var n int
_, _, err = socket.ReadFromUDP(answerBytes)
if err != nil {
return
}
for {
n, _, err = socket.ReadFromUDP(answerBytes)
if err != nil {
break
}
answer := string(answerBytes[0:n])
if !strings.Contains(answer, st) {
continue
}
// HTTP header field names are case-insensitive.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
locString := "\r\nlocation:"
answer = strings.ToLower(answer)
locIndex := strings.Index(answer, locString)
if locIndex < 0 {
continue
}
loc := answer[locIndex+len(locString):]
endIndex := strings.Index(loc, "\r\n")
if endIndex < 0 {
continue
}
locURL := strings.TrimSpace(loc[0:endIndex])
var serviceURL, urnDomain string
serviceURL, urnDomain, err = getServiceURL(locURL)
if err != nil {
return
}
var ourIP net.IP
ourIP, err = localIPv4()
if err != nil {
return
}
nat = &upnpNAT{serviceURL: serviceURL, ourIP: ourIP.String(), urnDomain: urnDomain}
return
}
}
err = errors.New("UPnP port discovery failed")
return
}
type Envelope struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`
Soap *SoapBody
}
type SoapBody struct {
XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
ExternalIP *ExternalIPAddressResponse
}
type ExternalIPAddressResponse struct {
XMLName xml.Name `xml:"GetExternalIPAddressResponse"`
IPAddress string `xml:"NewExternalIPAddress"`
}
type ExternalIPAddress struct {
XMLName xml.Name `xml:"NewExternalIPAddress"`
IP string
}
type UPNPService struct {
ServiceType string `xml:"serviceType"`
ControlURL string `xml:"controlURL"`
}
type DeviceList struct {
Device []Device `xml:"device"`
}
type ServiceList struct {
Service []UPNPService `xml:"service"`
}
type Device struct {
XMLName xml.Name `xml:"device"`
DeviceType string `xml:"deviceType"`
DeviceList DeviceList `xml:"deviceList"`
ServiceList ServiceList `xml:"serviceList"`
}
type Root struct {
Device Device
}
func getChildDevice(d *Device, deviceType string) *Device {
dl := d.DeviceList.Device
for i := 0; i < len(dl); i++ {
if strings.Contains(dl[i].DeviceType, deviceType) {
return &dl[i]
}
}
return nil
}
func getChildService(d *Device, serviceType string) *UPNPService {
sl := d.ServiceList.Service
for i := 0; i < len(sl); i++ {
if strings.Contains(sl[i].ServiceType, serviceType) {
return &sl[i]
}
}
return nil
}
func localIPv4() (net.IP, error) {
tt, err := net.Interfaces()
if err != nil {
return nil, err
}
for _, t := range tt {
aa, err := t.Addrs()
if err != nil {
return nil, err
}
for _, a := range aa {
ipnet, ok := a.(*net.IPNet)
if !ok {
continue
}
v4 := ipnet.IP.To4()
if v4 == nil || v4[0] == 127 { // loopback address
continue
}
return v4, nil
}
}
return nil, errors.New("cannot find local IP address")
}
func getServiceURL(rootURL string) (url, urnDomain string, err error) {
r, err := http.Get(rootURL)
if err != nil {
return
}
defer r.Body.Close() // nolint: errcheck
if r.StatusCode >= 400 {
err = errors.New(fmt.Sprint(r.StatusCode))
return
}
var root Root
err = xml.NewDecoder(r.Body).Decode(&root)
if err != nil {
return
}
a := &root.Device
if !strings.Contains(a.DeviceType, "InternetGatewayDevice:1") {
err = errors.New("No InternetGatewayDevice")
return
}
b := getChildDevice(a, "WANDevice:1")
if b == nil {
err = errors.New("No WANDevice")
return
}
c := getChildDevice(b, "WANConnectionDevice:1")
if c == nil {
err = errors.New("No WANConnectionDevice")
return
}
d := getChildService(c, "WANIPConnection:1")
if d == nil {
// Some routers don't follow the UPnP spec, and put WanIPConnection under WanDevice,
// instead of under WanConnectionDevice
d = getChildService(b, "WANIPConnection:1")
if d == nil {
d = getChildService(c, "WANPPPConnection:1")
if d == nil {
err = errors.New("No WANIPConnection or WANPPPConnection")
return
}
}
}
// Extract the domain name, which isn't always 'schemas-upnp-org'
urnDomain = strings.Split(d.ServiceType, ":")[1]
url = combineURL(rootURL, d.ControlURL)
return
}
func combineURL(rootURL, subURL string) string {
protocolEnd := "://"
protoEndIndex := strings.Index(rootURL, protocolEnd)
a := rootURL[protoEndIndex+len(protocolEnd):]
rootIndex := strings.Index(a, "/")
return rootURL[0:protoEndIndex+len(protocolEnd)+rootIndex] + subURL
}
func soapRequest(url, function, message, domain string) (r *http.Response, err error) {
fullMessage := "<?xml version=\"1.0\" ?>" +
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n" +
"<s:Body>" + message + "</s:Body></s:Envelope>"
req, err := http.NewRequest("POST", url, strings.NewReader(fullMessage))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "text/xml ; charset=\"utf-8\"")
req.Header.Set("User-Agent", "Darwin/10.0.0, UPnP/1.0, MiniUPnPc/1.3")
//req.Header.Set("Transfer-Encoding", "chunked")
req.Header.Set("SOAPAction", "\"urn:"+domain+":service:WANIPConnection:1#"+function+"\"")
req.Header.Set("Connection", "Close")
req.Header.Set("Cache-Control", "no-cache")
req.Header.Set("Pragma", "no-cache")
// log.Stderr("soapRequest ", req)
r, err = http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
/*if r.Body != nil {
defer r.Body.Close()
}*/
if r.StatusCode >= 400 {
// log.Stderr(function, r.StatusCode)
err = errors.New("Error " + strconv.Itoa(r.StatusCode) + " for " + function)
r = nil
return
}
return
}
type statusInfo struct {
externalIpAddress string
}
func (n *upnpNAT) getExternalIPAddress() (info statusInfo, err error) {
message := "<u:GetExternalIPAddress xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
"</u:GetExternalIPAddress>"
var response *http.Response
response, err = soapRequest(n.serviceURL, "GetExternalIPAddress", message, n.urnDomain)
if response != nil {
defer response.Body.Close() // nolint: errcheck
}
if err != nil {
return
}
var envelope Envelope
data, err := ioutil.ReadAll(response.Body)
if err != nil {
return
}
reader := bytes.NewReader(data)
err = xml.NewDecoder(reader).Decode(&envelope)
if err != nil {
return
}
info = statusInfo{envelope.Soap.ExternalIP.IPAddress}
if err != nil {
return
}
return
}
// GetExternalAddress returns an external IP. If GetExternalIPAddress action
// fails or IP returned is invalid, GetExternalAddress returns an error.
func (n *upnpNAT) GetExternalAddress() (addr net.IP, err error) {
info, err := n.getExternalIPAddress()
if err != nil {
return
}
addr = net.ParseIP(info.externalIpAddress)
if addr == nil {
err = fmt.Errorf("Failed to parse IP: %v", info.externalIpAddress)
}
return
}
func (n *upnpNAT) AddPortMapping(protocol string, externalPort, internalPort int, description string, timeout int) (mappedExternalPort int, err error) {
// A single concatenation would break ARM compilation.
message := "<u:AddPortMapping xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort)
message += "</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>"
message += "<NewInternalPort>" + strconv.Itoa(internalPort) + "</NewInternalPort>" +
"<NewInternalClient>" + n.ourIP + "</NewInternalClient>" +
"<NewEnabled>1</NewEnabled><NewPortMappingDescription>"
message += description +
"</NewPortMappingDescription><NewLeaseDuration>" + strconv.Itoa(timeout) +
"</NewLeaseDuration></u:AddPortMapping>"
var response *http.Response
response, err = soapRequest(n.serviceURL, "AddPortMapping", message, n.urnDomain)
if response != nil {
defer response.Body.Close() // nolint: errcheck
}
if err != nil {
return
}
// TODO: check response to see if the port was forwarded
// log.Println(message, response)
// JAE:
// body, err := ioutil.ReadAll(response.Body)
// fmt.Println(string(body), err)
mappedExternalPort = externalPort
_ = response
return
}
func (n *upnpNAT) DeletePortMapping(protocol string, externalPort, internalPort int) (err error) {
message := "<u:DeletePortMapping xmlns:u=\"urn:" + n.urnDomain + ":service:WANIPConnection:1\">\r\n" +
"<NewRemoteHost></NewRemoteHost><NewExternalPort>" + strconv.Itoa(externalPort) +
"</NewExternalPort><NewProtocol>" + protocol + "</NewProtocol>" +
"</u:DeletePortMapping>"
var response *http.Response
response, err = soapRequest(n.serviceURL, "DeletePortMapping", message, n.urnDomain)
if response != nil {
defer response.Body.Close() // nolint: errcheck
}
if err != nil {
return
}
// TODO: check response to see if the port was deleted
// log.Println(message, response)
_ = response
return
}
+32
View File
@@ -0,0 +1,32 @@
package main
import (
"strings"
"syscall"
)
const (
defaultInstallPath = "/usr/local/openp2p"
defaultBinName = "openp2p"
)
func getOsName() (osName string) {
output := execOutput("sw_vers", "-productVersion")
osName = "Mac OS X " + strings.TrimSpace(output)
return
}
func setRLimit() error {
var limit syscall.Rlimit
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
return err
}
limit.Cur = 10240
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
return err
}
return nil
}
func setFirewall() {
}
+72
View File
@@ -0,0 +1,72 @@
package main
import (
"bufio"
"bytes"
"io/ioutil"
"os"
"strings"
"syscall"
)
const (
defaultInstallPath = "/usr/local/openp2p"
defaultBinName = "openp2p"
)
func getOsName() (osName string) {
var sysnamePath string
sysnamePath = "/etc/redhat-release"
_, err := os.Stat(sysnamePath)
if err != nil && os.IsNotExist(err) {
str := "PRETTY_NAME="
f, err := os.Open("/etc/os-release")
if err != nil && os.IsNotExist(err) {
str = "DISTRIB_ID="
f, err = os.Open("/etc/openwrt_release")
}
if err == nil {
buf := bufio.NewReader(f)
for {
line, err := buf.ReadString('\n')
if err == nil {
line = strings.TrimSpace(line)
pos := strings.Count(line, str)
if pos > 0 {
len1 := len([]rune(str)) + 1
rs := []rune(line)
osName = string(rs[len1 : (len(rs))-1])
break
}
} else {
break
}
}
}
} else {
buff, err := ioutil.ReadFile(sysnamePath)
if err == nil {
osName = string(bytes.TrimSpace(buff))
}
}
if osName == "" {
osName = "Linux"
}
return
}
func setRLimit() error {
var limit syscall.Rlimit
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
return err
}
limit.Max = 1024 * 1024
limit.Cur = limit.Max
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
return err
}
return nil
}
func setFirewall() {
}
+53
View File
@@ -0,0 +1,53 @@
package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"golang.org/x/sys/windows/registry"
)
const (
defaultInstallPath = "C:\\Program Files\\OpenP2P"
defaultBinName = "openp2p.exe"
)
func getOsName() (osName string) {
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE|registry.WOW64_64KEY)
if err != nil {
return
}
defer k.Close()
pn, _, err := k.GetStringValue("ProductName")
if err == nil {
osName = pn
}
return
}
func setRLimit() error {
return nil
}
func setFirewall() {
fullPath, err := filepath.Abs(os.Args[0])
if err != nil {
gLog.Println(LvERROR, "add firewall error:", err)
return
}
isXP := false
osName := getOsName()
if strings.Contains(osName, "XP") || strings.Contains(osName, "2003") {
isXP = true
}
if isXP {
exec.Command("cmd.exe", `/c`, fmt.Sprintf(`netsh firewall del allowedprogram "%s"`, fullPath)).Run()
exec.Command("cmd.exe", `/c`, fmt.Sprintf(`netsh firewall add allowedprogram "%s" "%s" ENABLE`, ProducnName, fullPath)).Run()
} else { // win7 or later
exec.Command("cmd.exe", `/c`, fmt.Sprintf(`netsh advfirewall firewall del rule name="%s"`, ProducnName)).Run()
exec.Command("cmd.exe", `/c`, fmt.Sprintf(`netsh advfirewall firewall add rule name="%s" dir=in action=allow program="%s" enable=yes`, ProducnName, fullPath)).Run()
}
}