@@ -30,7 +30,7 @@ type Client struct {
30
30
// during tests.
31
31
close func () error
32
32
ioctlIfgroupreq func (ifg * wgh.Ifgroupreq ) error
33
- ioctlWGDataIO func (data * wgh.WGDataIO ) error
33
+ ioctlWGDataIO func (req uint , data * wgh.WGDataIO ) error
34
34
}
35
35
36
36
// New creates a new Client and returns whether or not the ioctl interface
@@ -122,7 +122,7 @@ func (c *Client) Device(name string) (*wgtypes.Device, error) {
122
122
// if it proves to be a concern.
123
123
var mem []byte
124
124
for {
125
- if err := c .ioctlWGDataIO (& data ); err != nil {
125
+ if err := c .ioctlWGDataIO (wgh . SIOCGWG , & data ); err != nil {
126
126
// ioctl functions always return a wrapped unix.Errno value.
127
127
// Conform to the wgctrl contract by unwrapping some values:
128
128
// ENXIO: "no such device": (no such WireGuard device)
@@ -223,14 +223,142 @@ func parseDevice(name string, ifio *wgh.WGInterfaceIO) (*wgtypes.Device, error)
223
223
224
224
// ConfigureDevice implements wginternal.Client.
225
225
func (c * Client ) ConfigureDevice (name string , cfg wgtypes.Config ) error {
226
- // Currently read-only: we must determine if a device belongs to this driver,
227
- // and if it does, return a sentinel so integration tests that configure a
228
- // device can be skipped.
229
- if _ , err := c .Device (name ); err != nil {
226
+ dname , err := deviceName (name )
227
+ if err != nil {
230
228
return err
231
229
}
232
230
233
- return wginternal .ErrReadOnly
231
+ var port uint16
232
+ var public wgtypes.Key
233
+ var private wgtypes.Key
234
+ var rtable int32
235
+
236
+ var flags uint8
237
+ if cfg .ReplacePeers {
238
+ flags |= wgh .WG_INTERFACE_REPLACE_PEERS
239
+ }
240
+ if cfg .FirewallMark != nil {
241
+ flags |= wgh .WG_INTERFACE_HAS_RTABLE
242
+ rtable = int32 (* cfg .FirewallMark )
243
+ }
244
+ if cfg .ListenPort != nil {
245
+ flags |= wgh .WG_INTERFACE_HAS_PORT
246
+ port = uint16 (* cfg .ListenPort )
247
+ }
248
+ if cfg .PrivateKey != nil {
249
+ flags |= wgh .WG_INTERFACE_HAS_PRIVATE
250
+ private = * cfg .PrivateKey
251
+ }
252
+
253
+ iface := wgh.WGInterfaceIO {
254
+ Peers_count : wgh .SizeT (len (cfg .Peers )),
255
+ Port : port ,
256
+ Rtable : rtable ,
257
+ Public : public ,
258
+ Private : private ,
259
+ Flags : flags ,
260
+ }
261
+
262
+ aipCount := 0
263
+ for _ , peer := range cfg .Peers {
264
+ aipCount += len (peer .AllowedIPs )
265
+ }
266
+
267
+ ioctlBuf := make ([]byte , wgh .SizeofWGInterfaceIO + len (cfg .Peers )* wgh .SizeofWGPeerIO + aipCount * wgh .SizeofWGAIPIO )
268
+ copy (ioctlBuf , (* (* [wgh .SizeofWGInterfaceIO ]byte )(unsafe .Pointer (& iface )))[:])
269
+
270
+ bufIdx := wgh .SizeofWGInterfaceIO
271
+
272
+ for _ , peer := range cfg .Peers {
273
+ var rawPeer wgh.WGPeerIO
274
+
275
+ rawPeer .Aips_count = wgh .SizeT (len (peer .AllowedIPs ))
276
+
277
+ if peer .Endpoint != nil {
278
+ if peer .Endpoint .IP .To4 () != nil {
279
+ rawAddr := unix.RawSockaddrInet4 {
280
+ Port : uint16 (bePort (uint16 (peer .Endpoint .Port ))),
281
+ Family : unix .AF_INET ,
282
+ Len : uint8 (unsafe .Sizeof (unix.RawSockaddrInet4 {})),
283
+ }
284
+ copy (rawAddr .Addr [:], peer .Endpoint .IP )
285
+ copy (rawPeer .Endpoint [:], (* (* [unsafe .Sizeof (rawAddr )]byte )(unsafe .Pointer (& rawAddr )))[:])
286
+ } else {
287
+ rawAddr := unix.RawSockaddrInet6 {
288
+ Port : uint16 (bePort (uint16 (peer .Endpoint .Port ))),
289
+ Family : unix .AF_INET6 ,
290
+ Len : uint8 (unsafe .Sizeof (unix.RawSockaddrInet6 {})),
291
+ }
292
+ copy (rawAddr .Addr [:], peer .Endpoint .IP )
293
+ copy (rawPeer .Endpoint [:], (* (* [unsafe .Sizeof (rawAddr )]byte )(unsafe .Pointer (& rawAddr )))[:])
294
+ }
295
+ rawPeer .Flags |= wgh .WG_PEER_HAS_ENDPOINT
296
+ }
297
+ if peer .PersistentKeepaliveInterval != nil {
298
+ rawPeer .Pka = uint16 (* peer .PersistentKeepaliveInterval )
299
+ rawPeer .Flags |= wgh .WG_PEER_HAS_PKA
300
+ }
301
+ if peer .PresharedKey != nil {
302
+ rawPeer .Psk = * peer .PresharedKey
303
+ rawPeer .Flags |= wgh .WG_PEER_HAS_PSK
304
+ }
305
+ rawPeer .Public = peer .PublicKey
306
+ rawPeer .Flags |= wgh .WG_PEER_HAS_PUBLIC
307
+
308
+ if peer .Remove {
309
+ rawPeer .Flags |= wgh .WG_PEER_REMOVE
310
+ }
311
+ if peer .ReplaceAllowedIPs {
312
+ rawPeer .Flags |= wgh .WG_PEER_REPLACE_AIPS
313
+ }
314
+ if peer .UpdateOnly {
315
+ // FIXME: not positive this flag is *only* update
316
+ rawPeer .Flags |= wgh .WG_PEER_UPDATE
317
+ }
318
+
319
+ rawPeer .Protocol_version = 1
320
+
321
+ copy (ioctlBuf [bufIdx :], (* (* [wgh .SizeofWGPeerIO ]byte )(unsafe .Pointer (& rawPeer )))[:])
322
+ bufIdx += wgh .SizeofWGPeerIO
323
+
324
+ for _ , aip := range peer .AllowedIPs {
325
+ var rawAip wgh.WGAIPIO
326
+ if v4 := aip .IP .To4 (); v4 != nil {
327
+ rawAip .Af = unix .AF_INET
328
+ copy (rawAip .Addr [:net .IPv4len ], v4 )
329
+ } else {
330
+ rawAip .Af = unix .AF_INET6
331
+ rawAip .Addr = [net .IPv6len ]byte (aip .IP )
332
+ }
333
+ ones , _ := aip .Mask .Size ()
334
+ rawAip .Cidr = int32 (ones )
335
+
336
+ copy (ioctlBuf [bufIdx :], (* (* [wgh .SizeofWGAIPIO ]byte )(unsafe .Pointer (& rawAip )))[:])
337
+ bufIdx += wgh .SizeofWGAIPIO
338
+ }
339
+
340
+ }
341
+
342
+ data := wgh.WGDataIO {
343
+ Name : dname ,
344
+ Size : wgh .SizeT (len (ioctlBuf )),
345
+ Interface : (* wgh .WGInterfaceIO )(unsafe .Pointer (& ioctlBuf [0 ])),
346
+ }
347
+ if err := c .ioctlWGDataIO (wgh .SIOCSWG , & data ); err != nil {
348
+ // ioctl functions always return a wrapped unix.Errno value.
349
+ // Conform to the wgctrl contract by unwrapping some values:
350
+ // ENXIO: "no such device": (no such WireGuard device)
351
+ // EINVAL: "inappropriate ioctl for device" (device is not a
352
+ // WireGuard device)
353
+ switch err .(* os.SyscallError ).Err {
354
+ case unix .ENXIO , unix .EINVAL :
355
+ return os .ErrNotExist
356
+ default :
357
+ return err
358
+ }
359
+ }
360
+
361
+ return nil
234
362
}
235
363
236
364
// deviceName converts an interface name string to the format required to pass
@@ -350,9 +478,9 @@ func ioctlIfgroupreq(fd int) func(*wgh.Ifgroupreq) error {
350
478
351
479
// ioctlWGDataIO returns a function which performs the appropriate ioctl on
352
480
// fd to issue a WireGuard data I/O.
353
- func ioctlWGDataIO (fd int ) func (* wgh.WGDataIO ) error {
354
- return func (data * wgh.WGDataIO ) error {
355
- return ioctl (fd , wgh . SIOCGWG , unsafe .Pointer (data ))
481
+ func ioctlWGDataIO (fd int ) func (uint , * wgh.WGDataIO ) error {
482
+ return func (req uint , data * wgh.WGDataIO ) error {
483
+ return ioctl (fd , req , unsafe .Pointer (data ))
356
484
}
357
485
}
358
486
0 commit comments