Skip to content

Commit

Permalink
internal/wglinux: gracefully degrade if kernel implementation not ava…
Browse files Browse the repository at this point in the history
…ilable
  • Loading branch information
mdlayher committed May 15, 2019
1 parent 457d546 commit 11aeee2
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 13 deletions.
19 changes: 13 additions & 6 deletions internal/wglinux/client_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,29 @@ type Client struct {
interfaces func() ([]string, error)
}

// New creates a new Client.
func New() (*Client, error) {
// New creates a new Client and returns whether or not the generic netlink
// interface is available.
func New() (*Client, bool, error) {
c, err := genetlink.Dial(nil)
if err != nil {
return nil, err
return nil, false, err
}

return initClient(c)
}

// initClient is the internal Client constructor used in some tests.
func initClient(c *genetlink.Conn) (*Client, error) {
func initClient(c *genetlink.Conn) (*Client, bool, error) {
f, err := c.GetFamily(wgh.GenlName)
if err != nil {
_ = c.Close()
return nil, err

if netlink.IsNotExist(err) {
// The generic netlink interface is not available.
return nil, false, nil
}

return nil, false, err
}

return &Client{
Expand All @@ -50,7 +57,7 @@ func initClient(c *genetlink.Conn) (*Client, error) {

// By default, gather only WireGuard interfaces using rtnetlink.
interfaces: rtnlInterfaces,
}, nil
}, true, nil
}

// Close implements wginternal.Client.
Expand Down
26 changes: 24 additions & 2 deletions internal/wglinux/client_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,14 @@ func TestLinuxClientIsPermission(t *testing.T) {
t.Skip("skipping, test must be run without elevated privileges")
}

c, err := New()
c, ok, err := New()
if err != nil {
t.Fatalf("failed to create Client: %v", err)
}
if !ok {
t.Skip("skipping, the WireGuard generic netlink API is not available")
}

defer c.Close()

// Check for permission denied as unprivileged user.
Expand All @@ -143,6 +147,21 @@ func TestLinuxClientIsPermission(t *testing.T) {
}
}

func Test_initClientNotExist(t *testing.T) {
conn := genltest.Dial(func(_ genetlink.Message, _ netlink.Message) ([]genetlink.Message, error) {
// Simulate genetlink family not found.
return nil, genltest.Error(int(unix.ENOENT))
})

_, ok, err := initClient(conn)
if err != nil {
t.Fatalf("failed to open Client: %v", err)
}
if ok {
t.Fatal("the generic netlink API should not be available from genltest")
}
}

func Test_parseRTNLInterfaces(t *testing.T) {
// marshalAttrs creates packed netlink attributes with a prepended ifinfomsg
// structure, as returned by rtnetlink.
Expand Down Expand Up @@ -266,10 +285,13 @@ func testClient(t *testing.T, fn genltest.Func) *Client {

conn := genltest.Dial(genltest.ServeFamily(family, fn))

c, err := initClient(conn)
c, ok, err := initClient(conn)
if err != nil {
t.Fatalf("failed to open Client: %v", err)
}
if !ok {
t.Fatal("the generic netlink API was not available from genltest")
}

c.interfaces = func() ([]string, error) {
return []string{okName}, nil
Expand Down
17 changes: 12 additions & 5 deletions os_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,26 @@ import (

// newClients configures wginternal.Clients for Linux systems.
func newClients() ([]wginternal.Client, error) {
// Linux has an in-kernel WireGuard implementation.
nlc, err := wglinux.New()
var clients []wginternal.Client

// Linux has an in-kernel WireGuard implementation. Determine if it is
// available and make use of it if so.
kc, ok, err := wglinux.New()
if err != nil {
return nil, err
}
if ok {
clients = append(clients, kc)
}

// Although it isn't recommended to use userspace implementations on Linux,
// it can be used. We make use of it in integration tests as well.
cfgc, err := wguser.New()
uc, err := wguser.New()
if err != nil {
return nil, err
}

// Netlink devices seem to appear first in wg(8).
return []wginternal.Client{nlc, cfgc}, nil
// Kernel devices seem to appear first in wg(8).
clients = append(clients, uc)
return clients, nil
}

0 comments on commit 11aeee2

Please sign in to comment.