uapi.go raw

   1  /* SPDX-License-Identifier: MIT
   2   *
   3   * Copyright (C) 2017-2025 WireGuard LLC. All Rights Reserved.
   4   */
   5  
   6  package device
   7  
   8  import (
   9  	"bufio"
  10  	"bytes"
  11  	"errors"
  12  	"fmt"
  13  	"io"
  14  	"net"
  15  	"net/netip"
  16  	"strconv"
  17  	"strings"
  18  	"sync"
  19  	"time"
  20  
  21  	"golang.zx2c4.com/wireguard/ipc"
  22  )
  23  
  24  type IPCError struct {
  25  	code int64 // error code
  26  	err  error // underlying/wrapped error
  27  }
  28  
  29  func (s IPCError) Error() string {
  30  	return fmt.Sprintf("IPC error %d: %v", s.code, s.err)
  31  }
  32  
  33  func (s IPCError) Unwrap() error {
  34  	return s.err
  35  }
  36  
  37  func (s IPCError) ErrorCode() int64 {
  38  	return s.code
  39  }
  40  
  41  func ipcErrorf(code int64, msg string, args ...any) *IPCError {
  42  	return &IPCError{code: code, err: fmt.Errorf(msg, args...)}
  43  }
  44  
  45  var byteBufferPool = &sync.Pool{
  46  	New: func() any { return new(bytes.Buffer) },
  47  }
  48  
  49  // IpcGetOperation implements the WireGuard configuration protocol "get" operation.
  50  // See https://www.wireguard.com/xplatform/#configuration-protocol for details.
  51  func (device *Device) IpcGetOperation(w io.Writer) error {
  52  	device.ipcMutex.RLock()
  53  	defer device.ipcMutex.RUnlock()
  54  
  55  	buf := byteBufferPool.Get().(*bytes.Buffer)
  56  	buf.Reset()
  57  	defer byteBufferPool.Put(buf)
  58  	sendf := func(format string, args ...any) {
  59  		fmt.Fprintf(buf, format, args...)
  60  		buf.WriteByte('\n')
  61  	}
  62  	keyf := func(prefix string, key *[32]byte) {
  63  		buf.Grow(len(key)*2 + 2 + len(prefix))
  64  		buf.WriteString(prefix)
  65  		buf.WriteByte('=')
  66  		const hex = "0123456789abcdef"
  67  		for i := 0; i < len(key); i++ {
  68  			buf.WriteByte(hex[key[i]>>4])
  69  			buf.WriteByte(hex[key[i]&0xf])
  70  		}
  71  		buf.WriteByte('\n')
  72  	}
  73  
  74  	func() {
  75  		// lock required resources
  76  
  77  		device.net.RLock()
  78  		defer device.net.RUnlock()
  79  
  80  		device.staticIdentity.RLock()
  81  		defer device.staticIdentity.RUnlock()
  82  
  83  		device.peers.RLock()
  84  		defer device.peers.RUnlock()
  85  
  86  		// serialize device related values
  87  
  88  		if !device.staticIdentity.privateKey.IsZero() {
  89  			keyf("private_key", (*[32]byte)(&device.staticIdentity.privateKey))
  90  		}
  91  
  92  		if device.net.port != 0 {
  93  			sendf("listen_port=%d", device.net.port)
  94  		}
  95  
  96  		if device.net.fwmark != 0 {
  97  			sendf("fwmark=%d", device.net.fwmark)
  98  		}
  99  
 100  		for _, peer := range device.peers.keyMap {
 101  			// Serialize peer state.
 102  			peer.handshake.mutex.RLock()
 103  			keyf("public_key", (*[32]byte)(&peer.handshake.remoteStatic))
 104  			keyf("preshared_key", (*[32]byte)(&peer.handshake.presharedKey))
 105  			peer.handshake.mutex.RUnlock()
 106  			sendf("protocol_version=1")
 107  			peer.endpoint.Lock()
 108  			if peer.endpoint.val != nil {
 109  				sendf("endpoint=%s", peer.endpoint.val.DstToString())
 110  			}
 111  			peer.endpoint.Unlock()
 112  
 113  			nano := peer.lastHandshakeNano.Load()
 114  			secs := nano / time.Second.Nanoseconds()
 115  			nano %= time.Second.Nanoseconds()
 116  
 117  			sendf("last_handshake_time_sec=%d", secs)
 118  			sendf("last_handshake_time_nsec=%d", nano)
 119  			sendf("tx_bytes=%d", peer.txBytes.Load())
 120  			sendf("rx_bytes=%d", peer.rxBytes.Load())
 121  			sendf("persistent_keepalive_interval=%d", peer.persistentKeepaliveInterval.Load())
 122  
 123  			device.allowedips.EntriesForPeer(peer, func(prefix netip.Prefix) bool {
 124  				sendf("allowed_ip=%s", prefix.String())
 125  				return true
 126  			})
 127  		}
 128  	}()
 129  
 130  	// send lines (does not require resource locks)
 131  	if _, err := w.Write(buf.Bytes()); err != nil {
 132  		return ipcErrorf(ipc.IpcErrorIO, "failed to write output: %w", err)
 133  	}
 134  
 135  	return nil
 136  }
 137  
 138  // IpcSetOperation implements the WireGuard configuration protocol "set" operation.
 139  // See https://www.wireguard.com/xplatform/#configuration-protocol for details.
 140  func (device *Device) IpcSetOperation(r io.Reader) (err error) {
 141  	device.ipcMutex.Lock()
 142  	defer device.ipcMutex.Unlock()
 143  
 144  	defer func() {
 145  		if err != nil {
 146  			device.log.Errorf("%v", err)
 147  		}
 148  	}()
 149  
 150  	peer := new(ipcSetPeer)
 151  	deviceConfig := true
 152  
 153  	scanner := bufio.NewScanner(r)
 154  	for scanner.Scan() {
 155  		line := scanner.Text()
 156  		if line == "" {
 157  			// Blank line means terminate operation.
 158  			peer.handlePostConfig()
 159  			return nil
 160  		}
 161  		key, value, ok := strings.Cut(line, "=")
 162  		if !ok {
 163  			return ipcErrorf(ipc.IpcErrorProtocol, "failed to parse line %q", line)
 164  		}
 165  
 166  		if key == "public_key" {
 167  			if deviceConfig {
 168  				deviceConfig = false
 169  			}
 170  			peer.handlePostConfig()
 171  			// Load/create the peer we are now configuring.
 172  			err := device.handlePublicKeyLine(peer, value)
 173  			if err != nil {
 174  				return err
 175  			}
 176  			continue
 177  		}
 178  
 179  		var err error
 180  		if deviceConfig {
 181  			err = device.handleDeviceLine(key, value)
 182  		} else {
 183  			err = device.handlePeerLine(peer, key, value)
 184  		}
 185  		if err != nil {
 186  			return err
 187  		}
 188  	}
 189  	peer.handlePostConfig()
 190  
 191  	if err := scanner.Err(); err != nil {
 192  		return ipcErrorf(ipc.IpcErrorIO, "failed to read input: %w", err)
 193  	}
 194  	return nil
 195  }
 196  
 197  func (device *Device) handleDeviceLine(key, value string) error {
 198  	switch key {
 199  	case "private_key":
 200  		var sk NoisePrivateKey
 201  		err := sk.FromMaybeZeroHex(value)
 202  		if err != nil {
 203  			return ipcErrorf(ipc.IpcErrorInvalid, "failed to set private_key: %w", err)
 204  		}
 205  		device.log.Verbosef("UAPI: Updating private key")
 206  		device.SetPrivateKey(sk)
 207  
 208  	case "listen_port":
 209  		port, err := strconv.ParseUint(value, 10, 16)
 210  		if err != nil {
 211  			return ipcErrorf(ipc.IpcErrorInvalid, "failed to parse listen_port: %w", err)
 212  		}
 213  
 214  		// update port and rebind
 215  		device.log.Verbosef("UAPI: Updating listen port")
 216  
 217  		device.net.Lock()
 218  		device.net.port = uint16(port)
 219  		device.net.Unlock()
 220  
 221  		if err := device.BindUpdate(); err != nil {
 222  			return ipcErrorf(ipc.IpcErrorPortInUse, "failed to set listen_port: %w", err)
 223  		}
 224  
 225  	case "fwmark":
 226  		mark, err := strconv.ParseUint(value, 10, 32)
 227  		if err != nil {
 228  			return ipcErrorf(ipc.IpcErrorInvalid, "invalid fwmark: %w", err)
 229  		}
 230  
 231  		device.log.Verbosef("UAPI: Updating fwmark")
 232  		if err := device.BindSetMark(uint32(mark)); err != nil {
 233  			return ipcErrorf(ipc.IpcErrorPortInUse, "failed to update fwmark: %w", err)
 234  		}
 235  
 236  	case "replace_peers":
 237  		if value != "true" {
 238  			return ipcErrorf(ipc.IpcErrorInvalid, "failed to set replace_peers, invalid value: %v", value)
 239  		}
 240  		device.log.Verbosef("UAPI: Removing all peers")
 241  		device.RemoveAllPeers()
 242  
 243  	default:
 244  		return ipcErrorf(ipc.IpcErrorInvalid, "invalid UAPI device key: %v", key)
 245  	}
 246  
 247  	return nil
 248  }
 249  
 250  // An ipcSetPeer is the current state of an IPC set operation on a peer.
 251  type ipcSetPeer struct {
 252  	*Peer        // Peer is the current peer being operated on
 253  	dummy   bool // dummy reports whether this peer is a temporary, placeholder peer
 254  	created bool // new reports whether this is a newly created peer
 255  	pkaOn   bool // pkaOn reports whether the peer had the persistent keepalive turn on
 256  }
 257  
 258  func (peer *ipcSetPeer) handlePostConfig() {
 259  	if peer.Peer == nil || peer.dummy {
 260  		return
 261  	}
 262  	if peer.created {
 263  		peer.endpoint.disableRoaming = peer.device.net.brokenRoaming && peer.endpoint.val != nil
 264  	}
 265  	if peer.device.isUp() {
 266  		peer.Start()
 267  		if peer.pkaOn {
 268  			peer.SendKeepalive()
 269  		}
 270  		peer.SendStagedPackets()
 271  	}
 272  }
 273  
 274  func (device *Device) handlePublicKeyLine(peer *ipcSetPeer, value string) error {
 275  	// Load/create the peer we are configuring.
 276  	var publicKey NoisePublicKey
 277  	err := publicKey.FromHex(value)
 278  	if err != nil {
 279  		return ipcErrorf(ipc.IpcErrorInvalid, "failed to get peer by public key: %w", err)
 280  	}
 281  
 282  	// Ignore peer with the same public key as this device.
 283  	device.staticIdentity.RLock()
 284  	peer.dummy = device.staticIdentity.publicKey.Equals(publicKey)
 285  	device.staticIdentity.RUnlock()
 286  
 287  	if peer.dummy {
 288  		peer.Peer = &Peer{}
 289  	} else {
 290  		peer.Peer = device.LookupPeer(publicKey)
 291  	}
 292  
 293  	peer.created = peer.Peer == nil
 294  	if peer.created {
 295  		peer.Peer, err = device.NewPeer(publicKey)
 296  		if err != nil {
 297  			return ipcErrorf(ipc.IpcErrorInvalid, "failed to create new peer: %w", err)
 298  		}
 299  		device.log.Verbosef("%v - UAPI: Created", peer.Peer)
 300  	}
 301  	return nil
 302  }
 303  
 304  func (device *Device) handlePeerLine(peer *ipcSetPeer, key, value string) error {
 305  	switch key {
 306  	case "update_only":
 307  		// allow disabling of creation
 308  		if value != "true" {
 309  			return ipcErrorf(ipc.IpcErrorInvalid, "failed to set update only, invalid value: %v", value)
 310  		}
 311  		if peer.created && !peer.dummy {
 312  			device.RemovePeer(peer.handshake.remoteStatic)
 313  			peer.Peer = &Peer{}
 314  			peer.dummy = true
 315  		}
 316  
 317  	case "remove":
 318  		// remove currently selected peer from device
 319  		if value != "true" {
 320  			return ipcErrorf(ipc.IpcErrorInvalid, "failed to set remove, invalid value: %v", value)
 321  		}
 322  		if !peer.dummy {
 323  			device.log.Verbosef("%v - UAPI: Removing", peer.Peer)
 324  			device.RemovePeer(peer.handshake.remoteStatic)
 325  		}
 326  		peer.Peer = &Peer{}
 327  		peer.dummy = true
 328  
 329  	case "preshared_key":
 330  		device.log.Verbosef("%v - UAPI: Updating preshared key", peer.Peer)
 331  
 332  		peer.handshake.mutex.Lock()
 333  		err := peer.handshake.presharedKey.FromHex(value)
 334  		peer.handshake.mutex.Unlock()
 335  
 336  		if err != nil {
 337  			return ipcErrorf(ipc.IpcErrorInvalid, "failed to set preshared key: %w", err)
 338  		}
 339  
 340  	case "endpoint":
 341  		device.log.Verbosef("%v - UAPI: Updating endpoint", peer.Peer)
 342  		endpoint, err := device.net.bind.ParseEndpoint(value)
 343  		if err != nil {
 344  			return ipcErrorf(ipc.IpcErrorInvalid, "failed to set endpoint %v: %w", value, err)
 345  		}
 346  		peer.endpoint.Lock()
 347  		defer peer.endpoint.Unlock()
 348  		peer.endpoint.val = endpoint
 349  
 350  	case "persistent_keepalive_interval":
 351  		device.log.Verbosef("%v - UAPI: Updating persistent keepalive interval", peer.Peer)
 352  
 353  		secs, err := strconv.ParseUint(value, 10, 16)
 354  		if err != nil {
 355  			return ipcErrorf(ipc.IpcErrorInvalid, "failed to set persistent keepalive interval: %w", err)
 356  		}
 357  
 358  		old := peer.persistentKeepaliveInterval.Swap(uint32(secs))
 359  
 360  		// Send immediate keepalive if we're turning it on and before it wasn't on.
 361  		peer.pkaOn = old == 0 && secs != 0
 362  
 363  	case "replace_allowed_ips":
 364  		device.log.Verbosef("%v - UAPI: Removing all allowedips", peer.Peer)
 365  		if value != "true" {
 366  			return ipcErrorf(ipc.IpcErrorInvalid, "failed to replace allowedips, invalid value: %v", value)
 367  		}
 368  		if peer.dummy {
 369  			return nil
 370  		}
 371  		device.allowedips.RemoveByPeer(peer.Peer)
 372  
 373  	case "allowed_ip":
 374  		add := true
 375  		verb := "Adding"
 376  		if len(value) > 0 && value[0] == '-' {
 377  			add = false
 378  			verb = "Removing"
 379  			value = value[1:]
 380  		}
 381  		device.log.Verbosef("%v - UAPI: %s allowedip", peer.Peer, verb)
 382  		prefix, err := netip.ParsePrefix(value)
 383  		if err != nil {
 384  			return ipcErrorf(ipc.IpcErrorInvalid, "failed to set allowed ip: %w", err)
 385  		}
 386  		if peer.dummy {
 387  			return nil
 388  		}
 389  		if add {
 390  			device.allowedips.Insert(prefix, peer.Peer)
 391  		} else {
 392  			device.allowedips.Remove(prefix, peer.Peer)
 393  		}
 394  
 395  	case "protocol_version":
 396  		if value != "1" {
 397  			return ipcErrorf(ipc.IpcErrorInvalid, "invalid protocol version: %v", value)
 398  		}
 399  
 400  	default:
 401  		return ipcErrorf(ipc.IpcErrorInvalid, "invalid UAPI peer key: %v", key)
 402  	}
 403  
 404  	return nil
 405  }
 406  
 407  func (device *Device) IpcGet() (string, error) {
 408  	buf := new(strings.Builder)
 409  	if err := device.IpcGetOperation(buf); err != nil {
 410  		return "", err
 411  	}
 412  	return buf.String(), nil
 413  }
 414  
 415  func (device *Device) IpcSet(uapiConf string) error {
 416  	return device.IpcSetOperation(strings.NewReader(uapiConf))
 417  }
 418  
 419  func (device *Device) IpcHandle(socket net.Conn) {
 420  	defer socket.Close()
 421  
 422  	buffered := func(s io.ReadWriter) *bufio.ReadWriter {
 423  		reader := bufio.NewReader(s)
 424  		writer := bufio.NewWriter(s)
 425  		return bufio.NewReadWriter(reader, writer)
 426  	}(socket)
 427  
 428  	for {
 429  		op, err := buffered.ReadString('\n')
 430  		if err != nil {
 431  			return
 432  		}
 433  
 434  		// handle operation
 435  		switch op {
 436  		case "set=1\n":
 437  			err = device.IpcSetOperation(buffered.Reader)
 438  		case "get=1\n":
 439  			var nextByte byte
 440  			nextByte, err = buffered.ReadByte()
 441  			if err != nil {
 442  				return
 443  			}
 444  			if nextByte != '\n' {
 445  				err = ipcErrorf(ipc.IpcErrorInvalid, "trailing character in UAPI get: %q", nextByte)
 446  				break
 447  			}
 448  			err = device.IpcGetOperation(buffered.Writer)
 449  		default:
 450  			device.log.Errorf("invalid UAPI operation: %v", op)
 451  			return
 452  		}
 453  
 454  		// write status
 455  		var status *IPCError
 456  		if err != nil && !errors.As(err, &status) {
 457  			// shouldn't happen
 458  			status = ipcErrorf(ipc.IpcErrorUnknown, "other UAPI error: %w", err)
 459  		}
 460  		if status != nil {
 461  			device.log.Errorf("%v", status)
 462  			fmt.Fprintf(buffered, "errno=%d\n\n", status.ErrorCode())
 463  		} else {
 464  			fmt.Fprintf(buffered, "errno=0\n\n")
 465  		}
 466  		buffered.Flush()
 467  	}
 468  }
 469