diff --git a/client/go/outline/device.go b/client/go/outline/device.go index 427ed3e063..cee9684b7d 100644 --- a/client/go/outline/device.go +++ b/client/go/outline/device.go @@ -26,6 +26,8 @@ import ( "github.com/Jigsaw-Code/outline-sdk/network/lwip2transport" ) +// Device is an IPDevice that connects to a remote Outline server. +// It also implements the vpn.ProxyDevice interface. type Device struct { network.IPDevice @@ -38,6 +40,7 @@ type Device struct { var _ vpn.ProxyDevice = (*Device)(nil) +// NewDevice creates a new [Device] using the given [Client]. func NewDevice(c *Client) (*Device, error) { if c == nil { return nil, errors.New("Client must be provided") @@ -45,10 +48,13 @@ func NewDevice(c *Client) (*Device, error) { return &Device{c: c}, nil } +// SupportsUDP returns true if the the Outline server forwards UDP traffic. +// This value will be refreshed after Connect or RefreshConnectivity. func (d *Device) SupportsUDP() bool { return d.supportsUDP } +// Connect tries to connect to the Outline server. func (d *Device) Connect(ctx context.Context) (err error) { if ctx.Err() != nil { return perrs.PlatformError{Code: perrs.OperationCanceled} @@ -78,6 +84,7 @@ func (d *Device) Connect(ctx context.Context) (err error) { return nil } +// Close closes the connection to the Outline server. func (d *Device) Close() (err error) { if d.IPDevice != nil { err = d.IPDevice.Close() @@ -85,6 +92,7 @@ func (d *Device) Close() (err error) { return } +// RefreshConnectivity refreshes the connectivity to the Outline server. func (d *Device) RefreshConnectivity(ctx context.Context) (err error) { if ctx.Err() != nil { return perrs.PlatformError{Code: perrs.OperationCanceled} diff --git a/client/go/outline/vpn.go b/client/go/outline/vpn.go index e1f7812d7a..14339665fb 100644 --- a/client/go/outline/vpn.go +++ b/client/go/outline/vpn.go @@ -27,6 +27,12 @@ type vpnConfigJSON struct { TransportConfig string `json:"transport"` } +// establishVPN establishes a VPN connection using the given configuration string. +// The configuration string should be a JSON object containing the VPN configuration +// and the transport configuration. +// +// The function returns a JSON string representing the established VPN connection, +// or an error if the connection fails. func establishVPN(configStr string) (string, error) { var conf vpnConfigJSON if err := json.Unmarshal([]byte(configStr), &conf); err != nil { @@ -77,6 +83,7 @@ func establishVPN(configStr string) (string, error) { return string(connJson), nil } +// closeVPN closes the currently active VPN connection. func closeVPN() error { return vpn.CloseVPN() } diff --git a/client/go/outline/vpn/dialer.go b/client/go/outline/vpn/dialer.go index 98a7040e62..63782f4b98 100644 --- a/client/go/outline/vpn/dialer.go +++ b/client/go/outline/vpn/dialer.go @@ -16,4 +16,5 @@ package vpn import "syscall" +// ControlFn is an alias to a function type that can be used in net.Dialer.Control. type ControlFn = func(network, address string, c syscall.RawConn) error diff --git a/client/go/outline/vpn/dialer_linux.go b/client/go/outline/vpn/dialer_linux.go index a1ad244ec9..d286419988 100644 --- a/client/go/outline/vpn/dialer_linux.go +++ b/client/go/outline/vpn/dialer_linux.go @@ -19,6 +19,8 @@ import ( "syscall" ) +// TCPDialerControl returns a ControlFn that sets the SO_MARK socket option on a TCP connection. +// This is used to exclude traffic targeting the remote proxy server from routing to TUN device. func TCPDialerControl(conf *Config) (ControlFn, error) { if conf == nil { return nil, errors.New("VPN config must be provided") @@ -30,6 +32,8 @@ func TCPDialerControl(conf *Config) (ControlFn, error) { }, nil } +// TCPDialerControl returns a ControlFn that sets the SO_MARK socket option on a TCP connection. +// This is used to exclude traffic targeting the remote proxy server from routing to TUN device. func UDPDialerControl(conf *Config) (ControlFn, error) { return TCPDialerControl(conf) } diff --git a/client/go/outline/vpn/dialer_others.go b/client/go/outline/vpn/dialer_others.go index 8dd1fd3ad9..e8a3a6b5df 100644 --- a/client/go/outline/vpn/dialer_others.go +++ b/client/go/outline/vpn/dialer_others.go @@ -18,10 +18,12 @@ package vpn import "errors" +// TCPDialerControl is not supported on this platform. func TCPDialerControl(conf *Config) (ControlFn, error) { return nil, errors.ErrUnsupported } +// UDPDialerControl is not supported on this platform. func UDPDialerControl(conf *Config) (ControlFn, error) { return nil, errors.ErrUnsupported } diff --git a/client/go/outline/vpn/vpn.go b/client/go/outline/vpn/vpn.go index 9c65990d23..3c77d1ba92 100644 --- a/client/go/outline/vpn/vpn.go +++ b/client/go/outline/vpn/vpn.go @@ -24,6 +24,7 @@ import ( "github.com/Jigsaw-Code/outline-sdk/network" ) +// Config holds the configuration to establish a system-wide [VPNConnection]. type Config struct { ID string `json:"id"` InterfaceName string `json:"interfaceName"` @@ -35,7 +36,7 @@ type Config struct { ProtectionMark uint32 `json:"protectionMark"` } -// Status defines the possible states of a VPN connection. +// Status defines the possible states of a [VPNConnection]. type Status string // Constants representing the different VPN connection statuses. @@ -47,20 +48,33 @@ const ( StatusDisconnecting Status = "Disconnecting" ) +// ProxyDevice is an interface representing a remote proxy server device. type ProxyDevice interface { network.IPDevice + + // Connect establishes a connection to the proxy device. Connect(ctx context.Context) error + + // SupportsUDP returns true if the proxy device is able to handle UDP traffic. SupportsUDP() bool + + // RefreshConnectivity refreshes the UDP support of the proxy device. RefreshConnectivity(ctx context.Context) error } +// platformVPNConn is an interface representing an OS-specific VPN connection. type platformVPNConn interface { + // Establish creates a TUN device and routes all system traffic to it. Establish(ctx context.Context) error + + // TUN returns a L3 IP tun device associated with the VPN connection. TUN() io.ReadWriteCloser + + // Close terminates the VPN connection and closes the TUN device. Close() error } -// VPNConnection is a platform neutral interface of a VPN connection. +// VPNConnection represents a system-wide VPN connection. type VPNConnection struct { ID string `json:"id"` Status Status `json:"status"` @@ -74,10 +88,12 @@ type VPNConnection struct { platform platformVPNConn } +// SetStatus sets the status of the VPN connection. func (c *VPNConnection) SetStatus(s Status) { c.Status = s } +// SetSupportsUDP sets whether the VPN connection supports UDP. func (c *VPNConnection) SetSupportsUDP(v bool) { c.SupportsUDP = &v } @@ -87,10 +103,10 @@ func (c *VPNConnection) SetSupportsUDP(v bool) { var mu sync.Mutex var conn *VPNConnection -// EstablishVPN establishes a new active [VPNConnection] with the given configuration. -// It will first close any active [VPNConnection] using [CloseVPN], and then mark the +// EstablishVPN establishes a new active [VPNConnection] with the given [Config]. +// It first closes any active [VPNConnection] using [CloseVPN], and then marks the // newly created [VPNConnection] as the currently active connection. -// It returns the connectionJSON as a string, or an error if the connection fails. +// It returns the new [VPNConnection], or an error if the connection fails. func EstablishVPN(conf *Config, proxy ProxyDevice) (_ *VPNConnection, err error) { if conf == nil { return nil, errors.New("a VPN Config must be provided") @@ -157,7 +173,7 @@ func EstablishVPN(conf *Config, proxy ProxyDevice) (_ *VPNConnection, err error) return c, nil } -// CloseVPN closes the currently active [VPNConnection]. +// CloseVPN terminates the currently active [VPNConnection]. func CloseVPN() error { mu.Lock() defer mu.Unlock() diff --git a/client/go/outline/vpn/vpn_linux.go b/client/go/outline/vpn/vpn_linux.go index 28953cab39..45b8c13108 100644 --- a/client/go/outline/vpn/vpn_linux.go +++ b/client/go/outline/vpn/vpn_linux.go @@ -24,7 +24,7 @@ import ( gonm "github.com/Wifx/gonetworkmanager/v2" ) -// linuxVPNConn implements a [VPNConnection] on Linux platform. +// linuxVPNConn implements a platformVPNConn on the Linux platform. type linuxVPNConn struct { tun io.ReadWriteCloser nmOpts *nmConnectionOptions @@ -34,9 +34,8 @@ type linuxVPNConn struct { var _ platformVPNConn = (*linuxVPNConn)(nil) -// newVPNConnection creates a new Linux specific [VPNConnection]. -// The newly connection will be [StatusDisconnected] initially, you need to call the -// Establish() in order to make it [StatusConnected]. +// newPlatformVPNConn creates a new Linux-specific platformVPNConn. +// You need to call Establish() in order to make it connected. func newPlatformVPNConn(conf *Config) (_ platformVPNConn, err error) { c := &linuxVPNConn{ nmOpts: &nmConnectionOptions{ @@ -70,9 +69,10 @@ func newPlatformVPNConn(conf *Config) (_ platformVPNConn, err error) { return c, nil } +// TUN returns the Linux L3 TUN device. func (c *linuxVPNConn) TUN() io.ReadWriteCloser { return c.tun } -// Establish tries to establish this [VPNConnection], and makes it [StatusConnected]. +// Establish tries to create the TUN device and route all traffic to it. func (c *linuxVPNConn) Establish(ctx context.Context) (err error) { if ctx.Err() != nil { return perrs.PlatformError{Code: perrs.OperationCanceled} @@ -89,7 +89,7 @@ func (c *linuxVPNConn) Establish(ctx context.Context) (err error) { return nil } -// Close tries to close this [VPNConnection] and make it [StatusDisconnected]. +// Close tries to restore the routing and deletes the TUN device. func (c *linuxVPNConn) Close() (err error) { if c == nil { return nil