mirror of
https://github.com/WireGuard/wgctrl-go.git
synced 2024-09-21 22:50:48 +00:00
97bc4ad4a1
* internal/freebsd: add initial version of FreeBSD support * internal/wguser: Replace deprecated io/ioutil package with io * internal/freebsd: prepare CI to run tests on FreeBSD * test: sort AllowedIPs before diffing them * test: skip integration test configure_peers_update_only on FreeBSD * test: increase test timeout for slow FreeBSD tests * add FreeBSD support to README Signed-off-by: Steffen Vogel <post@steffenvogel.de> * *: tidy * go.mod: bump dependencies * .builds: try to fix OpenBSD Signed-off-by: Matt Layher <mdlayher@gmail.com> Co-authored-by: Steffen Vogel <post@steffenvogel.de>
277 lines
7.7 KiB
Go
277 lines
7.7 KiB
Go
package wgtypes
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/curve25519"
|
|
)
|
|
|
|
// A DeviceType specifies the underlying implementation of a WireGuard device.
|
|
type DeviceType int
|
|
|
|
// Possible DeviceType values.
|
|
const (
|
|
Unknown DeviceType = iota
|
|
LinuxKernel
|
|
OpenBSDKernel
|
|
FreeBSDKernel
|
|
WindowsKernel
|
|
Userspace
|
|
)
|
|
|
|
// String returns the string representation of a DeviceType.
|
|
func (dt DeviceType) String() string {
|
|
switch dt {
|
|
case LinuxKernel:
|
|
return "Linux kernel"
|
|
case OpenBSDKernel:
|
|
return "OpenBSD kernel"
|
|
case FreeBSDKernel:
|
|
return "FreeBSD kernel"
|
|
case WindowsKernel:
|
|
return "Windows kernel"
|
|
case Userspace:
|
|
return "userspace"
|
|
default:
|
|
return "unknown"
|
|
}
|
|
}
|
|
|
|
// A Device is a WireGuard device.
|
|
type Device struct {
|
|
// Name is the name of the device.
|
|
Name string
|
|
|
|
// Type specifies the underlying implementation of the device.
|
|
Type DeviceType
|
|
|
|
// PrivateKey is the device's private key.
|
|
PrivateKey Key
|
|
|
|
// PublicKey is the device's public key, computed from its PrivateKey.
|
|
PublicKey Key
|
|
|
|
// ListenPort is the device's network listening port.
|
|
ListenPort int
|
|
|
|
// FirewallMark is the device's current firewall mark.
|
|
//
|
|
// The firewall mark can be used in conjunction with firewall software to
|
|
// take action on outgoing WireGuard packets.
|
|
FirewallMark int
|
|
|
|
// Peers is the list of network peers associated with this device.
|
|
Peers []Peer
|
|
}
|
|
|
|
// KeyLen is the expected key length for a WireGuard key.
|
|
const KeyLen = 32 // wgh.KeyLen
|
|
|
|
// A Key is a public, private, or pre-shared secret key. The Key constructor
|
|
// functions in this package can be used to create Keys suitable for each of
|
|
// these applications.
|
|
type Key [KeyLen]byte
|
|
|
|
// GenerateKey generates a Key suitable for use as a pre-shared secret key from
|
|
// a cryptographically safe source.
|
|
//
|
|
// The output Key should not be used as a private key; use GeneratePrivateKey
|
|
// instead.
|
|
func GenerateKey() (Key, error) {
|
|
b := make([]byte, KeyLen)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return Key{}, fmt.Errorf("wgtypes: failed to read random bytes: %v", err)
|
|
}
|
|
|
|
return NewKey(b)
|
|
}
|
|
|
|
// GeneratePrivateKey generates a Key suitable for use as a private key from a
|
|
// cryptographically safe source.
|
|
func GeneratePrivateKey() (Key, error) {
|
|
key, err := GenerateKey()
|
|
if err != nil {
|
|
return Key{}, err
|
|
}
|
|
|
|
// Modify random bytes using algorithm described at:
|
|
// https://cr.yp.to/ecdh.html.
|
|
key[0] &= 248
|
|
key[31] &= 127
|
|
key[31] |= 64
|
|
|
|
return key, nil
|
|
}
|
|
|
|
// NewKey creates a Key from an existing byte slice. The byte slice must be
|
|
// exactly 32 bytes in length.
|
|
func NewKey(b []byte) (Key, error) {
|
|
if len(b) != KeyLen {
|
|
return Key{}, fmt.Errorf("wgtypes: incorrect key size: %d", len(b))
|
|
}
|
|
|
|
var k Key
|
|
copy(k[:], b)
|
|
|
|
return k, nil
|
|
}
|
|
|
|
// ParseKey parses a Key from a base64-encoded string, as produced by the
|
|
// Key.String method.
|
|
func ParseKey(s string) (Key, error) {
|
|
b, err := base64.StdEncoding.DecodeString(s)
|
|
if err != nil {
|
|
return Key{}, fmt.Errorf("wgtypes: failed to parse base64-encoded key: %v", err)
|
|
}
|
|
|
|
return NewKey(b)
|
|
}
|
|
|
|
// PublicKey computes a public key from the private key k.
|
|
//
|
|
// PublicKey should only be called when k is a private key.
|
|
func (k Key) PublicKey() Key {
|
|
var (
|
|
pub [KeyLen]byte
|
|
priv = [KeyLen]byte(k)
|
|
)
|
|
|
|
// ScalarBaseMult uses the correct base value per https://cr.yp.to/ecdh.html,
|
|
// so no need to specify it.
|
|
curve25519.ScalarBaseMult(&pub, &priv)
|
|
|
|
return Key(pub)
|
|
}
|
|
|
|
// String returns the base64-encoded string representation of a Key.
|
|
//
|
|
// ParseKey can be used to produce a new Key from this string.
|
|
func (k Key) String() string {
|
|
return base64.StdEncoding.EncodeToString(k[:])
|
|
}
|
|
|
|
// A Peer is a WireGuard peer to a Device.
|
|
type Peer struct {
|
|
// PublicKey is the public key of a peer, computed from its private key.
|
|
//
|
|
// PublicKey is always present in a Peer.
|
|
PublicKey Key
|
|
|
|
// PresharedKey is an optional preshared key which may be used as an
|
|
// additional layer of security for peer communications.
|
|
//
|
|
// A zero-value Key means no preshared key is configured.
|
|
PresharedKey Key
|
|
|
|
// Endpoint is the most recent source address used for communication by
|
|
// this Peer.
|
|
Endpoint *net.UDPAddr
|
|
|
|
// PersistentKeepaliveInterval specifies how often an "empty" packet is sent
|
|
// to a peer to keep a connection alive.
|
|
//
|
|
// A value of 0 indicates that persistent keepalives are disabled.
|
|
PersistentKeepaliveInterval time.Duration
|
|
|
|
// LastHandshakeTime indicates the most recent time a handshake was performed
|
|
// with this peer.
|
|
//
|
|
// A zero-value time.Time indicates that no handshake has taken place with
|
|
// this peer.
|
|
LastHandshakeTime time.Time
|
|
|
|
// ReceiveBytes indicates the number of bytes received from this peer.
|
|
ReceiveBytes int64
|
|
|
|
// TransmitBytes indicates the number of bytes transmitted to this peer.
|
|
TransmitBytes int64
|
|
|
|
// AllowedIPs specifies which IPv4 and IPv6 addresses this peer is allowed
|
|
// to communicate on.
|
|
//
|
|
// 0.0.0.0/0 indicates that all IPv4 addresses are allowed, and ::/0
|
|
// indicates that all IPv6 addresses are allowed.
|
|
AllowedIPs []net.IPNet
|
|
|
|
// ProtocolVersion specifies which version of the WireGuard protocol is used
|
|
// for this Peer.
|
|
//
|
|
// A value of 0 indicates that the most recent protocol version will be used.
|
|
ProtocolVersion int
|
|
}
|
|
|
|
// A Config is a WireGuard device configuration.
|
|
//
|
|
// Because the zero value of some Go types may be significant to WireGuard for
|
|
// Config fields, pointer types are used for some of these fields. Only
|
|
// pointer fields which are not nil will be applied when configuring a device.
|
|
type Config struct {
|
|
// PrivateKey specifies a private key configuration, if not nil.
|
|
//
|
|
// A non-nil, zero-value Key will clear the private key.
|
|
PrivateKey *Key
|
|
|
|
// ListenPort specifies a device's listening port, if not nil.
|
|
ListenPort *int
|
|
|
|
// FirewallMark specifies a device's firewall mark, if not nil.
|
|
//
|
|
// If non-nil and set to 0, the firewall mark will be cleared.
|
|
FirewallMark *int
|
|
|
|
// ReplacePeers specifies if the Peers in this configuration should replace
|
|
// the existing peer list, instead of appending them to the existing list.
|
|
ReplacePeers bool
|
|
|
|
// Peers specifies a list of peer configurations to apply to a device.
|
|
Peers []PeerConfig
|
|
}
|
|
|
|
// TODO(mdlayher): consider adding ProtocolVersion in PeerConfig.
|
|
|
|
// A PeerConfig is a WireGuard device peer configuration.
|
|
//
|
|
// Because the zero value of some Go types may be significant to WireGuard for
|
|
// PeerConfig fields, pointer types are used for some of these fields. Only
|
|
// pointer fields which are not nil will be applied when configuring a peer.
|
|
type PeerConfig struct {
|
|
// PublicKey specifies the public key of this peer. PublicKey is a
|
|
// mandatory field for all PeerConfigs.
|
|
PublicKey Key
|
|
|
|
// Remove specifies if the peer with this public key should be removed
|
|
// from a device's peer list.
|
|
Remove bool
|
|
|
|
// UpdateOnly specifies that an operation will only occur on this peer
|
|
// if the peer already exists as part of the interface.
|
|
UpdateOnly bool
|
|
|
|
// PresharedKey specifies a peer's preshared key configuration, if not nil.
|
|
//
|
|
// A non-nil, zero-value Key will clear the preshared key.
|
|
PresharedKey *Key
|
|
|
|
// Endpoint specifies the endpoint of this peer entry, if not nil.
|
|
Endpoint *net.UDPAddr
|
|
|
|
// PersistentKeepaliveInterval specifies the persistent keepalive interval
|
|
// for this peer, if not nil.
|
|
//
|
|
// A non-nil value of 0 will clear the persistent keepalive interval.
|
|
PersistentKeepaliveInterval *time.Duration
|
|
|
|
// ReplaceAllowedIPs specifies if the allowed IPs specified in this peer
|
|
// configuration should replace any existing ones, instead of appending them
|
|
// to the allowed IPs list.
|
|
ReplaceAllowedIPs bool
|
|
|
|
// AllowedIPs specifies a list of allowed IP addresses in CIDR notation
|
|
// for this peer.
|
|
AllowedIPs []net.IPNet
|
|
}
|