mirror of
https://github.com/chenjia404/p2ptunnel.git
synced 2024-05-03 08:14:53 +08:00
0861d112d8
支持自定义p2p端口 降低默认连接节点数
283 lines
5.5 KiB
Go
283 lines
5.5 KiB
Go
package p2pforwarder
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/libp2p/go-libp2p/core/network"
|
|
|
|
"github.com/libp2p/go-libp2p/core/routing"
|
|
routing2 "github.com/libp2p/go-libp2p/p2p/discovery/routing"
|
|
"github.com/libp2p/go-libp2p/p2p/net/connmgr"
|
|
"github.com/libp2p/go-libp2p/p2p/security/noise"
|
|
|
|
"github.com/libp2p/go-libp2p"
|
|
dht "github.com/libp2p/go-libp2p-kad-dht"
|
|
"github.com/libp2p/go-libp2p/core/crypto"
|
|
"github.com/libp2p/go-libp2p/core/host"
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
|
libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls"
|
|
"github.com/sparkymat/appdir"
|
|
)
|
|
|
|
const (
|
|
protocolTypeTCP byte = 0x00
|
|
protocolTypeUDP byte = 0x01
|
|
)
|
|
|
|
// Forwarder - instance of P2P Forwarder
|
|
type Forwarder struct {
|
|
host host.Host
|
|
openPorts *openPortsStore
|
|
|
|
portsSubscriptions map[peer.ID]chan *portsManifest
|
|
portsSubscriptionsMux sync.Mutex
|
|
|
|
portsSubscribers map[peer.ID]struct{}
|
|
portsSubscribersMux sync.Mutex
|
|
}
|
|
|
|
type openPortsStore struct {
|
|
tcp *openPortsStoreMap
|
|
udp *openPortsStoreMap
|
|
}
|
|
|
|
type openPortsStoreMap struct {
|
|
ports map[uint16]context.Context
|
|
mux sync.Mutex
|
|
}
|
|
|
|
func newOpenPortsStore() *openPortsStore {
|
|
return &openPortsStore{
|
|
tcp: &openPortsStoreMap{
|
|
ports: map[uint16]context.Context{},
|
|
},
|
|
udp: &openPortsStoreMap{
|
|
ports: map[uint16]context.Context{},
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewForwarder - instances Forwarder and connects it to libp2p network
|
|
func NewForwarder(p2p_port int) (*Forwarder, context.CancelFunc, error) {
|
|
priv, err := loadUserPrivKey()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
h, err := createLibp2pHost(ctx, priv, p2p_port)
|
|
if err != nil {
|
|
cancel()
|
|
return nil, nil, err
|
|
}
|
|
|
|
for _, value := range h.Addrs() {
|
|
fmt.Println("multiaddr:" + value.String())
|
|
}
|
|
|
|
f := &Forwarder{
|
|
host: h,
|
|
|
|
openPorts: newOpenPortsStore(),
|
|
|
|
portsSubscriptions: make(map[peer.ID]chan *portsManifest),
|
|
portsSubscribers: make(map[peer.ID]struct{}),
|
|
}
|
|
|
|
setDialHandler(f)
|
|
setPortsSubHandler(f)
|
|
|
|
return f, cancel, nil
|
|
}
|
|
|
|
func loadUserPrivKey() (priv crypto.PrivKey, err error) {
|
|
krPath, err := appdir.AppInfo{
|
|
Author: "nickname32",
|
|
Name: "P2P Forwarder",
|
|
}.ConfigPath("keypair")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pkFile, err := os.Open(krPath)
|
|
|
|
if err == nil {
|
|
defer pkFile.Close()
|
|
|
|
b, err := ioutil.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
|
|
}
|
|
|
|
const Protocol = "/p2ptunnel/0.1"
|
|
|
|
func createLibp2pHost(ctx context.Context, priv crypto.PrivKey, p2p_port int) (host.Host, error) {
|
|
var d *dht.IpfsDHT
|
|
|
|
connmgr, _ := connmgr.NewConnManager(
|
|
10, // Lowwater
|
|
100, // HighWater,
|
|
connmgr.WithGracePeriod(time.Minute),
|
|
)
|
|
var h, err = libp2p.New(
|
|
libp2p.Identity(priv),
|
|
|
|
libp2p.ListenAddrStrings(
|
|
fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", p2p_port),
|
|
fmt.Sprintf("/ip6/::/tcp/%d", p2p_port),
|
|
|
|
fmt.Sprintf("/ip4/0.0.0.0/tcp/%d/ws", p2p_port),
|
|
fmt.Sprintf("/ip6/::/tcp/%d/ws", p2p_port),
|
|
|
|
fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic-v1", p2p_port),
|
|
fmt.Sprintf("/ip6/::/udp/%d/quic-v1", p2p_port),
|
|
|
|
fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic-v1/webtransport", p2p_port),
|
|
fmt.Sprintf("/ip6/::/udp/%d/quic-v1/webtransport", p2p_port),
|
|
),
|
|
|
|
libp2p.DefaultTransports,
|
|
|
|
libp2p.Security(noise.ID, noise.New),
|
|
libp2p.Security(libp2ptls.ID, libp2ptls.New),
|
|
|
|
libp2p.NATPortMap(),
|
|
|
|
libp2p.EnableNATService(),
|
|
libp2p.ConnectionManager(connmgr),
|
|
|
|
libp2p.EnableRelay(),
|
|
libp2p.EnableRelayService(),
|
|
libp2p.DefaultPeerstore,
|
|
|
|
libp2p.Routing(func(h host.Host) (routing.PeerRouting, error) {
|
|
var err error
|
|
d, err = dht.New(ctx, h, dht.BootstrapPeers(dht.GetDefaultBootstrapPeerAddrInfos()...))
|
|
return d, err
|
|
}),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// This connects to public bootstrappers
|
|
for _, addr := range dht.DefaultBootstrapPeers {
|
|
pi, err := peer.AddrInfoFromP2pAddr(addr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
h.Connect(ctx, *pi)
|
|
}
|
|
|
|
err = d.Bootstrap(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d1 := routing2.NewRoutingDiscovery(d)
|
|
|
|
go func() {
|
|
_, err = d1.Advertise(ctx, Protocol)
|
|
|
|
if err != nil {
|
|
log.Println(err)
|
|
}
|
|
}()
|
|
|
|
go func() {
|
|
peerChan, err := d1.FindPeers(ctx, Protocol)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
for dhtPeer := range peerChan {
|
|
if dhtPeer.ID == h.ID() {
|
|
continue
|
|
}
|
|
if h.Network().Connectedness(dhtPeer.ID) != network.Connected {
|
|
h.Connect(ctx, dhtPeer)
|
|
}
|
|
}
|
|
time.Sleep(time.Second * 10)
|
|
}()
|
|
|
|
return h, err
|
|
}
|
|
|
|
// ID returns id of Forwarder
|
|
func (f *Forwarder) ID() string {
|
|
return f.host.ID().String()
|
|
}
|
|
|
|
var onErrFn = func(err error) {
|
|
println(err.Error())
|
|
}
|
|
var onInfoFn = func(str string) {
|
|
println(str)
|
|
}
|
|
|
|
// OnError sets function which be called on error inside this package
|
|
func OnError(fn func(error)) {
|
|
if fn == nil {
|
|
return
|
|
}
|
|
onErrFn = fn
|
|
}
|
|
|
|
// OnInfo sets function which be called on information inside this package
|
|
func OnInfo(fn func(string)) {
|
|
if fn == nil {
|
|
return
|
|
}
|
|
onInfoFn = fn
|
|
}
|