mirror of
https://github.com/balena/go-libp2p-vpn.git
synced 2025-12-24 10:30:55 +08:00
Created an example and improved the errors returned by the VPNService initialization.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
39
libp2p-vpn/README.md
Normal 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
131
libp2p-vpn/main.go
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user