add linux native wg interface

This commit is contained in:
mlsmaycon 2021-06-18 13:01:43 +02:00
parent e41fdedd5b
commit aa854c5899
4 changed files with 262 additions and 18 deletions

View File

@ -94,9 +94,9 @@ func (conn *Connection) Open(timeout time.Duration) error {
// create an ice.Agent that will be responsible for negotiating and establishing actual peer-to-peer connection // create an ice.Agent that will be responsible for negotiating and establishing actual peer-to-peer connection
a, err := ice.NewAgent(&ice.AgentConfig{ a, err := ice.NewAgent(&ice.AgentConfig{
MulticastDNSMode: ice.MulticastDNSModeQueryAndGather, // MulticastDNSMode: ice.MulticastDNSModeQueryAndGather,
NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4}, NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4},
Urls: conn.Config.StunTurnURLS, Urls: conn.Config.StunTurnURLS,
InterfaceFilter: func(s string) bool { InterfaceFilter: func(s string) bool {
if conn.Config.iFaceBlackList == nil { if conn.Config.iFaceBlackList == nil {
return true return true

View File

@ -1,15 +1,12 @@
// +build !linux
package iface package iface
import ( import (
"net"
"time"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/conn" "golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun" "golang.zx2c4.com/wireguard/tun"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
) )
const ( const (

View File

@ -0,0 +1,207 @@
package iface
import (
"net"
"time"
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)
const (
defaultMTU = 1280
)
// ConfigureWithKeyGen Extends the functionality of Configure(iface string, privateKey string) by generating a new Wireguard private key
func ConfigureWithKeyGen(iface string) (*wgtypes.Key, error) {
key, err := wgtypes.GeneratePrivateKey()
if err != nil {
return nil, err
}
return &key, Configure(iface, key.String())
}
// Configure configures a Wireguard interface
// The interface must exist before calling this method (e.g. call interface.Create() before)
func Configure(iface string, privateKey string) error {
log.Debugf("configuring Wireguard interface %s", iface)
wg, err := wgctrl.New()
if err != nil {
return err
}
defer wg.Close()
log.Debugf("adding Wireguard private key")
key, err := wgtypes.ParseKey(privateKey)
if err != nil {
return err
}
fwmark := 0
cfg := wgtypes.Config{
PrivateKey: &key,
ReplacePeers: false,
FirewallMark: &fwmark,
}
err = wg.ConfigureDevice(iface, cfg)
if err != nil {
return err
}
return nil
}
// GetListenPort returns the listening port of the Wireguard endpoint
func GetListenPort(iface string) (*int, error) {
log.Debugf("getting Wireguard listen port of interface %s", iface)
//discover Wireguard current configuration
wg, err := wgctrl.New()
if err != nil {
return nil, err
}
defer wg.Close()
d, err := wg.Device(iface)
if err != nil {
return nil, err
}
log.Debugf("got Wireguard device listen port %s, %d", iface, &d.ListenPort)
return &d.ListenPort, nil
}
// UpdateListenPort updates a Wireguard interface listen port
func UpdateListenPort(iface string, newPort int) error {
log.Debugf("updating Wireguard listen port of interface %s, new port %d", iface, newPort)
//discover Wireguard current configuration
wg, err := wgctrl.New()
if err != nil {
return err
}
defer wg.Close()
_, err = wg.Device(iface)
if err != nil {
return err
}
log.Debugf("got Wireguard device %s", iface)
config := wgtypes.Config{
ListenPort: &newPort,
ReplacePeers: false,
}
err = wg.ConfigureDevice(iface, config)
if err != nil {
return err
}
log.Debugf("updated Wireguard listen port of interface %s, new port %d", iface, newPort)
return nil
}
// UpdatePeer updates existing Wireguard Peer or creates a new one if doesn't exist
// Endpoint is optional
func UpdatePeer(iface string, peerKey string, allowedIps string, keepAlive time.Duration, endpoint string) error {
log.Debugf("updating interface %s peer %s: endpoint %s ", iface, peerKey, endpoint)
wg, err := wgctrl.New()
if err != nil {
return err
}
defer wg.Close()
_, err = wg.Device(iface)
if err != nil {
return err
}
log.Debugf("got Wireguard device %s", iface)
//parse allowed ips
_, ipNet, err := net.ParseCIDR(allowedIps)
if err != nil {
return err
}
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
if err != nil {
return err
}
peers := make([]wgtypes.PeerConfig, 0)
peer := wgtypes.PeerConfig{
PublicKey: peerKeyParsed,
ReplaceAllowedIPs: true,
AllowedIPs: []net.IPNet{*ipNet},
PersistentKeepaliveInterval: &keepAlive,
}
peers = append(peers, peer)
config := wgtypes.Config{
ReplacePeers: false,
Peers: peers,
}
err = wg.ConfigureDevice(iface, config)
if err != nil {
return err
}
if endpoint != "" {
return UpdatePeerEndpoint(iface, peerKey, endpoint)
}
return nil
}
// UpdatePeerEndpoint updates a Wireguard interface Peer with the new endpoint
// Used when NAT hole punching was successful and an update of the remote peer endpoint is required
func UpdatePeerEndpoint(iface string, peerKey string, newEndpoint string) error {
log.Debugf("updating peer %s endpoint %s ", peerKey, newEndpoint)
wg, err := wgctrl.New()
if err != nil {
return err
}
defer wg.Close()
_, err = wg.Device(iface)
if err != nil {
return err
}
log.Debugf("got Wireguard device %s", iface)
peerAddr, err := net.ResolveUDPAddr("udp4", newEndpoint)
if err != nil {
return err
}
log.Debugf("parsed peer endpoint [%s]", peerAddr.String())
peerKeyParsed, err := wgtypes.ParseKey(peerKey)
if err != nil {
return err
}
peers := make([]wgtypes.PeerConfig, 0)
peer := wgtypes.PeerConfig{
PublicKey: peerKeyParsed,
ReplaceAllowedIPs: false,
UpdateOnly: true,
Endpoint: peerAddr,
}
peers = append(peers, peer)
config := wgtypes.Config{
ReplacePeers: false,
Peers: peers,
}
err = wg.ConfigureDevice(iface, config)
if err != nil {
return err
}
return nil
}

View File

@ -3,24 +3,64 @@ package iface
import ( import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
"golang.zx2c4.com/wireguard/tun"
"os" "os"
) )
//const ( // Create Creates a new Wireguard interface, sets a given IP and brings it up.
// interfacePrefix = "wg" // Will reuse an existing one.
//) func Create(iface string, address string) error {
// assignAddr Adds IP address to the tunnel interface
func assignAddr(address string, tunDevice tun.Device) error {
var err error
attrs := netlink.NewLinkAttrs() attrs := netlink.NewLinkAttrs()
attrs.Name, err = tunDevice.Name() attrs.Name = iface
link := wgLink{
attrs: &attrs,
}
log.Debugf("adding device: %s", iface)
err := netlink.LinkAdd(&link)
if os.IsExist(err) {
log.Infof("interface %s already exists. Will reuse.", iface)
} else if err != nil {
return err
}
log.Debugf("adding address %s to interface: %s", address, iface)
addr, _ := netlink.ParseAddr(address)
err = netlink.AddrAdd(&link, addr)
if os.IsExist(err) {
log.Infof("interface %s already has the address: %s", iface, address)
} else if err != nil {
return err
}
err = assignAddr(address, iface)
if err != nil { if err != nil {
return err return err
} }
// todo do a discovery
log.Debugf("setting MTU: %s", iface)
err = netlink.LinkSetMTU(&link, defaultMTU)
if err != nil {
log.Errorf("error setting MTU on interface: %s", iface)
return err
}
log.Debugf("bringing up interface: %s", iface)
err = netlink.LinkSetUp(&link)
if err != nil {
log.Errorf("error bringing up interface: %s", iface)
return err
}
return nil
}
// assignAddr Adds IP address to the tunnel interface
func assignAddr(address, name string) error {
var err error
attrs := netlink.NewLinkAttrs()
attrs.Name = name
link := wgLink{ link := wgLink{
attrs: &attrs, attrs: &attrs,
} }