@@ -30,7 +30,7 @@ type Client struct {
3030 // during tests.
3131 close func () error
3232 ioctlIfgroupreq func (ifg * wgh.Ifgroupreq ) error
33- ioctlWGDataIO func (data * wgh.WGDataIO ) error
33+ ioctlWGDataIO func (req uint , data * wgh.WGDataIO ) error
3434}
3535
3636// 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) {
122122 // if it proves to be a concern.
123123 var mem []byte
124124 for {
125- if err := c .ioctlWGDataIO (& data ); err != nil {
125+ if err := c .ioctlWGDataIO (wgh . SIOCGWG , & data ); err != nil {
126126 // ioctl functions always return a wrapped unix.Errno value.
127127 // Conform to the wgctrl contract by unwrapping some values:
128128 // ENXIO: "no such device": (no such WireGuard device)
@@ -223,14 +223,142 @@ func parseDevice(name string, ifio *wgh.WGInterfaceIO) (*wgtypes.Device, error)
223223
224224// ConfigureDevice implements wginternal.Client.
225225func (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 {
230228 return err
231229 }
232230
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
234362}
235363
236364// deviceName converts an interface name string to the format required to pass
@@ -350,9 +478,9 @@ func ioctlIfgroupreq(fd int) func(*wgh.Ifgroupreq) error {
350478
351479// ioctlWGDataIO returns a function which performs the appropriate ioctl on
352480// 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 ))
356484 }
357485}
358486
0 commit comments