mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
97 lines
2.1 KiB
Go
97 lines
2.1 KiB
Go
package tunnel
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"golang.zx2c4.com/wireguard/conn"
|
|
"golang.zx2c4.com/wireguard/device"
|
|
"golang.zx2c4.com/wireguard/tun/netstack"
|
|
"net"
|
|
"net/netip"
|
|
"time"
|
|
"github.com/psviderski/uncloud/internal/secret"
|
|
)
|
|
|
|
const (
|
|
DefaultEndpointPort = 51820
|
|
// DefaultKeepaliveInterval is sensible interval that works with a wide variety of firewalls.
|
|
DefaultKeepaliveInterval = 25 * time.Second
|
|
)
|
|
|
|
type Tunnel struct {
|
|
dev *device.Device
|
|
net *netstack.Net
|
|
}
|
|
|
|
type Config struct {
|
|
LocalAddress netip.Addr
|
|
LocalPrivateKey secret.Secret
|
|
Endpoint netip.AddrPort
|
|
RemotePublicKey secret.Secret
|
|
RemoteNetwork netip.Prefix
|
|
DNS *netip.Addr
|
|
MTU int
|
|
KeepAlive time.Duration
|
|
}
|
|
|
|
func Connect(config *Config) (*Tunnel, error) {
|
|
var dns netip.Addr
|
|
if config.DNS != nil {
|
|
dns = *config.DNS
|
|
} else {
|
|
dns = netip.MustParseAddr("1.1.1.1")
|
|
}
|
|
mtu := config.MTU
|
|
if mtu == 0 {
|
|
mtu = device.DefaultMTU
|
|
}
|
|
keepAlive := config.KeepAlive
|
|
if keepAlive == 0 {
|
|
keepAlive = DefaultKeepaliveInterval
|
|
}
|
|
|
|
tun, tnet, err := netstack.CreateNetTUN([]netip.Addr{config.LocalAddress}, []netip.Addr{dns}, mtu)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create WireGuard TUN device: %w", err)
|
|
}
|
|
|
|
dev := device.NewDevice(tun, conn.NewDefaultBind(), device.NewLogger(device.LogLevelError, "WireGuard tunnel: "))
|
|
conf := fmt.Sprintf(
|
|
"private_key=%s\n"+
|
|
"public_key=%s\n"+
|
|
"endpoint=%s\n"+
|
|
"allowed_ip=%s\n"+
|
|
"persistent_keepalive_interval=%d\n",
|
|
config.LocalPrivateKey.String(),
|
|
config.RemotePublicKey.String(),
|
|
config.Endpoint.String(),
|
|
config.RemoteNetwork.String(),
|
|
int(keepAlive.Seconds()),
|
|
)
|
|
err = dev.IpcSet(conf)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("configure WireGuard device: %w", err)
|
|
}
|
|
|
|
err = dev.Up()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("enable WireGuard device: %w", err)
|
|
}
|
|
|
|
return &Tunnel{
|
|
dev: dev,
|
|
net: tnet,
|
|
}, nil
|
|
}
|
|
|
|
func (t *Tunnel) Close() {
|
|
if t.dev != nil {
|
|
t.dev.Close()
|
|
}
|
|
t.dev, t.net = nil, nil
|
|
}
|
|
|
|
func (t *Tunnel) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
|
return t.net.DialContext(ctx, network, address)
|
|
}
|