Created an example and improved the errors returned by the VPNService initialization.

This commit is contained in:
Guilherme Balena Versiani
2023-02-07 12:52:11 +00:00
parent deb0de7a06
commit 5eec1dcc15
4 changed files with 180 additions and 3 deletions

View File

@@ -1,6 +1,8 @@
package libp2pvpn
import (
"fmt"
"github.com/songgao/water"
)
@@ -42,7 +44,7 @@ func NewDevice(opts ...Option) (*Interface, error) {
err = setupLink(iface, cfg.LinkOptions)
if err != nil {
iface.Close()
return nil, err
return nil, fmt.Errorf("error while setting %s: %s", iface.Name(), err)
}
return &Interface{iface}, err

View File

@@ -57,11 +57,16 @@ func setupLink(iface *water.Interface, linkOpts LinkOptions) error {
if linkOpts.MTU != 0 {
err := ifconfig(iface.Name(), "mtu", fmt.Sprintf("%d", linkOpts.MTU))
if err != nil {
return err
return fmt.Errorf("error setting mtu: %s", err)
}
}
return ifconfig(iface.Name(), "inet", linkOpts.LocalAddress, linkOpts.RemoteAddress, "up")
err := ifconfig(iface.Name(), "inet", linkOpts.LocalAddress, linkOpts.RemoteAddress, "up")
if err != nil {
return fmt.Errorf("error bringing interface up: %s", err)
}
return nil
}
func ifconfig(args ...string) error {

39
libp2p-vpn/README.md Normal file
View File

@@ -0,0 +1,39 @@
# Simple VPN with go-libp2p-vpn
This is an example that quickly shows how to use the `go-libp2p-vpn` stack.
The app will start a local TUN interface and wait for a connection to the peer on the `/vpn/tun/1.0.0` protocol.
After connecting, the VPN is fully established.
## Build
From the `libp2p-vpn` directory run the following:
```
> cd libp2p-vpn
> go build
```
## Usage
First create two private keys, it will print the respective peer IDs:
```
> ./libp2p-vpn keygen -f peer1
peer ID: Qm..Ana
> ./libp2p-vpn keygen -f peer2
peer ID: Qm..Bob
```
On Mac, in a terminal do:
```
> sudo ./libp2p-vpn run -f peer1 -l /ip4/127.0.0.1/tcp/10000 -p /ip4/127.0.0.1/tcp/10001/p2p/Qm..Bob -t 10.0.0.1,10.0.0.2
```
then from another terminal:
```
> sudo ./libp2p-vpn run -f peer2 -l /ip4/127.0.0.1/tcp/10001 -p /ip4/127.0.0.1/tcp/10000/p2p/Qm..Ana -t 10.0.0.2,10.0.0.1
```

131
libp2p-vpn/main.go Normal file
View File

@@ -0,0 +1,131 @@
package main
import (
"context"
"flag"
"fmt"
"os"
"strings"
"time"
libp2pvpn "github.com/balena/go-libp2p-vpn"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
)
func main() {
keygenCmd := flag.NewFlagSet("keygen", flag.ExitOnError)
keygenFileF := keygenCmd.String("f", "", "Specifies the filename of the private key file")
keygenKeyTypeF := keygenCmd.String("t", "ecdsa", "Specifies the type of key to create. "+
"The possible values are \"ecdsa\", \"ed25519\", \"secp256k1\", or \"rsa\"")
runCmd := flag.NewFlagSet("run", flag.ExitOnError)
runPrivKeyF := runCmd.String("f", "", "Specifies the filename of the private key file")
runPeerF := runCmd.String("p", "", "Specifies the peer address")
runListenAddrsF := runCmd.String("l", "", "Specifies listen addresses")
runTunnelAddrsF := runCmd.String("t", "", "Specifies the tunnel addresses")
switch os.Args[1] {
case "keygen":
keygenCmd.Parse(os.Args[2:])
runKeyGen(*keygenKeyTypeF, *keygenFileF)
case "run":
runCmd.Parse(os.Args[2:])
tunnelAddrs := strings.Split(*runTunnelAddrsF, ",")
listenAddrs := strings.Split(*runListenAddrsF, ",")
run(*runPrivKeyF, *runPeerF, tunnelAddrs[0], tunnelAddrs[1], listenAddrs)
}
}
func runKeyGen(keyType, file string) {
var typ int
switch keyType {
case "ecdsa":
typ = crypto.ECDSA
case "ed25519":
typ = crypto.Ed25519
case "secp256k1":
typ = crypto.Secp256k1
default:
panic(fmt.Sprintf("Unknown key type '%s'", keyType))
}
privKey, pubKey, err := crypto.GenerateKeyPair(typ, 0)
if err != nil {
panic(err)
}
id, err := peer.IDFromPublicKey(pubKey)
if err != nil {
panic(err)
}
b, err := crypto.MarshalPrivateKey(privKey)
if err != nil {
panic(err)
}
err = os.WriteFile(file, b, 0600)
if err != nil {
panic(err)
}
fmt.Printf("peer ID: %s\n", id.Pretty())
}
func run(privKeyFile, peerStr, localAddr, remoteAddr string, listenAddrs []string) {
ctx := context.Background()
b, err := os.ReadFile(privKeyFile)
if err != nil {
panic(err)
}
privKey, err := crypto.UnmarshalPrivateKey(b)
if err != nil {
panic(err)
}
h, err := libp2p.New(
libp2p.ListenAddrStrings(listenAddrs...),
libp2p.Identity(privKey),
)
if err != nil {
panic(err)
}
peerAddr, err := ma.NewMultiaddr(peerStr)
if err != nil {
panic(err)
}
peerAddrInfo, err := peer.AddrInfoFromP2pAddr(peerAddr)
if err != nil {
panic(err)
}
vpn, err := libp2pvpn.New(
peerAddrInfo.ID,
libp2pvpn.TunnelIP(localAddr, remoteAddr),
)
if err != nil {
panic(err)
}
fmt.Printf("Trying to connect to %s\n", peerStr)
for {
err = h.Connect(ctx, *peerAddrInfo)
if err == nil {
break
}
time.Sleep(5 * time.Second)
}
fmt.Println("[x] Connection succeeded!")
h.SetStreamHandler(vpn.Protocol(), vpn.Handler())
vpn.Serve(ctx, h)
}