forked from WireGuard/wgctrl-go
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.go
More file actions
136 lines (115 loc) · 3 KB
/
Copy pathclient.go
File metadata and controls
136 lines (115 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package wireguardctrl
import (
"io"
"os"
"runtime"
"github.com/mdlayher/wireguardctrl/internal/wgnl"
"github.com/mdlayher/wireguardctrl/internal/wguser"
"github.com/mdlayher/wireguardctrl/wgtypes"
)
// An osClient is the operating system-specific implementation of Client.
type wgClient interface {
io.Closer
Devices() ([]*wgtypes.Device, error)
Device(name string) (*wgtypes.Device, error)
ConfigureDevice(name string, cfg wgtypes.Config) error
}
// Expose an identical interface to the underlying packages.
var _ wgClient = &Client{}
// A Client provides access to WireGuard device information.
type Client struct {
// Seamlessly use different wgClient implementations to provide an interface
// similar to the wg(8).
cs []wgClient
}
// New creates a new Client.
func New() (*Client, error) {
cs, err := newClients()
if err != nil {
return nil, err
}
return &Client{
cs: cs,
}, nil
}
// newClients sets up various wgClients based on the current operating system
// and configuration.
func newClients() ([]wgClient, error) {
var cs []wgClient
// TODO(mdlayher): smarter detection logic than just the OS in use.
if runtime.GOOS == "linux" {
nlc, err := wgnl.New()
if err != nil {
return nil, err
}
// Netlink devices seem to appear first in wg(8).
cs = append(cs, nlc)
}
cfgc, err := wguser.New()
if err != nil {
return nil, err
}
cs = append(cs, cfgc)
return cs, nil
}
// Close releases resources used by a Client.
func (c *Client) Close() error {
for _, wgc := range c.cs {
if err := wgc.Close(); err != nil {
return err
}
}
return nil
}
// Devices retrieves all WireGuard devices on this system.
func (c *Client) Devices() ([]*wgtypes.Device, error) {
var out []*wgtypes.Device
for _, wgc := range c.cs {
devs, err := wgc.Devices()
if err != nil {
return nil, err
}
out = append(out, devs...)
}
return out, nil
}
// Device retrieves a WireGuard device by its interface name.
//
// If the device specified by name does not exist or is not a WireGuard device,
// an error is returned which can be checked using os.IsNotExist.
func (c *Client) Device(name string) (*wgtypes.Device, error) {
for _, wgc := range c.cs {
d, err := wgc.Device(name)
switch {
case err == nil:
return d, nil
case os.IsNotExist(err):
continue
default:
return nil, err
}
}
return nil, os.ErrNotExist
}
// ConfigureDevice configures a WireGuard device by its interface name.
//
// Because the zero value of some Go types may be significant to WireGuard for
// Config fields, only fields which are not nil will be applied when
// configuring a device.
//
// If the device specified by name does not exist or is not a WireGuard device,
// an error is returned which can be checked using os.IsNotExist.
func (c *Client) ConfigureDevice(name string, cfg wgtypes.Config) error {
for _, wgc := range c.cs {
err := wgc.ConfigureDevice(name, cfg)
switch {
case err == nil:
return nil
case os.IsNotExist(err):
continue
default:
return err
}
}
return os.ErrNotExist
}