Skip to content
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

feature: initial implementation of avoiding local proxy if peers are … #36

Merged
merged 14 commits into from
Jun 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions connection/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
ice "github.com/pion/ice/v2"
log "github.com/sirupsen/logrus"
"github.com/wiretrustee/wiretrustee/iface"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"sync"
"time"
Expand Down Expand Up @@ -93,6 +94,7 @@ 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
a, err := ice.NewAgent(&ice.AgentConfig{
// MulticastDNSMode: ice.MulticastDNSModeQueryAndGather,
NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4},
Urls: conn.Config.StunTurnURLS,
InterfaceFilter: func(s string) bool {
Expand Down Expand Up @@ -144,10 +146,23 @@ func (conn *Connection) Open(timeout time.Duration) error {
return err
}

err = conn.wgProxy.Start(remoteConn)
pair, err := conn.agent.GetSelectedCandidatePair()
if err != nil {
return err
}
// in case the remote peer is in the local network we don't need a Wireguard proxy, direct communication is possible.
if pair.Local.Type() == ice.CandidateTypeHost && pair.Remote.Type() == ice.CandidateTypeHost {
log.Debugf("remote peer %s is in the local network with an address %s", conn.Config.RemoteWgKey.String(), pair.Remote.Address())
err = conn.wgProxy.StartLocal(fmt.Sprintf("%s:%d", pair.Remote.Address(), iface.WgPort))
if err != nil {
return err
}
} else {
err = conn.wgProxy.Start(remoteConn)
if err != nil {
return err
}
}

log.Infof("opened connection to peer %s", conn.Config.RemoteWgKey.String())
case <-time.After(timeout):
Expand Down Expand Up @@ -298,7 +313,6 @@ func (conn *Connection) listenOnConnectionStateChanges() error {
}
log.Infof("will connect to peer %s via a selected connnection candidate pair %s", conn.Config.RemoteWgKey.String(), pair)
} else if state == ice.ConnectionStateDisconnected || state == ice.ConnectionStateFailed {
// todo do we really wanna have a connection restart within connection itself? Think of moving it outside
err := conn.Close()
if err != nil {
log.Warnf("error while closing connection to peer %s -> %s", conn.Config.RemoteWgKey.String(), err.Error())
Expand Down
9 changes: 9 additions & 0 deletions connection/wgproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ func (p *WgProxy) Close() error {
return nil
}

func (p *WgProxy) StartLocal(host string) error {
err := iface.UpdatePeer(p.iface, p.remoteKey, p.allowedIps, DefaultWgKeepAlive, host)
if err != nil {
log.Errorf("error while configuring Wireguard peer [%s] %s", p.remoteKey, err.Error())
return err
}
return nil
}

// Start starts a new proxy using the ICE connection
func (p *WgProxy) Start(remoteConn *ice.Conn) error {

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/vishvananda/netlink v1.1.0
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf
golang.org/x/sys v0.0.0-20210510120138-977fb7262007
golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5
golang.zx2c4.com/wireguard/windows v0.3.14
Expand Down
16 changes: 8 additions & 8 deletions iface/iface.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
package iface

import (
"net"
"time"

log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun"
"golang.zx2c4.com/wireguard/wgctrl"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"net"
"time"
)

const (
defaultMTU = 1280
WgPort = 51820
)

// Saves tun device object - is it required?
var tunIface tun.Device

// Create Creates a new Wireguard interface, sets a given IP and brings it up.
// Will reuse an existing one.
func Create(iface string, address string) error {
// CreateWithUserspace Creates a new Wireguard interface, using wireguard-go userspace implementation
func CreateWithUserspace(iface string, address string) error {
var err error
tunIface, err = tun.CreateTUN(iface, defaultMTU)
if err != nil {
Expand Down Expand Up @@ -52,7 +50,7 @@ func Create(iface string, address string) error {

log.Debugln("UAPI listener started")

err = assignAddr(address, tunIface)
err = assignAddr(address, iface)
if err != nil {
return err
}
Expand Down Expand Up @@ -85,10 +83,12 @@ func Configure(iface string, privateKey string) error {
return err
}
fwmark := 0
p := WgPort
cfg := wgtypes.Config{
PrivateKey: &key,
ReplacePeers: false,
FirewallMark: &fwmark,
ListenPort: &p,
}
err = wg.ConfigureDevice(iface, cfg)
if err != nil {
Expand Down
11 changes: 5 additions & 6 deletions iface/iface_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@ package iface

import (
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/tun"
"net"
"os/exec"
"strings"
)

//const (
// interfacePrefix = "utun"
//)
// Create Creates a new Wireguard interface, sets a given IP and brings it up.
func Create(iface string, address string) error {
return CreateWithUserspace(iface, address)
}

// assignAddr Adds IP address to the tunnel interface and network route based on the range provided
func assignAddr(address string, tunDevice tun.Device) error {
ifaceName, err := tunDevice.Name()
func assignAddr(address string, ifaceName string) error {
ip := strings.Split(address, "/")
cmd := exec.Command("ifconfig", ifaceName, "inet", address, ip[0])
if out, err := cmd.CombinedOutput(); err != nil {
Expand Down
70 changes: 61 additions & 9 deletions iface/iface_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,76 @@ package iface
import (
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
"golang.zx2c4.com/wireguard/tun"

"os"
)

//const (
// interfacePrefix = "wg"
//)
// Create Creates a new Wireguard interface, sets a given IP and brings it up.
// 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
if WireguardModExists() {
log.Debug("using kernel Wireguard module")
return CreateWithKernel(iface, address)
} else {
return CreateWithUserspace(iface, address)
}
}

// CreateWithKernel Creates a new Wireguard interface using kernel Wireguard module.
// Works for Linux and offers much better network performance
func CreateWithKernel(iface string, address string) error {
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 {
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{
attrs: &attrs,
}
Expand Down
13 changes: 9 additions & 4 deletions iface/iface_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,21 @@ import (
"net"
)

// Create Creates a new Wireguard interface, sets a given IP and brings it up.
func Create(iface string, address string) error {
return CreateWithUserspace(iface, address)
}

// assignAddr Adds IP address to the tunnel interface and network route based on the range provided
func assignAddr(address string, tunDevice tun.Device) error {
ifaceName, err := tunDevice.Name()
nativeTunDevice := tunDevice.(*tun.NativeTun)
func assignAddr(address string, ifaceName string) error {

nativeTunDevice := tunIface.(*tun.NativeTun)
luid := winipcfg.LUID(nativeTunDevice.LUID())

ip, ipnet, _ := net.ParseCIDR(address)

log.Debugf("adding address %s to interface: %s", address, ifaceName)
err = luid.SetIPAddresses([]net.IPNet{{ip, ipnet.Mask}})
err := luid.SetIPAddresses([]net.IPNet{{ip, ipnet.Mask}})
if err != nil {
return err
}
Expand Down
Loading