-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Hole Punching] - Implementation Example #2761
Comments
Enable the holepunch module by passing in Option: Line 536 in a2da8e0
|
You can enable the holepunch module like this: libp2p.New(libp2p.EnableHolePunching()) |
Thanks!! But how could I provide a public relay server address so that my peer could perform the hole punching with another peer? I found this option to pass on the EnableHolePunching function and on it I can provide peer addrs info... do you know if thats it? libp2p.New(libp2p.EnableHolePunching(libp2p.EnableAutoRelayWithStaticRelays())) |
If you want to use a fixed Relay node address, you can write like this: var nodes []peer.AddrInfo
for _, s := range []string{"node1 info","node2 info"} {
addrInfo, err := peer.AddrInfoFromString(s)
if err != nil {
panic(err)
}
nodes = append(nodes, *addrInfo)
}
libp2p.New(libp2p.EnableAutoRelayWithStaticRelays(nodes), libp2p.EnableHolePunching()) |
@wlynxg What does the EnableHolePunching do? does it only create a Node that can perform the hole punching? Thank you for your responses btw! |
These things are all done automatically inside libp2p, so you only need to enable holepunch through |
Oh cool! so now, to connect peer A to B, I only need to implement some type of Discovery to find out B address, and when I try to connect to it, the hole drilling will be performed and the peers will connect? Do you know if I need first to find the public IP of peer B to perform the hole punching or, when I try to connect to it using the address with his private IP the holepunch module will take care of the rest? |
When a node is connected to the DHT network, the node will automatically exchange information with other nodes through the Identify protocol. In this process, the node will obtain its own public network egress address through information exchange. So you just need to first link nodes A and B to the DHT network, then node B then connects to a relay server, and then node A connects to node B through the relay node. Later, nodes A and B will automatically try the holepunch logic. |
Sorry to bother you again, but I'm trying to make the DHT work right now, and I already saw some examples, so I've been trying to implement it... I use this code to connect to some Default Bootstrap Peers: if err = kademliaDht.Bootstrap(ctx); err != nil {
logCallback(fmt.Sprintf("Failed to bootstrap the DHT: %s\n", err))
}
// Let's connect to the bootstrap nodes first. They will tell us about the
// other nodes in the network.
var wg sync.WaitGroup
for _, peerAddr := range dht.DefaultBootstrapPeers {
logCallback(fmt.Sprintf("Connecting to bootstrap node: %s\n", peerAddr))
peerinfo, _ := peer.AddrInfoFromP2pAddr(peerAddr)
wg.Add(1)
go func() {
defer wg.Done()
if err := h.Connect(ctx, *peerinfo); err != nil {
logCallback(fmt.Sprintf("Connection failed: %s\n", err))
} else {
logCallback(fmt.Sprintf("Connected to peer %s", peerinfo.ID))
}
}()
}
wg.Wait() after, if I try to open another console to run peer B, it will also connect to the Bootstrap peers and populate the DHT but if I try to find peer A on it by providing his peer ID it says that he can't find it. I don't know if I need to do something else so that peer A and B can find each other on the DHT. |
I'm not sure why it isn't working for you. From what I see it seems generally correct. Take a look at the chat with rendezvous example. It should be doing something similar. Also you could try using kubo to debug things. I find Kubo's |
For node A, you are missing the program to broadcast data to the DHT. You need to add the following code: import (
"context"
"io"
"log"
"net"
"github.com/libp2p/go-libp2p"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/discovery/routing"
"github.com/libp2p/go-libp2p/p2p/discovery/util"
)
func main() {
// the code you have implemented to connect to the DHT node
......
// you need to broadcast node A’s information to the DHT network here
discovery := routing.NewRoutingDiscovery(kademliaDht)
util.Advertise(ctx, discovery, h.ID().String())
select {}
} For node B, you can query the information of node A through the following code: import (
"context"
"io"
"log"
"net"
"github.com/libp2p/go-libp2p"
dht "github.com/libp2p/go-libp2p-kad-dht"
"github.com/libp2p/go-libp2p/core"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/discovery/routing"
"github.com/libp2p/go-libp2p/p2p/discovery/util"
)
func main() {
// the code you have implemented to connect to the DHT node
......
// query information about node A
discovery := routing.NewRoutingDiscovery(kademliaDht)
peerChan, err := routingDiscovery.FindPeers(ctx, "node A's ID")
if err != nil {
panic(err)
}
for peer := range peerChan {
......
}
} |
Still cant find peers... but I have a question about the query you showed. peerID, err := peer.Decode(destination)
if err != nil {
logCallback(fmt.Sprintf("Failed to decode peer ID: %s\n", err))
}
kademliaDht.FindPeer(contextVar, peerID) (this way also cant find the other peer) |
Are you using the code below to expose node information to DHT? discovery := routing.NewRoutingDiscovery(kademliaDht)
util.Advertise(ctx, discovery, h.ID().String()) |
When querying nodes, do you use peerID.String() or the original peerID? (Because peerID and peerID.String() values are different) |
After a lot of testing and trial and error, I GOT THE DHT WORKING :D! Thanks a lot, guys! Now I need to put the Hole Punching working... I'll come back when I have more questions... |
Let's continue on discussions. Closing this issue as there's nothing to do. |
@MarcoPolo @wlynxg @AfonsoBatista7 I tried modifying the Host A run: chat -listen /ip4/0.0.0.0/tcp/6666 -peer /ip4/public_ip/tcp/9876/p2p/12D3KooWP2soRwZSeaYabBvbRS76DNYzxqcKvimqKbMJRtHhNAra Host B run: chat -listen /ip4/0.0.0.0/tcp/6668 -peer /ip4/public_ip/tcp/9876/p2p/12D3KooWP2soRwZSeaYabBvbRS76DNYzxqcKvimqKbMJRtHhNAra Host A and Host B are in different LANs, that is, behind NAT. Here is my simple Bootstrap and Relay server code: relay1, err := libp2p.New(libp2p.ListenAddrStrings("/ip4/0.0.0.0/tcp/9876"))
if err != nil {
log.Printf("Failed to create relay1: %v", err)
return
}
_, err = relay.New(relay1, relay.WithInfiniteLimits())
if err != nil {
log.Printf("Failed to instantiate the relay: %v", err)
return
}
_, err = dht.New(context.Background(), relay1, dht.Mode(dht.ModeServer))
if err != nil {
log.Printf("Failed to create DHT: %v", err)
return
}
_, err = autonat.New(relay1)
if err != nil {
log.Printf("Failed to create AutoNAT: %v", err)
return
}
fmt.Printf("[*] Your Bootstrap ID Is: /ip4/%s/tcp/%v/p2p/%s\n", "0.0.0.0", 9876, relay1.ID().String())
select {} After running, I found that the hole punching did not work. Host A and Host B could find each other, but could not establish a connection. |
@iGwkang sourceMultiAddrTCP, _ := multiaddr.NewMultiaddr("/ip4/0.0.0.0/tcp/4001")
sourceMultiAddrUDP, _ := multiaddr.NewMultiaddr("/ip4/0.0.0.0/udp/4001/quic-v1")
// libp2p.New constructs a new libp2p Host.
// Other options can be added here.
return libp2p.New(
libp2p.ListenAddrs(sourceMultiAddrTCP, sourceMultiAddrUDP),
// Attempt to open ports using uPNP for NATed hosts.
libp2p.NATPortMap(),
libp2p.EnableHolePunching(),
libp2p.EnableNATService(),
libp2p.EnableRelayService(),
) I think the rest of your code is the same as mine |
Still can't connect successfully, please note that Host A and Host B are behind different firewalls and both are cone NAT. |
Sorry for the late reply... Can your host A and B dial the relay peer? |
@AfonsoBatista7 I have specified the relay node. Do you have any sample code that can hole punching properly for me to refer to? |
@iGwkang Hi have you solve this yet? i have the same problem |
@NanoRed Sorry, I have given up using go-libp2p. |
Is there currently any available NAT Transversal Hole Punching implementation example in Go? I saw it is in Rust but I didn't find it, in Go. If it doesn't exist yet, does someone have some recommendations or links on how I could implement one?
The text was updated successfully, but these errors were encountered: