Skip to content

Commit

Permalink
refactored services
Browse files Browse the repository at this point in the history
  • Loading branch information
Place1 committed Oct 26, 2019
1 parent bb43e8b commit 524662d
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 77 deletions.
3 changes: 2 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import (
)

type AppConfig struct {
Web struct {
Mode string
Web struct {
// ExternalAddress is the address that
// clients should use to connect to this
// server. It will be used in generated
Expand Down
5 changes: 2 additions & 3 deletions internal/services/manager.go → internal/services/devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/pkg/errors"
"github.com/place1/wireguard-access-server/internal/storage"
"github.com/place1/wireguard-access-server/internal/wg"
"github.com/sirupsen/logrus"
)

Expand All @@ -25,11 +24,11 @@ func nextPeerID() int {
}

type DeviceManager struct {
wgserver *wg.Server
wgserver *WireGuard
storage storage.Storage
}

func NewDeviceManager(w *wg.Server, s storage.Storage) *DeviceManager {
func NewDeviceManager(w *WireGuard, s storage.Storage) *DeviceManager {
return &DeviceManager{w, s}
}

Expand Down
49 changes: 49 additions & 0 deletions internal/services/network.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package services

import (
"github.com/coreos/go-iptables/iptables"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
)

func ConfigureRouting(wgIface string) error {
// Networking configuration (ip links and route tables)
// to ensure that network traffic in the VPN subnet
// moves through the wireguard interface
link, err := netlink.LinkByName(wgIface)
if err != nil {
return errors.Wrap(err, "failed to find wireguard interface")
}
addr, err := netlink.ParseAddr("10.0.0.1/24")
if err != nil {
return errors.Wrap(err, "failed to parse subnet address")
}
if err := netlink.AddrAdd(link, addr); err != nil {
logrus.Warn(errors.Wrap(err, "failed to add subnet to wireguard interface"))
}
if err := netlink.LinkSetUp(link); err != nil {
logrus.Warn(errors.Wrap(err, "failed to bring wireguard interface up"))
}
return nil
}

func ConfigureForwarding(wgIface string, gatewayIface string) error {
// Networking configuration (iptables) configuration
// to ensure that traffic from clients the wireguard interface
// is sent to the provided network interface
ipt, err := iptables.New()
if err != nil {
return errors.Wrap(err, "failed to init iptables")
}
if err := ipt.AppendUnique("filter", "FORWARD", "-s", "10.0.0.1/24", "-o", wgIface, "-j", "ACCEPT"); err != nil {
return errors.Wrap(err, "failed to set ip tables rule")
}
if err := ipt.AppendUnique("filter", "FORWARD", "-s", "10.0.0.1/24", "-i", wgIface, "-j", "ACCEPT"); err != nil {
return errors.Wrap(err, "failed to set ip tables rule")
}
if err := ipt.AppendUnique("nat", "POSTROUTING", "-s", "10.0.0.1/24", "-o", gatewayIface, "-j", "MASQUERADE"); err != nil {
return errors.Wrap(err, "failed to set ip tables rule")
}
return nil
}
30 changes: 15 additions & 15 deletions internal/wg/server.go → internal/services/wireguard.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package wg
package services

import (
"fmt"
Expand All @@ -12,7 +12,7 @@ import (
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
)

type Server struct {
type WireGuard struct {
client *wgctrl.Client
iface string
externalName string
Expand All @@ -21,7 +21,7 @@ type Server struct {
lock sync.Mutex
}

func New(iface string, privateKey string, port int, externalName string) (*Server, error) {
func NewWireGuard(iface string, privateKey string, port int, externalName string) (*WireGuard, error) {
// wgctrl.New() will search for a kernel implementation
// of wireguard, then user implementations
// user implementations are found in /var/run/wireguard/<iface>.sock
Expand All @@ -34,7 +34,7 @@ func New(iface string, privateKey string, port int, externalName string) (*Serve
if err != nil {
return nil, errors.Wrap(err, "bad private key format")
}
server := &Server{
server := &WireGuard{
client: client,
iface: iface,
port: port,
Expand All @@ -52,7 +52,7 @@ func New(iface string, privateKey string, port int, externalName string) (*Serve
return server, nil
}

func (s *Server) AddPeer(publicKey string, addressCIDR string) error {
func (s *WireGuard) AddPeer(publicKey string, addressCIDR string) error {
logrus.
WithField("publicKey", publicKey).
WithField("address", addressCIDR).
Expand Down Expand Up @@ -80,15 +80,15 @@ func (s *Server) AddPeer(publicKey string, addressCIDR string) error {
})
}

func (s *Server) ListPeers() ([]wgtypes.Peer, error) {
func (s *WireGuard) ListPeers() ([]wgtypes.Peer, error) {
d, err := s.Device()
if err != nil {
return nil, err
}
return d.Peers, nil
}

func (s *Server) Peer(publicKey string) (*wgtypes.Peer, error) {
func (s *WireGuard) Peer(publicKey string) (*wgtypes.Peer, error) {
peers, err := s.ListPeers()
if err != nil {
return nil, err
Expand All @@ -101,7 +101,7 @@ func (s *Server) Peer(publicKey string) (*wgtypes.Peer, error) {
return nil, fmt.Errorf("peer with public key '%s' not found", publicKey)
}

func (s *Server) HasPeer(publicKey string) bool {
func (s *WireGuard) HasPeer(publicKey string) bool {
peers, err := s.ListPeers()
if err != nil {
logrus.Error(errors.Wrap(err, "failed to list peers"))
Expand All @@ -115,7 +115,7 @@ func (s *Server) HasPeer(publicKey string) bool {
return false
}

func (s *Server) RemovePeer(publicKey string) error {
func (s *WireGuard) RemovePeer(publicKey string) error {
logrus.WithField("publicKey", publicKey).Debug("removing peer")
key, err := wgtypes.ParseKey(publicKey)
if err != nil {
Expand All @@ -133,27 +133,27 @@ func (s *Server) RemovePeer(publicKey string) error {
})
}

func (s *Server) PublicKey() string {
func (s *WireGuard) PublicKey() string {
return s.publicKey.String()
}

func (s *Server) Endpoint() string {
func (s *WireGuard) Endpoint() string {
return fmt.Sprintf("%s:%d", s.externalName, s.port)
}

func (s *Server) DNS() string {
func (s *WireGuard) DNS() string {
return "1.1.1.1, 8.8.8.8" // TODO: dns stuff
}

func (s *Server) Device() (*wgtypes.Device, error) {
func (s *WireGuard) Device() (*wgtypes.Device, error) {
return s.client.Device(s.iface)
}

func (s *Server) Close() error {
func (s *WireGuard) Close() error {
return s.client.Close()
}

func (s *Server) configure(cb func(*wgtypes.Config) error) error {
func (s *WireGuard) configure(cb func(*wgtypes.Config) error) error {
s.lock.Lock()
defer s.lock.Unlock()
next := wgtypes.Config{}
Expand Down
41 changes: 41 additions & 0 deletions internal/services/wireguard_userspace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package services

import (
"os/exec"

"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)

func ExecUserWireGuard(wgcommand string, ifaceName string) error {
logrus.Infof("using userspace wireguard implementation %s", wgcommand)

// create the command to exec
// if it's "boringtun" we'll provide some non-standard
// flags to better support running within a docker container
var cmd *exec.Cmd
if wgcommand == "boringtun" {
cmd = exec.Command(
wgcommand,
ifaceName,
"--disable-drop-privileges=root",
"--foreground",
)
} else {
cmd = exec.Command(
wgcommand,
"-f",
ifaceName,
)
}

entry := logrus.NewEntry(logrus.New()).WithField("process", wgcommand)
cmd.Stdout = entry.Writer()
cmd.Stderr = entry.Writer()
logrus.Infof("starting %s", cmd.String())
if err := cmd.Run(); err != nil {
return errors.Wrap(err, "userspace wireguard exitted")
}

return nil
}
68 changes: 10 additions & 58 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,15 @@ package main
import (
"fmt"
"net/http"
"os/exec"
"time"

"github.com/coreos/go-iptables/iptables"

"github.com/vishvananda/netlink"

"github.com/gorilla/mux"

"github.com/pkg/errors"
"github.com/place1/wireguard-access-server/internal/config"
"github.com/place1/wireguard-access-server/internal/services"
"github.com/place1/wireguard-access-server/internal/storage"
"github.com/place1/wireguard-access-server/internal/web"
"github.com/place1/wireguard-access-server/internal/wg"
"github.com/sirupsen/logrus"
)

Expand All @@ -27,31 +21,12 @@ func main() {
// Userspace wireguard command
if config.WireGuard.UserspaceImplementation != "" {
go func() {
logrus.Infof("using userspace wireguard implementation %s", config.WireGuard.UserspaceImplementation)
var command *exec.Cmd
if config.WireGuard.UserspaceImplementation == "boringtun" {
command = exec.Command(
config.WireGuard.UserspaceImplementation,
config.WireGuard.InterfaceName,
"--disable-drop-privileges=root",
"--foreground",
)
} else {
command = exec.Command(
config.WireGuard.UserspaceImplementation,
"-f",
config.WireGuard.InterfaceName,
)
}
entry := logrus.NewEntry(logrus.New()).WithField("process", config.WireGuard.UserspaceImplementation)
command.Stdout = entry.Writer()
command.Stderr = entry.Writer()
logrus.Infof("starting %s", command.String())
if err := command.Run(); err != nil {
logrus.Fatal(errors.Wrap(err, "userspace wireguard exitted"))
// execute the userspace wireguard implementation
// if it exists/crashes for some reason then we'll also crash
if err := services.ExecUserWireGuard(config.WireGuard.UserspaceImplementation, config.WireGuard.InterfaceName); err != nil {
logrus.Fatal(err)
}
}()

// Wait for the userspace wireguard process to
// startup and create the wg0 interface
// Super sorry if this just caused a race
Expand All @@ -60,7 +35,7 @@ func main() {
}

// WireGuard
wgserver, err := wg.New(
wgserver, err := services.NewWireGuard(
config.WireGuard.InterfaceName,
config.WireGuard.PrivateKey,
config.WireGuard.Port,
Expand All @@ -73,36 +48,13 @@ func main() {
logrus.Infof("wireguard server public key is %s", wgserver.PublicKey())
logrus.Infof("wireguard endpoint is %s", wgserver.Endpoint())

// Networking configuration (ip links and route tables)
link, err := netlink.LinkByName(config.WireGuard.InterfaceName)
if err != nil {
logrus.Fatal(errors.Wrap(err, "failed to find wireguard interface"))
}
addr, err := netlink.ParseAddr("10.0.0.1/24")
if err != nil {
logrus.Fatal(errors.Wrap(err, "failed to parse subnet address"))
// Networking configuration
if err := services.ConfigureRouting(config.WireGuard.InterfaceName); err != nil {
logrus.Fatal(err)
}
if err := netlink.AddrAdd(link, addr); err != nil {
logrus.Warn(errors.Wrap(err, "failed to add subnet to wireguard interface"))
}
if err := netlink.LinkSetUp(link); err != nil {
logrus.Warn(errors.Wrap(err, "failed to bring wireguard interface up"))
}

// Networking configuration (iptables)
if config.VPN.GatewayInterface != nil {
ipt, err := iptables.New()
if err != nil {
logrus.Fatal(errors.Wrap(err, "failed to init iptables"))
}
if err := ipt.AppendUnique("filter", "FORWARD", "-s", "10.0.0.1/24", "-o", config.WireGuard.InterfaceName, "-j", "ACCEPT"); err != nil {
logrus.Fatal(errors.Wrap(err, "failed to set ip tables rule"))
}
if err := ipt.AppendUnique("filter", "FORWARD", "-s", "10.0.0.1/24", "-i", config.WireGuard.InterfaceName, "-j", "ACCEPT"); err != nil {
logrus.Fatal(errors.Wrap(err, "failed to set ip tables rule"))
}
if err := ipt.AppendUnique("nat", "POSTROUTING", "-s", "10.0.0.1/24", "-o", config.VPN.GatewayInterface.Attrs().Name, "-j", "MASQUERADE"); err != nil {
logrus.Fatal(errors.Wrap(err, "failed to set ip tables rule"))
if err := services.ConfigureForwarding(config.WireGuard.InterfaceName, config.VPN.GatewayInterface.Attrs().Name); err != nil {
logrus.Fatal(err)
}
}

Expand Down

0 comments on commit 524662d

Please sign in to comment.