package main import ( "context" "fmt" "io" "log" "net" "os" "path/filepath" "runtime" "sync" "time" "github.com/things-go/go-socks5" "github.com/chenjia404/go-p2ptunnel/config" "github.com/chenjia404/go-p2ptunnel/p2p" "github.com/chenjia404/go-p2ptunnel/update" "github.com/chenjia404/go-p2ptunnel/pRuntime" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peerstore" "github.com/multiformats/go-multiaddr" "github.com/libp2p/go-libp2p/core/crypto" "github.com/libp2p/go-libp2p/core/peer" ) const Protocol = "/p2ptunnel/0.1" func loadUserPrivKey() (priv crypto.PrivKey, err error) { krPath := user + ".key" pkFile, err := os.Open(krPath) if err == nil { defer pkFile.Close() b, err := io.ReadAll(pkFile) if err != nil { return nil, err } priv, err = crypto.UnmarshalPrivateKey(b) if err != nil { return nil, err } return priv, nil } if !os.IsNotExist(err) { return nil, err } priv, _, err = crypto.GenerateKeyPair(crypto.Ed25519, -1) if err != nil { return nil, err } b, err := crypto.MarshalPrivateKey(priv) if err != nil { return nil, err } err = os.MkdirAll(filepath.Dir(krPath), os.ModePerm) if err != nil { return nil, err } newPkFile, err := os.Create(krPath) if err != nil { return nil, err } _, err = newPkFile.Write(b) if err != nil { return nil, err } err = newPkFile.Close() if err != nil { return nil, err } return priv, nil } var ( version = "0.2.32" gitRev = "" buildTime = "" ) var nodisc bool var user = "user" func main() { config.LoadConfig() if config.Cfg.Update { update.CheckGithubVersion(version) return } RE: proc, err := pRuntime.NewProc() if err != nil { fmt.Println("up proc fail........") } //如果proc为nil表示当前进程已经是子进程了 //不为空表示当前进程为主进程 if proc != nil { go func() { pRuntime.HandleEndSignal(func() { if err := proc.Kill(); err != nil { fmt.Println(err) } fmt.Println("main proc exit....") os.Exit(0) }) }() //等待子进程退出后 重启 err = proc.Wait() if err != nil { fmt.Println("proc wait err........") } else { goto RE } return } else { if config.Cfg.AutoUpdate { ticker := time.NewTicker(time.Hour * 24) go func() { for t := range ticker.C { fmt.Println("CheckGithubVersion time:", t) update.CheckGithubVersion(version) } }() } } fmt.Printf("p2ptunnel %s-%s\n", version, gitRev) fmt.Printf("buildTime %s\n", buildTime) fmt.Printf("System version: %s\n", runtime.GOARCH+"/"+runtime.GOOS) fmt.Printf("Golang version: %s\n", runtime.Version()) if config.Cfg.AutoUpdate { fmt.Printf("AutoUpdate:open") go update.CheckGithubVersion(version) } if len(config.Cfg.User) > 0 { user = config.Cfg.User } ctx, cancel := context.WithCancel(context.Background()) priv, _ := loadUserPrivKey() h, err := p2p.CreateLibp2pHost(ctx, priv, config.Cfg.P2pPort, config.Cfg.MaxPeers, config.Cfg.Nodisc, Protocol) if err != nil { cancel() fmt.Printf("err:%s", err.Error()) //return nil, nil, err } fmt.Println("Your id: " + h.ID().String()) if nodisc { fmt.Println("Turn off node discovery") } if len(config.Cfg.Socks5) >= 6 { server := socks5.NewServer( socks5.WithLogger(socks5.NewLogger(log.New(os.Stdout, "socks5: ", log.LstdFlags))), ) // Create SOCKS5 proxy on localhost port 8000 go func() { if err := server.ListenAndServe("tcp", config.Cfg.Socks5); err != nil { panic(err) } }() log.Printf("socks5 open:%s\n", config.Cfg.Socks5) } //打开隧道 if config.Cfg.Id == "" { ticker := time.NewTicker(time.Second * 10) go func() { for { // 用上一个死循环,不停地执行,否则只会执行一次 select { case <-ticker.C: log.Printf("Conns:%d\n", len(h.Network().Conns())) } } }() h.SetStreamHandler(Protocol, func(s network.Stream) { log.Printf("新客户端%s\n", s.Conn().RemotePeer().String()) dconn, err := net.Dial("tcp", config.Cfg.Listen) if err != nil { fmt.Printf("连接%v失败:%v\n", config.Cfg.Listen, err) s.Close() return } else { fmt.Printf("转发:%s\n", config.Cfg.Listen) fmt.Printf("Streams:%d\n", len(s.Conn().GetStreams())) } go pipe(dconn, s) }) } else { //连接指定节点 // Turn the destination into a multiaddr. id_str := config.Cfg.Id if id_str[0] != '/' { id_str = "/p2p/" + id_str } maddr, err := multiaddr.NewMultiaddr(id_str) if err != nil { log.Fatalln("multiaddr", err) } // Extract the peer ID from the multiaddr. info, err := peer.AddrInfoFromP2pAddr(maddr) if err != nil { log.Panic(err) } // Add the destination's peer multiaddress in the peerstore. // This will be used during connection and stream creation by libp2p. //time.Sleep(time.Second * 5) var s network.Stream ticker := time.NewTicker(time.Second * 10) go func() { for { // 用上一个死循环,不停地执行,否则只会执行一次 select { case <-ticker.C: if s != nil { log.Printf("Stream:%d\n", len(s.Conn().GetStreams())) } } } }() lis, err := net.Listen("tcp", config.Cfg.Listen) if err != nil { fmt.Println("Listen:", err) return } else { fmt.Printf("监听:%s\n", config.Cfg.Listen) } for { h.Peerstore().AddAddrs(info.ID, info.Addrs, peerstore.PermanentAddrTTL) err = h.Connect(ctx, *info) if err != nil { log.Println("Connect:", err) time.Sleep(time.Second * 5) } else { fmt.Printf("连接成功%s\n", info.ID.String()) for { if s != nil { log.Printf("Stream:%d\n", len(s.Conn().GetStreams())) if len(s.Conn().GetStreams()) == 0 { err = h.Connect(ctx, *info) if err != nil { log.Println("Connect:", err) time.Sleep(time.Second * 5) } } } log.Println("open New Stream") timeout, _ := context.WithTimeout(context.Background(), 5*time.Second) s, err = h.NewStream(timeout, info.ID, Protocol) if err != nil { fmt.Println("New Stream:" + err.Error()) err = h.Connect(ctx, *info) if err != nil { log.Println("Connect:", err) time.Sleep(time.Second * 5) } } else { log.Println("New Stream is open") } // 长时间休眠,已经没有 Stream 了 if s == nil || len(s.Conn().GetStreams()) == 0 { continue } conn, err := lis.Accept() if err != nil { fmt.Printf("建立连接错误:%s\n", err.Error()) } else { fmt.Println("新请求") } go pipe(conn, s) } } } } select {} } func pipe(src net.Conn, dest network.Stream) { var wg sync.WaitGroup var wait = 10 * time.Second onClose := func(err error) { _ = dest.Reset() _ = src.Close() } wg.Add(2) go func() { defer wg.Done() _, err := io.Copy(src, dest) src.SetReadDeadline(time.Now().Add(wait)) // unblock read on right onClose(err) }() go func() { defer wg.Done() _, err := io.Copy(dest, src) dest.SetReadDeadline(time.Now().Add(wait)) // unblock read on left onClose(err) }() wg.Wait() }