github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/services/wireguard/endpoint/userspace/device_parser.go (about)

     1  /*
     2   * Copyright (C) 2020 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package userspace
    19  
    20  import (
    21  	"bufio"
    22  	"bytes"
    23  	"encoding/hex"
    24  	"fmt"
    25  	"io"
    26  	"net"
    27  	"os"
    28  	"strconv"
    29  	"time"
    30  
    31  	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
    32  )
    33  
    34  // UserspaceDevice is a WireGuard device.
    35  type UserspaceDevice struct {
    36  	// ListenPort is the device's network listening port.
    37  	ListenPort int
    38  
    39  	// FirewallMark is the device's current firewall mark.
    40  	//
    41  	// The firewall mark can be used in conjunction with firewall software to
    42  	// take action on outgoing WireGuard packets.
    43  	FirewallMark int
    44  
    45  	// Peers is the list of network peers associated with this device.
    46  	Peers []UserspaceDevicePeer
    47  }
    48  
    49  // UserspaceDevicePeer is a WireGuard peer to a Device.
    50  type UserspaceDevicePeer struct {
    51  	// PublicKey is the public key of a peer, computed from its private key.
    52  	//
    53  	// PublicKey is always present in a Peer.
    54  	PublicKey string
    55  
    56  	// Endpoint is the most recent source address used for communication by
    57  	// this Peer.
    58  	Endpoint *net.UDPAddr
    59  
    60  	// PersistentKeepaliveInterval specifies how often an "empty" packet is sent
    61  	// to a peer to keep a connection alive.
    62  	//
    63  	// A value of 0 indicates that persistent keepalives are disabled.
    64  	PersistentKeepaliveInterval time.Duration
    65  
    66  	// LastHandshakeTime indicates the most recent time a handshake was performed
    67  	// with this peer.
    68  	//
    69  	// A zero-value time.Time indicates that no handshake has taken place with
    70  	// this peer.
    71  	LastHandshakeTime time.Time
    72  
    73  	// ReceiveBytes indicates the number of bytes received from this peer.
    74  	ReceiveBytes int64
    75  
    76  	// TransmitBytes indicates the number of bytes transmitted to this peer.
    77  	TransmitBytes int64
    78  
    79  	// AllowedIPs specifies which IPv4 and IPv6 addresses this peer is allowed
    80  	// to communicate on.
    81  	//
    82  	// 0.0.0.0/0 indicates that all IPv4 addresses are allowed, and ::/0
    83  	// indicates that all IPv6 addresses are allowed.
    84  	AllowedIPs []net.IPNet
    85  
    86  	// ProtocolVersion specifies which version of the WireGuard protocol is used
    87  	// for this Peer.
    88  	//
    89  	// A value of 0 indicates that the most recent protocol version will be used.
    90  	ProtocolVersion int
    91  }
    92  
    93  // ParseUserspaceDevice parses WireGuard device state buffer.
    94  func ParseUserspaceDevice(ipcGetOp func(w io.Writer) error) (*UserspaceDevice, error) {
    95  	var buf bytes.Buffer
    96  	writer := bufio.NewWriter(&buf)
    97  	if err := ipcGetOp(writer); err != nil {
    98  		return nil, err
    99  	}
   100  	if err := writer.Flush(); err != nil {
   101  		return nil, err
   102  	}
   103  
   104  	var dp deviceParser
   105  	s := bufio.NewScanner(&buf)
   106  	for s.Scan() {
   107  		b := s.Bytes()
   108  		if len(b) == 0 {
   109  			// Empty line, done parsing.
   110  			break
   111  		}
   112  
   113  		// All data is in key=value format.
   114  		kvs := bytes.Split(b, []byte("="))
   115  		if len(kvs) != 2 {
   116  			return nil, fmt.Errorf("invalid key=value pair: %q", string(b))
   117  		}
   118  
   119  		dp.Parse(string(kvs[0]), string(kvs[1]))
   120  	}
   121  
   122  	if dp.err != nil {
   123  		return nil, dp.err
   124  	}
   125  	return &dp.d, nil
   126  }
   127  
   128  // A deviceParser accumulates information about a Device and its Peers. Adapted from
   129  // https://github.com/WireGuard/wgctrl-go/blob/master/internal/wguser/parse.go.
   130  type deviceParser struct {
   131  	d   UserspaceDevice
   132  	err error
   133  
   134  	parsePeers    bool
   135  	peers         int
   136  	hsSec, hsNano int
   137  }
   138  
   139  // Parse parses a single key/value pair into fields of a Device.
   140  func (dp *deviceParser) Parse(key, value string) {
   141  	switch key {
   142  	case "errno":
   143  		// 0 indicates success, anything else returns an error number that matches
   144  		// definitions from errno.h.
   145  		if errno := dp.parseInt(value); errno != 0 {
   146  			dp.err = os.NewSyscallError("read", fmt.Errorf("wguser: errno=%d", errno))
   147  			return
   148  		}
   149  	case "public_key":
   150  		// We've either found the first peer or the next peer.  Stop parsing
   151  		// Device fields and start parsing Peer fields, including the public
   152  		// key indicated here.
   153  		dp.parsePeers = true
   154  		dp.peers++
   155  
   156  		dp.d.Peers = append(dp.d.Peers, UserspaceDevicePeer{
   157  			PublicKey: dp.parseKey(value),
   158  		})
   159  		return
   160  	}
   161  
   162  	// Are we parsing peer fields?
   163  	if dp.parsePeers {
   164  		dp.peerParse(key, value)
   165  		return
   166  	}
   167  
   168  	// Device field parsing.
   169  	switch key {
   170  	case "listen_port":
   171  		dp.d.ListenPort = dp.parseInt(value)
   172  	case "fwmark":
   173  		dp.d.FirewallMark = dp.parseInt(value)
   174  	}
   175  }
   176  
   177  // curPeer returns the current Peer being parsed so its fields can be populated.
   178  func (dp *deviceParser) curPeer() *UserspaceDevicePeer {
   179  	return &dp.d.Peers[dp.peers-1]
   180  }
   181  
   182  // peerParse parses a key/value field into the current Peer.
   183  func (dp *deviceParser) peerParse(key, value string) {
   184  	p := dp.curPeer()
   185  	switch key {
   186  	case "endpoint":
   187  		p.Endpoint = dp.parseAddr(value)
   188  	case "last_handshake_time_sec":
   189  		dp.hsSec = dp.parseInt(value)
   190  	case "last_handshake_time_nsec":
   191  		dp.hsNano = dp.parseInt(value)
   192  
   193  		// Assume that we've seen both seconds and nanoseconds and populate this
   194  		// field now. However, if both fields were set to 0, assume we have never
   195  		// had a successful handshake with this peer, and return a zero-value
   196  		// time.Time to our callers.
   197  		if dp.hsSec > 0 && dp.hsNano > 0 {
   198  			p.LastHandshakeTime = time.Unix(int64(dp.hsSec), int64(dp.hsNano))
   199  		}
   200  	case "tx_bytes":
   201  		p.TransmitBytes = dp.parseInt64(value)
   202  	case "rx_bytes":
   203  		p.ReceiveBytes = dp.parseInt64(value)
   204  	case "persistent_keepalive_interval":
   205  		p.PersistentKeepaliveInterval = time.Duration(dp.parseInt(value)) * time.Second
   206  	case "allowed_ip":
   207  		cidr := dp.parseCIDR(value)
   208  		if cidr != nil {
   209  			p.AllowedIPs = append(p.AllowedIPs, *cidr)
   210  		}
   211  	case "protocol_version":
   212  		p.ProtocolVersion = dp.parseInt(value)
   213  	}
   214  }
   215  
   216  // parseKey parses a Key from a hex string.
   217  func (dp *deviceParser) parseKey(s string) string {
   218  	if dp.err != nil {
   219  		return ""
   220  	}
   221  
   222  	b, err := hex.DecodeString(s)
   223  	if err != nil {
   224  		dp.err = err
   225  		return ""
   226  	}
   227  
   228  	key, err := wgtypes.NewKey(b)
   229  	if err != nil {
   230  		dp.err = err
   231  		return ""
   232  	}
   233  
   234  	return key.String()
   235  }
   236  
   237  // parseInt parses an integer from a string.
   238  func (dp *deviceParser) parseInt(s string) int {
   239  	if dp.err != nil {
   240  		return 0
   241  	}
   242  
   243  	v, err := strconv.Atoi(s)
   244  	if err != nil {
   245  		dp.err = err
   246  		return 0
   247  	}
   248  
   249  	return v
   250  }
   251  
   252  // parseInt64 parses an int64 from a string.
   253  func (dp *deviceParser) parseInt64(s string) int64 {
   254  	if dp.err != nil {
   255  		return 0
   256  	}
   257  
   258  	v, err := strconv.ParseInt(s, 10, 64)
   259  	if err != nil {
   260  		dp.err = err
   261  		return 0
   262  	}
   263  
   264  	return v
   265  }
   266  
   267  // parseAddr parses a UDP address from a string.
   268  func (dp *deviceParser) parseAddr(s string) *net.UDPAddr {
   269  	if dp.err != nil {
   270  		return nil
   271  	}
   272  
   273  	addr, err := net.ResolveUDPAddr("udp", s)
   274  	if err != nil {
   275  		dp.err = err
   276  		return nil
   277  	}
   278  
   279  	return addr
   280  }
   281  
   282  // parseInt parses an address CIDR from a string.
   283  func (dp *deviceParser) parseCIDR(s string) *net.IPNet {
   284  	if dp.err != nil {
   285  		return nil
   286  	}
   287  
   288  	_, cidr, err := net.ParseCIDR(s)
   289  	if err != nil {
   290  		dp.err = err
   291  		return nil
   292  	}
   293  
   294  	return cidr
   295  }