Documentation ¶
Overview ¶
Package tun is an IP packet tunnel server and client. It supports tunneling both IPv4 and IPv6.
......................................................... .-,( ),-. . [server] .-----. . .-( )-. . | NIC |<---->( Internet ) . ....................................... '-----' . '-( ).-' . . [packet tunnel daemon] . ^ . '-.( ).-' . . . | . . . ........................... . | . . . . [session] . . NAT . . . . . . | . . . . . . v . . . . . . .---. . . . . . . | t | . . . . . . | u | . . . . .---. . .---. . | n | . . . . | q | . | d | . | | . . . . | u | . | e | . | d | . . . . .------| e |<-----| m |<---------| e | . . . . | | u | . | u | . | v | . . . . | | e | . | x | . | i | . . . . rewrite '---' . '---' . | c | . . . . | . . | e | . . . . v . . '---' . . . . .---------. . . ^ . . . . | channel |--rewrite--------------------' . . . . '---------' . . . . . ...........^............... . . . .............|......................... . ...............|......................................... | | (typically via Internet) | ...............|................. . [client] | . . | . . .............|............... . . . v . . . . .---------. . . . . | channel | . . . . '---------' . . . . ^ . . . .............|............... . . v . . .------------. . . | tun device | . . '------------' . .................................
The client relays IP packets between a local tun device and a channel, which is a transport to the server. In Psiphon, the channel will be an SSH channel within an SSH connection to a Psiphon server.
The server relays packets between each client and its own tun device. The server tun device is NATed to the Internet via an external network interface. In this way, client traffic is tunneled and will egress from the server host.
Similar to a typical VPN, IP addresses are assigned to each client. Unlike a typical VPN, the assignment is not transmitted to the client. Instead, the server transparently rewrites the source addresses of client packets to the assigned IP address. The server also rewrites the destination address of certain DNS packets. The purpose of this is to allow clients to reconnect to different servers without having to tear down or change their local network configuration. Clients may configure their local tun device with an arbitrary IP address and a static DNS resolver address.
The server uses the 24-bit 10.0.0.0/8 IPv4 private address space to maximize the number of addresses available, due to Psiphon client churn and minimum address lease time constraints. For IPv6, a 24-bit unique local space is used. When a client is allocated addresses, a unique, unused 24-bit "index" is reserved/leased. This index maps to and from IPv4 and IPv6 private addresses. The server multiplexes all client packets into a single tun device. When a packet is read, the destination address is used to map the packet back to the correct index, which maps back to the client.
The server maintains client "sessions". A session maintains client IP address state and effectively holds the lease on assigned addresses. If a client is disconnected and quickly reconnects, it will resume its previous session, retaining its IP address and network connection states. Idle sessions with no client connection will eventually expire.
Packet count and bytes transferred metrics are logged for each client session.
The server integrates with and enforces Psiphon traffic rules and logging facilities. The server parses and validates packets. Client-to-client packets are not permitted. Only global unicast packets are permitted. Only TCP and UDP packets are permitted. The client also filters out, before sending, packets that the server won't route.
Certain aspects of packet tunneling are outside the scope of this package; e.g, the Psiphon client and server are responsible for establishing an SSH channel and negotiating the correct MTU and DNS settings. The Psiphon server will call Server.ClientConnected when a client connects and establishes a packet tunnel channel; and Server.ClientDisconnected when the client closes the channel and/or disconnects.
Index ¶
- Constants
- func BindToDevice(fd int, deviceName string) error
- func GetTransparentDNSResolverIPv4Address() net.IP
- func GetTransparentDNSResolverIPv6Address() net.IP
- func IsSupported() bool
- func OpenTunDevice(name string) (*os.File, string, error)
- type AllowedPortChecker
- type Channel
- type Client
- type ClientConfig
- type Device
- type FlowActivityUpdater
- type FlowActivityUpdaterMaker
- type MetricsUpdater
- type NonblockingIO
- type PacketQueue
- type Server
- type ServerConfig
Constants ¶
const ( DEFAULT_MTU = 1500 DEFAULT_DOWNSTREAM_PACKET_QUEUE_SIZE = 32768 * 16 DEFAULT_UPSTREAM_PACKET_QUEUE_SIZE = 32768 DEFAULT_IDLE_SESSION_EXPIRY_SECONDS = 300 ORPHAN_METRICS_CHECKPOINTER_PERIOD = 30 * time.Minute FLOW_IDLE_EXPIRY = 60 * time.Second )
const (
DEFAULT_PUBLIC_INTERFACE_NAME = "eth0"
)
Variables ¶
This section is empty.
Functions ¶
func BindToDevice ¶
BindToDevice binds a socket to the specified interface.
func GetTransparentDNSResolverIPv4Address ¶
GetTransparentDNSResolverIPv4Address returns the static IPv4 address to use as a DNS resolver when transparent DNS rewriting is desired.
func GetTransparentDNSResolverIPv6Address ¶
GetTransparentDNSResolverIPv6Address returns the static IPv6 address to use as a DNS resolver when transparent DNS rewriting is desired.
func IsSupported ¶
func IsSupported() bool
Types ¶
type AllowedPortChecker ¶
AllowedPortChecker is a function which returns true when it is permitted to relay packets to the specified upstream IP address and/or port.
type Channel ¶
type Channel struct {
// contains filtered or unexported fields
}
Channel manages packet transport over a communications channel. Any io.ReadWriteCloser can provide transport. In psiphond, the io.ReadWriteCloser will be an SSH channel. Channel I/O frames packets with a length header and uses static, preallocated buffers to avoid GC churn.
func NewChannel ¶
func NewChannel(transport io.ReadWriteCloser, MTU int) *Channel
NewChannel initializes a new Channel.
func (*Channel) Close ¶
Close interrupts any blocking Read/Write calls and closes the channel transport.
func (*Channel) ReadPacket ¶
ReadPacket reads one full packet from the channel. The return value is a slice of a static, reused buffer, so the value is only valid until the next ReadPacket call. Concurrent calls to ReadPacket are not supported.
func (*Channel) WriteFramedPackets ¶
WriteFramedPackets writes a buffer of pre-framed packets to the channel. Concurrent calls to WriteFramedPackets are not supported.
func (*Channel) WritePacket ¶
WritePacket writes one full packet to the channel. Concurrent calls to WritePacket are not supported.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a packet tunnel client. A packet tunnel client relays packets between a local tun device and a packet tunnel server via a transport channel.
func NewClient ¶
func NewClient(config *ClientConfig) (*Client, error)
NewClient initializes a new Client. Unless using the TunFileDescriptor configuration parameter, a new tun device is created for the client.
type ClientConfig ¶
type ClientConfig struct { // Logger is used for logging events and metrics. Logger common.Logger // SudoNetworkConfigCommands specifies whether to use "sudo" // when executing network configuration commands. See description // for ServerConfig.SudoNetworkConfigCommands. SudoNetworkConfigCommands bool // AllowNoIPv6NetworkConfiguration indicates that failures while // configuring tun interfaces and routing for IPv6 are to be // logged as warnings only. See description for // ServerConfig.AllowNoIPv6NetworkConfiguration. AllowNoIPv6NetworkConfiguration bool // MTU is the packet MTU value to use; this value // should be obtained from the packet tunnel server. // When MTU is 0, a default value is used. MTU int // UpstreamPacketQueueSize specifies the size of the upstream // packet queue. // When UpstreamPacketQueueSize is 0, a default value tuned for // Psiphon is used. UpstreamPacketQueueSize int // Transport is an established transport channel that // will be used to relay packets to and from a packet // tunnel server. Transport io.ReadWriteCloser // TunFileDescriptor specifies a file descriptor to use to // read and write packets to be relayed to the client. When // TunFileDescriptor is specified, the Client will use this // existing tun device and not create its own; in this case, // network address and routing configuration is not performed // by the Client. As the packet tunnel server performs // transparent source IP address and DNS rewriting, the tun // device may have any assigned IP address, but should be // configured with the given MTU; and DNS should be configured // to use the transparent DNS target resolver addresses. // Set TunFileDescriptor to <= 0 to ignore this parameter // and create and configure a tun device. TunFileDescriptor int // IPv4AddressCIDR is the IPv4 address and netmask to // assign to a newly created tun device. IPv4AddressCIDR string // IPv6AddressCIDR is the IPv6 address and prefix to // assign to a newly created tun device. IPv6AddressCIDR string // RouteDestinations are hosts (IPs) or networks (CIDRs) // to be configured to be routed through a newly // created tun device. RouteDestinations []string }
ClientConfig specifies the configuration of a packet tunnel client.
type Device ¶
type Device struct {
// contains filtered or unexported fields
}
Device manages a tun device. It handles packet I/O using static, preallocated buffers to avoid GC churn.
func NewClientDevice ¶
func NewClientDevice(config *ClientConfig) (*Device, error)
NewClientDevice creates and configures a new client tun device. Multiple client tun devices may exist per host.
func NewClientDeviceFromFD ¶
func NewClientDeviceFromFD(config *ClientConfig) (*Device, error)
NewClientDeviceFromFD wraps an existing tun device.
func NewServerDevice ¶
func NewServerDevice(config *ServerConfig) (*Device, error)
NewServerDevice creates and configures a new server tun device. Since the server uses fixed address spaces, only one server device may exist per host.
func (*Device) Close ¶
Close interrupts any blocking Read/Write calls and tears down the tun device.
func (*Device) Name ¶
Name returns the interface name for a created tun device, or returns "" for a device created by NewClientDeviceFromFD. The interface name may be used for additional network and routing configuration.
func (*Device) ReadPacket ¶
ReadPacket reads one full packet from the tun device. The return value is a slice of a static, reused buffer, so the value is only valid until the next ReadPacket call. Concurrent calls to ReadPacket are _not_ supported.
func (*Device) WritePacket ¶
WritePacket writes one full packet to the tun device. Concurrent calls to WritePacket are supported.
type FlowActivityUpdater ¶
type FlowActivityUpdater interface {
UpdateProgress(downstreamBytes, upstreamBytes int64, durationNanoseconds int64)
}
FlowActivityUpdater defines an interface for receiving updates for flow activity. Values passed to UpdateProgress are bytes transferred and flow duration since the previous UpdateProgress.
type FlowActivityUpdaterMaker ¶
type FlowActivityUpdaterMaker func( upstreamHostname string, upstreamIPAddress net.IP) []FlowActivityUpdater
FlowActivityUpdaterMaker is a function which returns a list of appropriate updaters for a new flow to the specified upstream hostname (if known -- may be ""), and IP address.
type MetricsUpdater ¶
type MetricsUpdater func( TCPApplicationBytesDown, TCPApplicationBytesUp, UDPApplicationBytesDown, UDPApplicationBytesUp int64)
MetricsUpdater is a function which receives a checkpoint summary of application bytes transferred through a packet tunnel.
type NonblockingIO ¶
type NonblockingIO struct {
// contains filtered or unexported fields
}
NonblockingIO provides interruptible I/O for non-pollable and/or foreign file descriptors that can't use the netpoller available in os.OpenFile as of Go 1.9.
A NonblockingIO wraps a file descriptor in an io.ReadWriteCloser interface. The underlying implementation uses select and a pipe to interrupt Read and Write calls that are blocked when Close is called.
Read and write mutexes allow, for each operation, only one concurrent goroutine to call syscalls, preventing an unbounded number of OS threads from being created by blocked select syscalls.
func NewNonblockingIO ¶
func NewNonblockingIO(ioFD int) (*NonblockingIO, error)
NewNonblockingIO creates a new NonblockingIO with the specified file descriptor, which is duplicated and set to nonblocking and close-on-exec.
func (*NonblockingIO) Close ¶
func (nio *NonblockingIO) Close() error
Close implements the io.Closer interface.
func (*NonblockingIO) IsClosed ¶
func (nio *NonblockingIO) IsClosed() bool
IsClosed indicates whether the NonblockingIO is closed.
type PacketQueue ¶
type PacketQueue struct {
// contains filtered or unexported fields
}
PacketQueue is a fixed-size, preallocated queue of packets. Enqueued packets are packed into a contiguous buffer with channel framing, allowing the entire queue to be written to a channel in a single call. Reuse of the queue buffers avoids GC churn. To avoid memory use spikes when many clients connect and may disconnect before relaying packets, the packet queue buffers start small and grow when required, up to the maximum size, and then remain static.
func NewPacketQueue ¶
func NewPacketQueue(maxSize int) *PacketQueue
NewPacketQueue creates a new PacketQueue. The caller must ensure that maxSize exceeds the packet MTU, or packets will will never enqueue.
func (*PacketQueue) DequeueFramedPackets ¶
func (queue *PacketQueue) DequeueFramedPackets( runContext context.Context) ([]byte, bool)
DequeueFramedPackets waits until at least one packet is enqueued, and then returns a packet buffer containing one or more framed packets. The returned buffer remains part of the PacketQueue structure and the caller _must_ replace the buffer by calling Replace. DequeueFramedPackets unblocks and returns false if it receives runContext.Done(). DequeueFramedPackets is _not_ safe for concurrent calls.
func (*PacketQueue) Enqueue ¶
func (queue *PacketQueue) Enqueue(packet []byte)
Enqueue adds a packet to the queue. If the queue is full, the packet is dropped. Enqueue is _not_ safe for concurrent calls.
func (*PacketQueue) Replace ¶
func (queue *PacketQueue) Replace(buffer []byte)
Replace returns the buffer to the PacketQueue to be reused. The input must be a return value from DequeueFramedPackets.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is a packet tunnel server. A packet tunnel server maintains client sessions, relays packets through client channels, and multiplexes packets through a single tun device. The server assigns IP addresses to clients, performs IP address and transparent DNS rewriting, and enforces traffic rules.
func NewServer ¶
func NewServer(config *ServerConfig) (*Server, error)
NewServer initializes a server.
func (*Server) ClientConnected ¶
func (server *Server) ClientConnected( sessionID string, transport io.ReadWriteCloser, checkAllowedTCPPortFunc, checkAllowedUDPPortFunc AllowedPortChecker, flowActivityUpdaterMaker FlowActivityUpdaterMaker, metricsUpdater MetricsUpdater) error
ClientConnected handles new client connections, creating or resuming a session and returns with client packet handlers running.
sessionID is used to identify sessions for resumption.
transport provides the channel for relaying packets to and from the client.
checkAllowedTCPPortFunc/checkAllowedUDPPortFunc are callbacks used to enforce traffic rules. For each TCP/UDP packet, the corresponding function is called to check if traffic to the packet's port is permitted. These callbacks must be efficient and safe for concurrent calls.
flowActivityUpdaterMaker is a callback invoked for each new packet flow; it may create updaters to track flow activity.
metricsUpdater is a callback invoked at metrics checkpoints (usually when the client disconnects) with a summary of application bytes transferred.
It is safe to make concurrent calls to ClientConnected for distinct session IDs. The caller is responsible for serializing calls with the same session ID. Further, the caller must ensure, in the case of a client transport reconnect when an existing transport has not yet disconnected, that ClientDisconnected is called first -- so it doesn't undo the new ClientConnected. (psiphond meets these constraints by closing any existing SSH client with duplicate session ID early in the lifecycle of a new SSH client connection.)
func (*Server) ClientDisconnected ¶
ClientDisconnected handles clients disconnecting. Packet handlers are halted, but the client session is left intact to reserve the assigned IP addresses and retain network state in case the client soon reconnects.
type ServerConfig ¶
type ServerConfig struct { // Logger is used for logging events and metrics. Logger common.Logger // SudoNetworkConfigCommands specifies whether to use "sudo" // when executing network configuration commands. This is required // when the packet tunnel server is not run as root and when // process capabilities are not available (only Linux kernel 4.3+ // has the required capabilities support). The host sudoers file // must be configured to allow the tunnel server process user to // execute the commands invoked in configureServerInterface; see // the implementation for the appropriate platform. SudoNetworkConfigCommands bool // AllowNoIPv6NetworkConfiguration indicates that failures while // configuring tun interfaces and routing for IPv6 are to be // logged as warnings only. This option is intended to support // test cases on hosts without IPv6 and is not for production use; // the packet tunnel server will still accept IPv6 packets and // relay them to the tun device. // AllowNoIPv6NetworkConfiguration may not be supported on all // platforms. AllowNoIPv6NetworkConfiguration bool // EgressInterface is the interface to which client traffic is // masqueraded/NATed. For example, "eth0". If blank, a platform- // appropriate default is used. EgressInterface string // GetDNSResolverIPv4Addresses is a function which returns the // DNS resolvers to use as transparent DNS rewrite targets for // IPv4 DNS traffic. // // GetDNSResolverIPv4Addresses is invoked for each new client // session and the list of resolvers is stored with the session. // This is a compromise between checking current resolvers for // each packet (too expensive) and simply passing in a static // list (won't pick up resolver changes). As implemented, only // new client sessions will pick up resolver changes. // // Transparent DNS rewriting occurs when the client uses the // specific, target transparent DNS addresses specified by // GetTransparentDNSResolverIPv4/6Address. // // For outbound DNS packets with a target resolver IP address, // a random resolver is selected and used for the rewrite. // For inbound packets, _any_ resolver in the list is rewritten // back to the target resolver IP address. As a side-effect, // responses to client DNS packets originally destined for a // resolver in GetDNSResolverIPv4Addresses will be lost. GetDNSResolverIPv4Addresses func() []net.IP // GetDNSResolverIPv6Addresses is a function which returns the // DNS resolvers to use as transparent DNS rewrite targets for // IPv6 DNS traffic. It functions like GetDNSResolverIPv4Addresses. GetDNSResolverIPv6Addresses func() []net.IP // DownstreamPacketQueueSize specifies the size of the downstream // packet queue. The packet tunnel server multiplexes all client // packets through a single tun device, so when a packet is read, // it must be queued or dropped if it cannot be immediately routed // to the appropriate client. Note that the TCP and SSH windows // for the underlying channel transport will impact transfer rate // and queuing. // When DownstreamPacketQueueSize is 0, a default value tuned for // Psiphon is used. DownstreamPacketQueueSize int // MTU specifies the maximum transmission unit for the packet // tunnel. Clients must be configured with the same MTU. The // server's tun device will be set to this MTU value and is // assumed not to change for the duration of the server. // When MTU is 0, a default value is used. MTU int // SessionIdleExpirySeconds specifies how long to retain client // sessions which have no client attached. Sessions are retained // across client connections so reconnecting clients can resume // a previous session. Resuming avoids leasing new IP addresses // for reconnection, and also retains NAT state for active // tunneled connections. // // SessionIdleExpirySeconds is also, effectively, the lease // time for assigned IP addresses. SessionIdleExpirySeconds int }
ServerConfig specifies the configuration of a packet tunnel server.