server

package
v0.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 20, 2024 License: GPL-3.0 Imports: 75 Imported by: 0

Documentation

Overview

Package server implements the core tunnel functionality of a Psiphon server. The main function is RunServices, which runs one or all of a Psiphon API web server, a tunneling SSH server, and an Obfuscated SSH protocol server. The server configuration is created by the GenerateConfig function.

Index

Constants

View Source
const (
	MAX_API_PARAMS_SIZE = 256 * 1024 // 256KB
	PADDING_MAX_BYTES   = 16 * 1024

	CLIENT_PLATFORM_ANDROID = "Android"
	CLIENT_PLATFORM_WINDOWS = "Windows"
	CLIENT_PLATFORM_IOS     = "iOS"
)
View Source
const (
	SERVER_CONFIG_FILENAME                              = "psiphond.config"
	SERVER_TRAFFIC_RULES_CONFIG_FILENAME                = "psiphond-traffic-rules.config"
	SERVER_OSL_CONFIG_FILENAME                          = "psiphond-osl.config"
	SERVER_TACTICS_CONFIG_FILENAME                      = "psiphond-tactics.config"
	SERVER_ENTRY_FILENAME                               = "server-entry.dat"
	DEFAULT_SERVER_IP_ADDRESS                           = "127.0.0.1"
	WEB_SERVER_SECRET_BYTE_LENGTH                       = 32
	DISCOVERY_VALUE_KEY_BYTE_LENGTH                     = 32
	SSH_USERNAME_SUFFIX_BYTE_LENGTH                     = 8
	SSH_PASSWORD_BYTE_LENGTH                            = 32
	SSH_RSA_HOST_KEY_BITS                               = 2048
	SSH_OBFUSCATED_KEY_BYTE_LENGTH                      = 32
	PEAK_UPSTREAM_FAILURE_RATE_MINIMUM_SAMPLE_SIZE      = 10
	PERIODIC_GARBAGE_COLLECTION                         = 120 * time.Second
	STOP_ESTABLISH_TUNNELS_ESTABLISHED_CLIENT_THRESHOLD = 20
	DEFAULT_LOG_FILE_REOPEN_RETRIES                     = 25
)
View Source
const (
	DISCOVERY_STRATEGY_CLASSIC    = "classic"
	DISCOVERY_STRATEGY_CONSISTENT = "consistent"
)
View Source
const (
	DNS_SYSTEM_CONFIG_FILENAME      = "/etc/resolv.conf"
	DNS_SYSTEM_CONFIG_RELOAD_PERIOD = 5 * time.Second
	DNS_RESOLVER_PORT               = 53
)
View Source
const (
	GEOIP_UNKNOWN_VALUE     = "None"
	GEOIP_DATABASE_TYPE_ISP = "GeoIP2-ISP"
)
View Source
const (

	// Protocol version 1 clients can handle arbitrary length response bodies. Older clients
	// report no version number and expect at most 64K response bodies.
	MEEK_PROTOCOL_VERSION_1 = 1

	// Protocol version 2 clients initiate a session by sending an encrypted and obfuscated meek
	// cookie with their initial HTTP request. Connection information is contained within the
	// encrypted cookie payload. The server inspects the cookie and establishes a new session and
	// returns a new random session ID back to client via Set-Cookie header. The client uses this
	// session ID on all subsequent requests for the remainder of the session.
	MEEK_PROTOCOL_VERSION_2 = 2

	// Protocol version 3 clients include resiliency enhancements and will add a Range header
	// when retrying a request for a partially downloaded response payload.
	MEEK_PROTOCOL_VERSION_3 = 3

	MEEK_MAX_REQUEST_PAYLOAD_LENGTH                  = 65536
	MEEK_MIN_SESSION_ID_LENGTH                       = 8
	MEEK_MAX_SESSION_ID_LENGTH                       = 20
	MEEK_DEFAULT_TURN_AROUND_TIMEOUT                 = 10 * time.Millisecond
	MEEK_DEFAULT_EXTENDED_TURN_AROUND_TIMEOUT        = 100 * time.Millisecond
	MEEK_DEFAULT_SKIP_EXTENDED_TURN_AROUND_THRESHOLD = 8192
	MEEK_DEFAULT_MAX_SESSION_STALENESS               = 45 * time.Second
	MEEK_DEFAULT_HTTP_CLIENT_IO_TIMEOUT              = 45 * time.Second
	MEEK_DEFAULT_FRONTED_HTTP_CLIENT_IO_TIMEOUT      = 360 * time.Second
	MEEK_DEFAULT_RESPONSE_BUFFER_LENGTH              = 65536
	MEEK_DEFAULT_POOL_BUFFER_LENGTH                  = 65536
	MEEK_DEFAULT_POOL_BUFFER_COUNT                   = 2048
	MEEK_ENDPOINT_MAX_REQUEST_PAYLOAD_LENGTH         = 65536
)
View Source
const (
	REPLAY_CACHE_MAX_ENTRIES      = 100000
	REPLAY_CACHE_CLEANUP_INTERVAL = 1 * time.Minute
)
View Source
const (
	DEFAULT_IDLE_TCP_PORT_FORWARD_TIMEOUT_MILLISECONDS        = 30000
	DEFAULT_IDLE_UDP_PORT_FORWARD_TIMEOUT_MILLISECONDS        = 30000
	DEFAULT_DIAL_TCP_PORT_FORWARD_TIMEOUT_MILLISECONDS        = 10000
	DEFAULT_MAX_TCP_DIALING_PORT_FORWARD_COUNT                = 64
	DEFAULT_MAX_TCP_PORT_FORWARD_COUNT                        = 512
	DEFAULT_MAX_UDP_PORT_FORWARD_COUNT                        = 32
	DEFAULT_MEEK_RATE_LIMITER_GARBAGE_COLLECTOR_TRIGGER_COUNT = 5000
	DEFAULT_MEEK_RATE_LIMITER_REAP_HISTORY_FREQUENCY_SECONDS  = 300
	DEFAULT_MEEK_RATE_LIMITER_MAX_ENTRIES                     = 1000000
)
View Source
const (
	SSH_AUTH_LOG_PERIOD                   = 30 * time.Minute
	SSH_HANDSHAKE_TIMEOUT                 = 30 * time.Second
	SSH_BEGIN_HANDSHAKE_TIMEOUT           = 1 * time.Second
	SSH_CONNECTION_READ_DEADLINE          = 5 * time.Minute
	SSH_TCP_PORT_FORWARD_COPY_BUFFER_SIZE = 8192
	SSH_TCP_PORT_FORWARD_QUEUE_SIZE       = 1024
	SSH_KEEP_ALIVE_PAYLOAD_MIN_BYTES      = 0
	SSH_KEEP_ALIVE_PAYLOAD_MAX_BYTES      = 256
	SSH_SEND_OSL_INITIAL_RETRY_DELAY      = 30 * time.Second
	SSH_SEND_OSL_RETRY_FACTOR             = 2
	GEOIP_SESSION_CACHE_TTL               = 60 * time.Minute
	OSL_SESSION_CACHE_TTL                 = 5 * time.Minute
	MAX_AUTHORIZATIONS                    = 16
	PRE_HANDSHAKE_RANDOM_STREAM_MAX_COUNT = 1
	RANDOM_STREAM_MAX_BYTES               = 10485760
	ALERT_REQUEST_QUEUE_BUFFER_SIZE       = 16
)
View Source
const (
	TACTICS_CACHE_MAX_ENTRIES = 10000
)

Variables

This section is empty.

Functions

func CommonLogger

func CommonLogger(traceLogger *TraceLogger) *commonLogger

CommonLogger wraps a TraceLogger instance with an interface that conforms to common.Logger. This is used to make the TraceLogger available to other packages that don't import the "server" package.

func GenerateConfig

func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, []byte, []byte, error)

GenerateConfig creates a new Psiphon server config. It returns JSON encoded configs and a client-compatible "server entry" for the server. It generates all necessary secrets and key material, which are emitted in the config file and server entry as necessary.

GenerateConfig uses sample values for many fields. The intention is for generated configs to be used for testing or as examples for production setup, not to generate production-ready configurations.

When tactics key material is provided in GenerateConfigParams, tactics capabilities are added for all meek protocols in TunnelProtocolPorts.

func InitLogging

func InitLogging(config *Config) (retErr error)

InitLogging configures a logger according to the specified config params. If not called, the default logger set by the package init() is used. Concurrency notes: this should only be called from the main goroutine; InitLogging only has effect on the first call, as the logging facilities it initializes may be in use by other goroutines after that point.

func IsLogLevelDebug

func IsLogLevelDebug() bool

func ListenTLSTunnel

func ListenTLSTunnel(
	support *SupportServices,
	listener net.Listener,
	listenerTunnelProtocol string,
	listenerPort int,
) (net.Listener, error)

ListenTLSTunnel returns the listener of a new TLSTunnelServer. Note: the first Read or Write call on a connection returned by the listener will trigger the underlying TLS handshake.

func NewIntentionalPanicError

func NewIntentionalPanicError(errorMessage string) error

NewIntentionalPanicError creates a new IntentionalPanicError.

func NewLogWriter

func NewLogWriter() *io.PipeWriter

NewLogWriter returns an io.PipeWriter that can be used to write to the global logger. Caller must Close() the writer.

func RunServices

func RunServices(configJSON []byte) (retErr error)

RunServices initializes support functions including logging and GeoIP services; and then starts the server components and runs them until os.Interrupt or os.Kill signals are received. The config determines which components are run.

func ServerBPFEnabled

func ServerBPFEnabled() bool

ServerBPFEnabled indicates if BPF functionality is enabled.

Types

type Blocklist

type Blocklist struct {
	common.ReloadableFile
	// contains filtered or unexported fields
}

Blocklist provides a fast lookup of IP addresses and domains that are candidates for egress blocking. This is intended to be used to block malware and other malicious traffic.

The Reload function supports hot reloading of rules data while the server is running.

Limitations: the blocklist is implemented with in-memory Go maps, which limits the practical size of the blocklist.

func NewBlocklist

func NewBlocklist(filename string) (*Blocklist, error)

NewBlocklist creates a new block list.

The input file must be a 3 field comma-delimited and optional quote-escaped CSV. Fields: <IPv4 address>,<source>,<subject>.

IP addresses may appear multiple times in the input file; each distinct source/subject is associated with the IP address and returned in the Lookup tag list.

func (*Blocklist) LookupDomain

func (b *Blocklist) LookupDomain(domain string) []BlocklistTag

LookupDomain returns the blocklist tags for any domain that is on the blocklist, or returns nil for any domain not on the blocklist. Lookup may be called concurrently. The caller must not modify the return value.

func (*Blocklist) LookupIP

func (b *Blocklist) LookupIP(IPAddress net.IP) []BlocklistTag

LookupIP returns the blocklist tags for any IP address that is on the blocklist, or returns nil for any IP address not on the blocklist. Lookup may be called concurrently. The caller must not modify the return value.

type BlocklistTag

type BlocklistTag struct {
	Source  string
	Subject string
}

BlocklistTag indicates the source containing an IP address and the subject, or name of the suspected malicious traffic.

type CachedResponse

type CachedResponse struct {
	// contains filtered or unexported fields
}

CachedResponse is a data structure that supports meek protocol connection interruption resiliency: it stores payload data from the most recent response so that it may be resent if the client fails to receive it.

The meek server maintains one CachedResponse for each meek client. Psiphon's variant of meek streams response data, so responses are not fixed size. To limit the memory overhead of response caching, each CachedResponse has a fixed-size buffer that operates as a ring buffer, discarding older response bytes when the buffer fills. A CachedResponse that has discarded data may still satisfy a client retry where the client has already received part of the response payload.

A CachedResponse will also extend its capacity by borrowing buffers from a CachedResponseBufferPool, if available. When Reset is called, borrowed buffers are released back to the pool.

func NewCachedResponse

func NewCachedResponse(
	bufferSize int,
	extendedBufferPool *CachedResponseBufferPool) *CachedResponse

NewCachedResponse creates a CachedResponse with a fixed buffer of size bufferSize and borrowing buffers from extendedBufferPool.

func (*CachedResponse) Available

func (response *CachedResponse) Available() int

Available returns the size of the buffered response data.

func (*CachedResponse) CopyFromPosition

func (response *CachedResponse) CopyFromPosition(
	position int, writer io.Writer) (int, error)

CopyFromPosition writes the response data, starting at the specified position, to writer. Any data before the position is skipped. CopyFromPosition will return an error if the specified position is not available. CopyFromPosition will copy no data and return no error if the position is at the end of its available data. CopyFromPosition can be called repeatedly to read the same data -- it does not advance or modify the CachedResponse.

func (*CachedResponse) HasPosition

func (response *CachedResponse) HasPosition(position int) bool

HasPosition checks if the CachedResponse has buffered response data starting at or before the specified position.

func (*CachedResponse) Reset

func (response *CachedResponse) Reset()

Reset reinitializes the CachedResponse state to have no buffered response and releases all extended buffers back to the pool. Reset _must_ be called before discarding a CachedResponse or extended buffers will not be released.

func (*CachedResponse) Write

func (response *CachedResponse) Write(data []byte) (int, error)

Write appends data to the CachedResponse. All writes will succeed, but only the most recent bytes will be retained once the fixed buffer is full and no extended buffers are available.

Write may be called multiple times to record a single response; Reset should be called between responses.

Write conforms to the io.Writer interface.

type CachedResponseBufferPool

type CachedResponseBufferPool struct {
	// contains filtered or unexported fields
}

CachedResponseBufferPool is a fixed-size pool of fixed-size buffers that are used to temporarily extend the capacity of CachedResponses.

func NewCachedResponseBufferPool

func NewCachedResponseBufferPool(
	bufferSize, bufferCount int) *CachedResponseBufferPool

NewCachedResponseBufferPool creates a new CachedResponseBufferPool with the specified number of buffers. Buffers are allocated on demand and once allocated remain allocated.

func (*CachedResponseBufferPool) Get

func (pool *CachedResponseBufferPool) Get() []byte

Get returns a buffer, if one is available, or returns nil when no buffer is available. Get does not block. Call Put to release the buffer back to the pool.

Note: currently, Buffers are not zeroed between use by different CachedResponses owned by different clients. A bug resulting in cross-client data transfer exposes only OSSH ciphertext in the case of meek's use of CachedResponses.

func (*CachedResponseBufferPool) Put

func (pool *CachedResponseBufferPool) Put(buffer []byte)

Put releases a buffer back to the pool. The buffer must have been obtained from Get.

type Config

type Config struct {

	// LogLevel specifies the log level. Valid values are:
	// panic, fatal, error, warn, info, debug
	LogLevel string

	// LogFilename specifies the path of the file to log
	// to. When blank, logs are written to stderr.
	LogFilename string

	// LogFileReopenRetries specifies how many retries, each with a 1ms delay,
	// will be attempted after reopening a rotated log file fails. Retries
	// mitigate any race conditions between writes/reopens and file operations
	// performed by external log managers, such as logrotate.
	//
	// When omitted, DEFAULT_LOG_FILE_REOPEN_RETRIES is used.
	LogFileReopenRetries *int

	// LogFileCreateMode specifies that the Psiphon server should create a new
	// log file when one is not found, such as after rotation with logrotate
	// configured with nocreate. The value is the os.FileMode value to use when
	// creating the file.
	//
	// When omitted, the Psiphon server does not create log files.
	LogFileCreateMode *int

	// SkipPanickingLogWriter disables panicking when
	// unable to write any logs.
	SkipPanickingLogWriter bool

	// DiscoveryValueHMACKey is the network-wide secret value
	// used to determine a unique discovery strategy.
	DiscoveryValueHMACKey string

	// GeoIPDatabaseFilenames are paths of GeoIP2/GeoLite2
	// MaxMind database files. When empty, no GeoIP lookups are
	// performed. Each file is queried, in order, for the
	// logged fields: country code, city, and ISP. Multiple
	// file support accommodates the MaxMind distribution where
	// ISP data in a separate file.
	GeoIPDatabaseFilenames []string

	// PsinetDatabaseFilename is the path of the file containing
	// psinet.Database data.
	PsinetDatabaseFilename string

	// HostID identifies the server host; this value is included with all logs.
	HostID string

	// HostProvider identifies the server host provider; this value is
	// included with all logs and logged only when not blank.
	HostProvider string

	// ServerIPAddress is the public IP address of the server.
	ServerIPAddress string

	// TunnelProtocolPorts specifies which tunnel protocols to run
	// and which ports to listen on for each protocol. Valid tunnel
	// protocols include:
	// "SSH", "OSSH", "TLS-OSSH", "UNFRONTED-MEEK-OSSH", "UNFRONTED-MEEK-HTTPS-OSSH",
	// "UNFRONTED-MEEK-SESSION-TICKET-OSSH", "FRONTED-MEEK-OSSH",
	// "FRONTED-MEEK-QUIC-OSSH", "FRONTED-MEEK-HTTP-OSSH", "QUIC-OSSH",
	// "TAPDANCE-OSSH", abd "CONJURE-OSSH".
	TunnelProtocolPorts map[string]int

	// TunnelProtocolPassthroughAddresses specifies passthrough addresses to be
	// used for tunnel protocols configured in TunnelProtocolPorts. Passthrough
	// is a probing defense which relays all network traffic between a client and
	// the passthrough target when the client fails anti-probing tests.
	//
	// TunnelProtocolPassthroughAddresses is supported for:
	// "TLS-OSSH", "UNFRONTED-MEEK-HTTPS-OSSH",
	// "UNFRONTED-MEEK-SESSION-TICKET-OSSH", "UNFRONTED-MEEK-OSSH".
	TunnelProtocolPassthroughAddresses map[string]string

	// LegacyPassthrough indicates whether to expect legacy passthrough messages
	// from clients attempting to connect. This should be set for existing/legacy
	// passthrough servers only.
	LegacyPassthrough bool

	// EnableGQUIC indicates whether to enable legacy gQUIC QUIC-OSSH
	// versions, for backwards compatibility with all versions used by older
	// clients. Enabling gQUIC degrades the anti-probing stance of QUIC-OSSH,
	// as the legacy gQUIC stack will respond to probing packets.
	EnableGQUIC bool

	// SSHPrivateKey is the SSH host key. The same key is used for
	// all protocols, run by this server instance, which use SSH.
	SSHPrivateKey string

	// SSHServerVersion is the server version presented in the
	// identification string. The same value is used for all
	// protocols, run by this server instance, which use SSH.
	SSHServerVersion string

	// SSHUserName is the SSH user name to be presented by the
	// the tunnel-core client. The same value is used for all
	// protocols, run by this server instance, which use SSH.
	SSHUserName string

	// SSHPassword is the SSH password to be presented by the
	// the tunnel-core client. The same value is used for all
	// protocols, run by this server instance, which use SSH.
	SSHPassword string

	// SSHBeginHandshakeTimeoutMilliseconds specifies the timeout
	// for clients queueing to begin an SSH handshake. The default
	// is SSH_BEGIN_HANDSHAKE_TIMEOUT.
	SSHBeginHandshakeTimeoutMilliseconds *int

	// SSHHandshakeTimeoutMilliseconds specifies the timeout
	// before which a client must complete its handshake. The default
	// is SSH_HANDSHAKE_TIMEOUT.
	SSHHandshakeTimeoutMilliseconds *int

	// ObfuscatedSSHKey is the secret key for use in the Obfuscated
	// SSH protocol. The same secret key is used for all protocols,
	// run by this server instance, which use Obfuscated SSH.
	ObfuscatedSSHKey string

	// MeekCookieEncryptionPrivateKey is the NaCl private key used
	// to decrypt meek cookie payload sent from clients. The same
	// key is used for all meek protocols run by this server instance.
	MeekCookieEncryptionPrivateKey string

	// MeekObfuscatedKey is the secret key used for obfuscating
	// meek cookies sent from clients. The same key is used for all
	// meek protocols run by this server instance.
	//
	// NOTE: this key is also used by the TLS-OSSH protocol, which allows
	// clients with legacy unfronted meek-https server entries, that have the
	// passthrough capability, to connect with TLS-OSSH to the servers
	// corresponding to those server entries, which now support TLS-OSSH by
	// demultiplexing meek-https and TLS-OSSH over the meek-https port.
	MeekObfuscatedKey string

	// MeekProhibitedHeaders is a list of HTTP headers to check for
	// in client requests. If one of these headers is found, the
	// request fails. This is used to defend against abuse.
	MeekProhibitedHeaders []string

	// MeekRequiredHeaders is a list of HTTP header names and values that must
	// appear in requests. This is used to defend against abuse.
	MeekRequiredHeaders map[string]string

	// MeekServerCertificate specifies an optional certificate to use for meek
	// servers, in place of the default, randomly generate certificate. When
	// specified, the corresponding private key must be supplied in
	// MeekServerPrivateKey. Any specified certificate is used for all meek
	// listeners.
	MeekServerCertificate string

	// MeekServerPrivateKey is the private key corresponding to the optional
	// MeekServerCertificate parameter.
	MeekServerPrivateKey string

	// MeekProxyForwardedForHeaders is a list of HTTP headers which
	// may be added by downstream HTTP proxies or CDNs in front
	// of clients. These headers supply the original client IP
	// address, which is geolocated for stats purposes. Headers
	// include, for example, X-Forwarded-For. The header's value
	// is assumed to be a comma delimted list of IP addresses where
	// the client IP is the first IP address in the list. Meek protocols
	// look for these headers and use the client IP address from
	// the header if any one is present and the value is a valid
	// IP address; otherwise the direct connection remote address is
	// used as the client IP.
	MeekProxyForwardedForHeaders []string

	// MeekTurnAroundTimeoutMilliseconds specifies the amount of time meek will
	// wait for downstream bytes before responding to a request. The default is
	// MEEK_DEFAULT_TURN_AROUND_TIMEOUT.
	MeekTurnAroundTimeoutMilliseconds *int

	// MeekExtendedTurnAroundTimeoutMilliseconds specifies the extended amount of
	// time meek will wait for downstream bytes, as long as bytes arrive every
	// MeekTurnAroundTimeoutMilliseconds, before responding to a request. The
	// default is MEEK_DEFAULT_EXTENDED_TURN_AROUND_TIMEOUT.
	MeekExtendedTurnAroundTimeoutMilliseconds *int

	// MeekSkipExtendedTurnAroundThresholdBytes specifies when to skip the
	// extended turn around. When the number of bytes received in the client
	// request meets the threshold, optimize for upstream flows with quicker
	// round trip turn arounds.
	MeekSkipExtendedTurnAroundThresholdBytes *int

	// MeekMaxSessionStalenessMilliseconds specifies the TTL for meek sessions.
	// The default is MEEK_DEFAULT_MAX_SESSION_STALENESS.
	MeekMaxSessionStalenessMilliseconds *int

	// MeekHTTPClientIOTimeoutMilliseconds specifies meek HTTP server I/O
	// timeouts. The default is MEEK_DEFAULT_HTTP_CLIENT_IO_TIMEOUT.
	MeekHTTPClientIOTimeoutMilliseconds *int

	// MeekFrontedHTTPClientIOTimeoutMilliseconds specifies meek HTTP server
	// I/O timeouts for fronted protocols. The default is
	// MEEK_DEFAULT_FRONTED_HTTP_CLIENT_IO_TIMEOUT.
	MeekFrontedHTTPClientIOTimeoutMilliseconds *int

	// MeekCachedResponseBufferSize is the size of a private,
	// fixed-size buffer allocated for every meek client. The buffer
	// is used to cache response payload, allowing the client to retry
	// fetching when a network connection is interrupted. This retry
	// makes the OSSH tunnel within meek resilient to interruptions
	// at the HTTP TCP layer.
	// Larger buffers increase resiliency to interruption, but consume
	// more memory as buffers as never freed. The maximum size of a
	// response payload is a function of client activity, network
	// throughput and throttling.
	// A default of 64K is used when MeekCachedResponseBufferSize is 0.
	MeekCachedResponseBufferSize int

	// MeekCachedResponsePoolBufferSize is the size of a fixed-size,
	// shared buffer used to temporarily extend a private buffer when
	// MeekCachedResponseBufferSize is insufficient. Shared buffers
	// allow some clients to successfully retry longer response payloads
	// without allocating large buffers for all clients.
	// A default of 64K is used when MeekCachedResponsePoolBufferSize
	// is 0.
	MeekCachedResponsePoolBufferSize int

	// MeekCachedResponsePoolBufferCount is the number of shared
	// buffers. Shared buffers are allocated on first use and remain
	// allocated, so shared buffer count * size is roughly the memory
	// overhead of this facility.
	// A default of 2048 is used when MeekCachedResponsePoolBufferCount
	// is 0.
	MeekCachedResponsePoolBufferCount int

	// UDPInterceptUdpgwServerAddress specifies the network address of
	// a udpgw server which clients may be port forwarding to. When
	// specified, these TCP port forwards are intercepted and handled
	// directly by this server, which parses the SSH channel using the
	// udpgw protocol. Handling includes udpgw transparent DNS: tunneled
	// UDP DNS packets are rerouted to the host's DNS server.
	//
	// The intercept is applied before the port forward destination is
	// validated against SSH_DISALLOWED_PORT_FORWARD_HOSTS and
	// AllowTCPPorts. So the intercept address may be any otherwise
	// prohibited destination.
	UDPInterceptUdpgwServerAddress string

	// DNSResolverIPAddress specifies the IP address of a DNS server
	// to be used when "/etc/resolv.conf" doesn't exist or fails to
	// parse. When blank, "/etc/resolv.conf" must contain a usable
	// "nameserver" entry.
	DNSResolverIPAddress string

	// LoadMonitorPeriodSeconds indicates how frequently to log server
	// load information (number of connected clients per tunnel protocol,
	// number of running goroutines, amount of memory allocated, etc.)
	// The default, 0, disables load logging.
	LoadMonitorPeriodSeconds int

	// PeakUpstreamFailureRateMinimumSampleSize specifies the minimum number
	// of samples (e.g., upstream port forward attempts) that are required
	// before taking a failure rate snapshot which may be recorded as
	// peak_dns_failure_rate/peak_tcp_port_forward_failure_rate.  The default
	// is PEAK_UPSTREAM_FAILURE_RATE_SAMPLE_SIZE.
	PeakUpstreamFailureRateMinimumSampleSize *int

	// ProcessProfileOutputDirectory is the path of a directory to which
	// process profiles will be written when signaled with SIGUSR2. The
	// files are overwritten on each invocation. When set to the default
	// value, blank, no profiles are written on SIGUSR2. Profiles include
	// the default profiles here: https://golang.org/pkg/runtime/pprof/#Profile.
	ProcessProfileOutputDirectory string

	// ProcessBlockProfileDurationSeconds specifies the sample duration for
	// "block" profiling. For the default, 0, no "block" profile is taken.
	ProcessBlockProfileDurationSeconds int

	// ProcessCPUProfileDurationSeconds specifies the sample duration for
	// CPU profiling. For the default, 0, no CPU profile is taken.
	ProcessCPUProfileDurationSeconds int

	// TrafficRulesFilename is the path of a file containing a JSON-encoded
	// TrafficRulesSet, the traffic rules to apply to Psiphon client tunnels.
	TrafficRulesFilename string

	// OSLConfigFilename is the path of a file containing a JSON-encoded
	// OSL Config, the OSL schemes to apply to Psiphon client tunnels.
	OSLConfigFilename string

	// RunPacketTunnel specifies whether to run a packet tunnel.
	RunPacketTunnel bool

	// PacketTunnelEgressInterface specifies tun.ServerConfig.EgressInterface.
	PacketTunnelEgressInterface string

	// PacketTunnelEnableDNSFlowTracking sets
	// tun.ServerConfig.EnableDNSFlowTracking.
	PacketTunnelEnableDNSFlowTracking bool

	// PacketTunnelDownstreamPacketQueueSize specifies
	// tun.ServerConfig.DownStreamPacketQueueSize.
	PacketTunnelDownstreamPacketQueueSize int

	// PacketTunnelSessionIdleExpirySeconds specifies
	// tun.ServerConfig.SessionIdleExpirySeconds.
	PacketTunnelSessionIdleExpirySeconds int

	// PacketTunnelSudoNetworkConfigCommands sets
	// tun.ServerConfig.SudoNetworkConfigCommands.
	PacketTunnelSudoNetworkConfigCommands bool

	// RunPacketManipulator specifies whether to run a packet manipulator.
	RunPacketManipulator bool

	// MaxConcurrentSSHHandshakes specifies a limit on the number of concurrent
	// SSH handshake negotiations. This is set to mitigate spikes in memory
	// allocations and CPU usage associated with SSH handshakes when many clients
	// attempt to connect concurrently. When a maximum limit is specified and
	// reached, additional clients that establish TCP or meek connections will
	// be disconnected after a short wait for the number of concurrent handshakes
	// to drop below the limit.
	// The default, 0 is no limit.
	MaxConcurrentSSHHandshakes int

	// PeriodicGarbageCollectionSeconds turns on periodic calls to
	// debug.FreeOSMemory, every specified number of seconds, to force garbage
	// collection and memory scavenging. Specify 0 to disable. The default is
	// PERIODIC_GARBAGE_COLLECTION.
	PeriodicGarbageCollectionSeconds *int

	// StopEstablishTunnelsEstablishedClientThreshold sets the established client
	// threshold for dumping profiles when SIGTSTP is signaled. When there are
	// less than or equal to the threshold number of established clients,
	// profiles are dumped to aid investigating unusual load limited states that
	// occur when few clients are connected and load should be relatively low. A
	// profile dump is attempted at most once per process lifetime, the first
	// time the threshold is met. Disabled when < 0.
	StopEstablishTunnelsEstablishedClientThreshold *int

	// AccessControlVerificationKeyRing is the access control authorization
	// verification key ring used to verify signed authorizations presented
	// by clients. Verified, active (unexpired) access control types will be
	// available for matching in the TrafficRulesFilter for the client via
	// AuthorizedAccessTypes. All other authorizations are ignored.
	AccessControlVerificationKeyRing accesscontrol.VerificationKeyRing

	// TacticsConfigFilename is the path of a file containing a JSON-encoded
	// tactics server configuration.
	TacticsConfigFilename string

	// BlocklistFilename is the path of a file containing a CSV-encoded
	// blocklist configuration. See NewBlocklist for more file format
	// documentation.
	BlocklistFilename string

	// BlocklistActive indicates whether to actively prevent blocklist hits in
	// addition to logging events.
	BlocklistActive bool

	// AllowBogons disables port forward bogon checks. This should be used only
	// for testing.
	AllowBogons bool

	// EnableSteeringIPs enables meek server steering IP support.
	EnableSteeringIPs bool

	// OwnEncodedServerEntries is a list of the server's own encoded server
	// entries, idenfified by server entry tag. These values are used in the
	// handshake API to update clients that don't yet have a signed copy of these
	// server entries.
	//
	// For purposes of compartmentalization, each server receives only its own
	// server entries here; and, besides the discovery server entries, in
	// psinet.Database, necessary for the discovery feature, no other server
	// entries are stored on a Psiphon server.
	OwnEncodedServerEntries map[string]string

	// MeekServerRunInproxyBroker indicates whether to run an in-proxy broker
	// endpoint and service under the meek server.
	MeekServerRunInproxyBroker bool

	// MeekServerInproxyBrokerOnly indicates whether to run only an in-proxy
	// broker under the meek server, and not run any meek tunnel protocol. To
	// run the meek listener, a meek server protocol and port must still be
	// specified in TunnelProtocolPorts, but no other tunnel protocol
	// parameters are required.
	MeekServerInproxyBrokerOnly bool

	// InproxyBrokerSessionPrivateKey specifies the broker's in-proxy session
	// private key and derived public key used by in-proxy clients and
	// proxies. This value is required when running an in-proxy broker.
	InproxyBrokerSessionPrivateKey string

	// InproxyBrokerObfuscationRootSecret specifies the broker's in-proxy
	// session root obfuscation secret used by in-proxy clients and proxies.
	// This value is required when running an in-proxy broker.
	InproxyBrokerObfuscationRootSecret string

	// InproxyBrokerServerEntrySignaturePublicKey specifies the public key
	// used to verify Psiphon server entry signature. This value is required
	// when running an in-proxy broker.
	InproxyBrokerServerEntrySignaturePublicKey string

	// InproxyBrokerAllowCommonASNMatching overrides the default broker
	// matching behavior which doesn't match non-personal in-proxy clients
	// and proxies from the same ASN. This parameter is for testing only.
	InproxyBrokerAllowCommonASNMatching bool

	// InproxyBrokerAllowBogonWebRTCConnections overrides the default broker
	// SDP validation behavior, which doesn't allow private network WebRTC
	// candidates. This parameter is for testing only.
	InproxyBrokerAllowBogonWebRTCConnections bool

	// InproxyServerSessionPrivateKey specifies the server's in-proxy session
	// private key and derived public key used by brokers. This value is
	// required when running in-proxy tunnel protocols.
	InproxyServerSessionPrivateKey string

	// InproxyServerObfuscationRootSecret specifies the server's in-proxy
	// session root obfuscation secret used by brokers. This value is
	// required when running in-proxy tunnel protocols.
	InproxyServerObfuscationRootSecret string
	// contains filtered or unexported fields
}

Config specifies the configuration and behavior of a Psiphon server.

func LoadConfig

func LoadConfig(configJSON []byte) (*Config, error)

LoadConfig loads and validates a JSON encoded server config.

func (*Config) DumpProfilesOnStopEstablishTunnels

func (config *Config) DumpProfilesOnStopEstablishTunnels(establishedClientsCount int) bool

DumpProfilesOnStopEstablishTunnels indicates whether dump profiles due to an unexpectedly low number of established clients during high load.

func (*Config) GetFrontingProviderID

func (config *Config) GetFrontingProviderID() string

GetFrontingProviderID returns the fronting provider ID associated with the server's fronted protocol(s).

func (*Config) GetLogFileReopenConfig

func (config *Config) GetLogFileReopenConfig() (int, bool, os.FileMode)

GetLogFileReopenConfig gets the reopen retries, and create/mode inputs for rotate.NewRotatableFileWriter, which is used when writing to log files.

By default, we expect the log files to be managed by logrotate, with logrotate configured to re-create the next log file after rotation. As described in the documentation for rotate.NewRotatableFileWriter, and as observed in production, we occasionally need retries when attempting to reopen the log file post-rotation; and we avoid conflicts, and spurious re-rotations, by disabling file create in rotate.NewRotatableFileWriter. In large scale production, incidents requiring retry are very rare, so the retry delay is not expected to have a significant impact on performance.

The defaults may be overriden in the Config.

func (*Config) GetOwnEncodedServerEntry

func (config *Config) GetOwnEncodedServerEntry(serverEntryTag string) (string, bool)

GetOwnEncodedServerEntry returns one of the server's own server entries, as identified by the server entry tag.

func (*Config) GetProviderID

func (config *Config) GetProviderID() string

GetProviderID returns the provider ID associated with the server.

func (*Config) GetRegion

func (config *Config) GetRegion() string

GetRegion returns the region associated with the server.

func (*Config) GetRunningProtocols

func (config *Config) GetRunningProtocols() []string

GetRunningProtocols returns the list of protcols this server is running. The caller must not mutate the return value.

func (*Config) RunLoadMonitor

func (config *Config) RunLoadMonitor() bool

RunLoadMonitor indicates whether to monitor and log server load.

func (*Config) RunPeriodicGarbageCollection

func (config *Config) RunPeriodicGarbageCollection() bool

RunPeriodicGarbageCollection indicates whether to run periodic garbage collection.

type CustomJSONFormatter

type CustomJSONFormatter struct {
}

CustomJSONFormatter is a customized version of logrus.JSONFormatter

func (*CustomJSONFormatter) Format

func (f *CustomJSONFormatter) Format(entry *logrus.Entry) ([]byte, error)

Format implements logrus.Formatter. This is a customized version of the standard logrus.JSONFormatter adapted from: https://github.com/Sirupsen/logrus/blob/f1addc29722ba9f7651bc42b4198d0944b66e7c4/json_formatter.go

The changes are: - "time" is renamed to "timestamp" - there's an option to omit the standard "msg" and "level" fields

type DNSResolver

type DNSResolver struct {
	common.ReloadableFile
	// contains filtered or unexported fields
}

DNSResolver maintains fresh DNS resolver values, monitoring "/etc/resolv.conf" on platforms where it is available; and otherwise using a default value.

func NewDNSResolver

func NewDNSResolver(defaultResolver string) (*DNSResolver, error)

NewDNSResolver initializes a new DNSResolver, loading it with fresh resolver values. The load must succeed, so either "/etc/resolv.conf" must contain valid "nameserver" lines with a DNS server IP address, or a valid "defaultResolver" default value must be provided. On systems without "/etc/resolv.conf", "defaultResolver" is required.

The resolver is considered stale and reloaded if last checked more than 5 seconds before the last Get(), which is similar to frequencies in other implementations:

func (*DNSResolver) Get

func (dns *DNSResolver) Get() net.IP

Get returns one of the cached resolvers, selected at random, after first updating the cached values if they're stale. If reloading fails, the previous values are used.

Randomly selecting any one of the configured resolvers is expected to be more resiliant to failure; e.g., if one of the resolvers becomes unavailable.

func (*DNSResolver) GetAll

func (dns *DNSResolver) GetAll() []net.IP

GetAll returns a list of all DNS resolver addresses. Cached values are updated if they're stale. If reloading fails, the previous values are used.

func (*DNSResolver) GetAllIPv4

func (dns *DNSResolver) GetAllIPv4() []net.IP

GetAllIPv4 returns a list of all IPv4 DNS resolver addresses. Cached values are updated if they're stale. If reloading fails, the previous values are used.

func (*DNSResolver) GetAllIPv6

func (dns *DNSResolver) GetAllIPv6() []net.IP

GetAllIPv6 returns a list of all IPv6 DNS resolver addresses. Cached values are updated if they're stale. If reloading fails, the previous values are used.

type Discovery

type Discovery struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Discovery handles the discovery step of the "handshake" API request. It's safe for concurrent usage.

func (*Discovery) DiscoverServers

func (d *Discovery) DiscoverServers(clientIP net.IP) []string

DiscoverServers selects new encoded server entries to be "discovered" by the client, using the client's IP address as the input into the discovery algorithm.

func (*Discovery) Start

func (d *Discovery) Start() error

Start starts discovery.

func (*Discovery) Stop

func (d *Discovery) Stop()

Stop stops discovery and cleans up underlying resources.

type GenerateConfigParams

type GenerateConfigParams struct {
	LogFilename                        string
	SkipPanickingLogWriter             bool
	LogLevel                           string
	ServerEntrySignaturePublicKey      string
	ServerEntrySignaturePrivateKey     string
	ServerIPAddress                    string
	TunnelProtocolPorts                map[string]int
	TunnelProtocolPassthroughAddresses map[string]string
	TrafficRulesConfigFilename         string
	OSLConfigFilename                  string
	TacticsConfigFilename              string
	TacticsRequestPublicKey            string
	TacticsRequestObfuscatedKey        string
	Passthrough                        bool
	LegacyPassthrough                  bool
	LimitQUICVersions                  protocol.QUICVersions
	EnableGQUIC                        bool
	FrontingProviderID                 string
}

GenerateConfigParams specifies customizations to be applied to a generated server config.

type GeoIPData

type GeoIPData struct {
	Country string
	City    string
	ISP     string
	ASN     string
	ASO     string
}

GeoIPData is GeoIP data for a client session. Individual client IP addresses are neither logged nor explicitly referenced during a session. The GeoIP country, city, and ISP corresponding to a client IP address are resolved and then logged along with usage stats.

func NewGeoIPData

func NewGeoIPData() GeoIPData

NewGeoIPData returns a GeoIPData initialized with the expected GEOIP_UNKNOWN_VALUE values to be used when GeoIP lookup fails.

func (GeoIPData) SetClientLogFields

func (g GeoIPData) SetClientLogFields(logFields LogFields)

SetClientLogFields adds the GeoIPData fields to LogFields, following Psiphon field name and format conventions. For example, GeoIPData.Country is logged as client_region.

func (GeoIPData) SetClientLogFieldsWithPrefix

func (g GeoIPData) SetClientLogFieldsWithPrefix(prefix string, logFields LogFields)

SetClientLogFieldsWithPrefix adds the GeoIPData fields to LogFields, following Psiphon field name and format conventions and with the specified prefix. For example, GeoIPData.Country is logged as duplicate_authorization_client_region for the prefix "duplicate_authorization_".

func (GeoIPData) SetLogFieldsWithPrefix

func (g GeoIPData) SetLogFieldsWithPrefix(prefix string, name string, logFields LogFields)

SetLogFieldsWithPrefix adds the GeoIPData fields to LogFields, following Psiphon field name and format conventions and with the specified prefix and name. For example, GeoIPData.Country is logged as proxy_region for the prefix "" and name "proxy".

type GeoIPService

type GeoIPService struct {
	// contains filtered or unexported fields
}

GeoIPService implements GeoIP lookup and session/GeoIP caching. Lookup is via a MaxMind database; the ReloadDatabase function supports hot reloading of MaxMind data while the server is running.

func NewGeoIPService

func NewGeoIPService(databaseFilenames []string) (*GeoIPService, error)

NewGeoIPService initializes a new GeoIPService.

func (*GeoIPService) Lookup

func (geoIP *GeoIPService) Lookup(strIP string) GeoIPData

Lookup determines a GeoIPData for a given string client IP address.

func (*GeoIPService) LookupIP

func (geoIP *GeoIPService) LookupIP(IP net.IP) GeoIPData

LookupIP determines a GeoIPData for a given client IP address.

func (*GeoIPService) LookupISPForIP

func (geoIP *GeoIPService) LookupISPForIP(IP net.IP) GeoIPData

LookupISPForIP determines a GeoIPData for a given client IP address. Only ISP, ASN, and ASO fields will be populated. This lookup is faster than a full lookup. Benchmarks show this lookup is <= ~1 microsecond against the production geo IP database.

func (*GeoIPService) Reloaders

func (geoIP *GeoIPService) Reloaders() []common.Reloader

Reloaders gets the list of reloadable databases in use by the GeoIPService. This list is used to hot reload these databases.

type IntentionalPanicError

type IntentionalPanicError struct {
	// contains filtered or unexported fields
}

IntentionalPanicError is an error type that is used when calling panic() in a situation where recovers should propagate the panic.

func (IntentionalPanicError) Error

func (err IntentionalPanicError) Error() string

Error implements the error interface.

type LogFields

type LogFields logrus.Fields

LogFields is an alias for the field struct in the underlying logging package.

func (LogFields) Add

func (a LogFields) Add(b LogFields)

Add copies log fields from b to a, skipping fields which already exist, regardless of value, in a.

type MeekServer

type MeekServer struct {
	// contains filtered or unexported fields
}

MeekServer implements the meek protocol, which tunnels TCP traffic (in the case of Psiphon, Obfuscated SSH traffic) over HTTP. Meek may be fronted (through a CDN) or direct and may be HTTP or HTTPS.

Upstream traffic arrives in HTTP request bodies and downstream traffic is sent in response bodies. The sequence of traffic for a given flow is associated using a session ID that's set as a HTTP cookie for the client to submit with each request.

MeekServer hooks into TunnelServer via the net.Conn interface by transforming the HTTP payload traffic for a given session into net.Conn conforming Read()s and Write()s via the meekConn struct.

func NewMeekServer

func NewMeekServer(
	support *SupportServices,
	listener net.Listener,
	listenerTunnelProtocol string,
	listenerPort int,
	useTLS, isFronted, useObfuscatedSessionTickets, useHTTPNormalizer bool,
	clientHandler func(clientConn net.Conn, data *additionalTransportData),
	stopBroadcast <-chan struct{}) (*MeekServer, error)

NewMeekServer initializes a new meek server.

func (*MeekServer) ReloadTactics

func (server *MeekServer) ReloadTactics() error

ReloadTactics signals components to reload tactics and reinitialize as required when tactics may have changed.

func (*MeekServer) Run

func (server *MeekServer) Run() error

Run runs the meek server; this function blocks while serving HTTP or HTTPS connections on the specified listener. This function also runs a goroutine which cleans up expired meek client sessions.

To stop the meek server, both Close() the listener and set the stopBroadcast signal specified in NewMeekServer.

func (*MeekServer) ServeHTTP

func (server *MeekServer) ServeHTTP(responseWriter http.ResponseWriter, request *http.Request)

ServeHTTP handles meek client HTTP requests, where the request body contains upstream traffic and the response will contain downstream traffic.

type PanickingLogWriter

type PanickingLogWriter struct {
	// contains filtered or unexported fields
}

PanickingLogWriter wraps an io.Writer and intentionally panics when a Write() fails.

func NewPanickingLogWriter

func NewPanickingLogWriter(
	name string, writer io.Writer) *PanickingLogWriter

NewPanickingLogWriter creates a new PanickingLogWriter.

func (*PanickingLogWriter) Write

func (w *PanickingLogWriter) Write(p []byte) (n int, err error)

Write implements the io.Writer interface.

type ProtocolStats

type ProtocolStats map[string]map[string]interface{}

type RateLimits

type RateLimits struct {
	ReadUnthrottledBytes  *int64
	ReadBytesPerSecond    *int64
	WriteUnthrottledBytes *int64
	WriteBytesPerSecond   *int64
	CloseAfterExhausted   *bool

	// EstablishmentRead/WriteBytesPerSecond are used in place of
	// Read/WriteBytesPerSecond for tunnels in the establishment phase, from the
	// initial network connection up to the completion of the API handshake.
	EstablishmentReadBytesPerSecond  *int64
	EstablishmentWriteBytesPerSecond *int64

	// UnthrottleFirstTunnelOnly specifies whether any
	// ReadUnthrottledBytes/WriteUnthrottledBytes apply
	// only to the first tunnel in a session.
	UnthrottleFirstTunnelOnly *bool
}

RateLimits is a clone of common.RateLimits with pointers to fields to enable distinguishing between zero values and omitted values in JSON serialized traffic rules. See common.RateLimits for field descriptions.

func (*RateLimits) CommonRateLimits

func (rateLimits *RateLimits) CommonRateLimits(handshaked bool) common.RateLimits

CommonRateLimits converts a RateLimits to a common.RateLimits.

type RegionStats

type RegionStats map[string]map[string]map[string]interface{}

type ReplayCache

type ReplayCache struct {
	// contains filtered or unexported fields
}

ReplayCache is a cache of recently used and successful network obfuscation parameters that may be replayed -- reused -- for subsequent tunnel connections.

Server-side replay is analogous to client-side replay, with one key difference: server-side replay can be applied across multiple clients in the same GeoIP scope.

Replay is enabled with tactics, and tactics determine the tunnel quality targets for establishing and clearing replay parameters.

ReplayCache has a maximum capacity with an LRU strategy to cap memory overhead.

func NewReplayCache

func NewReplayCache(support *SupportServices) *ReplayCache

NewReplayCache creates a new ReplayCache.

func (*ReplayCache) FailedReplayParameters

func (r *ReplayCache) FailedReplayParameters(
	tunnelProtocol string,
	geoIPData GeoIPData,
	packetManipulationSpecName string,
	fragmentorSeed *prng.Seed)

FailedReplayParameters increments the count of tunnels which failed to complete any liveness test and API handshake after using replay parameters. Once a failure threshold is reached, cached replay parameters are cleared. Call this function for tunnels which meet the failure criteria.

func (*ReplayCache) Flush

func (r *ReplayCache) Flush()

Flush clears all entries in the ReplayCache. Flush should be called when tactics hot reload and change to clear any cached replay parameters that may be based on stale tactics.

func (*ReplayCache) GetMetrics

func (r *ReplayCache) GetMetrics() LogFields

GetMetrics returns a snapshop of current ReplayCache event counters and resets all counters to zero.

func (*ReplayCache) GetReplayFragmentor

func (r *ReplayCache) GetReplayFragmentor(
	tunnelProtocol string,
	geoIPData GeoIPData) (*prng.Seed, bool)

GetReplayFragmentor returns an active replay fragmentor seed for the specified tunnel protocol and GeoIP scope.

func (*ReplayCache) GetReplayPacketManipulation

func (r *ReplayCache) GetReplayPacketManipulation(
	tunnelProtocol string,
	geoIPData GeoIPData) (string, bool)

GetReplayPacketManipulation returns an active replay packet manipulation spec for the specified tunnel protocol and GeoIP scope.

While Flush should be called to clear parameters based on stale tactics, it's still possible for GetReplayPacketManipulation to return a spec name that's no longer in the current list of known specs.

func (*ReplayCache) GetReplayTargetDuration

func (r *ReplayCache) GetReplayTargetDuration(
	geoIPData GeoIPData) (bool, time.Duration, time.Duration)

GetReplayTargetDuration returns the tactics replay target tunnel duration for the specified GeoIP data. Tunnels which are active for the specified duration are candidates for setting or extending replay parameters. Wait for the returned wait duration before evaluating the tunnel duration. Once this target is met, call SetReplayParameters, which will check additional targets and conditionally set replay parameters.

func (*ReplayCache) SetReplayParameters

func (r *ReplayCache) SetReplayParameters(
	tunnelProtocol string,
	geoIPData GeoIPData,
	packetManipulationSpecName string,
	fragmentorSeed *prng.Seed,
	tunneledBytesUp int64,
	tunneledBytesDown int64)

SetReplayParameters sets replay parameters, packetManipulationSpecName and fragmentorSeed, for the specified tunnel protocol and GeoIP scope. Once set, replay parameters are active for a tactics-configurable TTL.

The specified tunneledBytesUp/Down must meet tactics replay bytes transferred targets. SetReplayParameters should be called only after first calling ReplayTargetDuration and ensuring the tunnel meets the active tunnel duration target. When cached replay parameters exist, their TTL is extended and any failure counts are reset to zero.

SetReplayParameters must be called only once per tunnel. Extending replay parameters TTL should only be done only immediately after a successful tunnel dial and target achievement, as this is the part of a tunnel lifecycle at highest risk of blocking.

The value pointed to by fragmentorSeed must not be mutated after calling SetReplayParameters.

type ServerTacticsParametersCache

type ServerTacticsParametersCache struct {
	// contains filtered or unexported fields
}

ServerTacticsParametersCache is a cache of filtered server-side tactics, intended to speed-up frequent tactics lookups.

Presently, the cache is targeted at pre-handshake lookups which are both the most time critical and have a low tactic cardinality, as only GeoIP filter inputs are available.

There is no TTL for cache entries as the cached filtered tactics remain valid until the tactics config changes; Flush must be called on tactics config hot reloads.

func NewServerTacticsParametersCache

func NewServerTacticsParametersCache(
	support *SupportServices) *ServerTacticsParametersCache

NewServerTacticsParametersCache creates a new ServerTacticsParametersCache.

func (*ServerTacticsParametersCache) Flush

func (c *ServerTacticsParametersCache) Flush()

func (*ServerTacticsParametersCache) Get

Get returns server-side tactics parameters for the specified GeoIP scope. Get is designed to be called before the API handshake and does not filter by API parameters. IsNil guards must be used when accessing the returned ParametersAccessor.

func (*ServerTacticsParametersCache) GetMetrics

func (c *ServerTacticsParametersCache) GetMetrics() LogFields

GetMetrics returns a snapshop of current ServerTacticsParametersCache event counters and resets all counters to zero.

type SupportServices

type SupportServices struct {
	// TODO: make all fields non-exported, none are accessed outside
	// of this package.
	Config                       *Config
	TrafficRulesSet              *TrafficRulesSet
	OSLConfig                    *osl.Config
	PsinetDatabase               *psinet.Database
	GeoIPService                 *GeoIPService
	DNSResolver                  *DNSResolver
	TunnelServer                 *TunnelServer
	PacketTunnelServer           *tun.Server
	TacticsServer                *tactics.Server
	Blocklist                    *Blocklist
	PacketManipulator            *packetman.Manipulator
	ReplayCache                  *ReplayCache
	ServerTacticsParametersCache *ServerTacticsParametersCache
	// contains filtered or unexported fields
}

SupportServices carries common and shared data components across different server components. SupportServices implements a hot reload of traffic rules, psinet database, and geo IP database components, which allows these data components to be refreshed without restarting the server process.

func NewSupportServices

func NewSupportServices(config *Config) (*SupportServices, error)

NewSupportServices initializes a new SupportServices.

func (*SupportServices) Reload

func (support *SupportServices) Reload()

Reload reinitializes traffic rules, psinet database, and geo IP database components. If any component fails to reload, an error is logged and Reload proceeds, using the previous state of the component.

type TLSTunnelConn

type TLSTunnelConn struct {
	net.Conn
	// contains filtered or unexported fields
}

TLSTunnelConn implements the net.Conn and common.MetricsSource interfaces.

func NewTLSTunnelConn

func NewTLSTunnelConn(conn net.Conn, server *TLSTunnelServer) *TLSTunnelConn

NewTLSTunnelConn initializes a new TLSTunnelConn.

func (*TLSTunnelConn) GetMetrics

func (conn *TLSTunnelConn) GetMetrics() common.LogFields

GetMetrics implements the common.MetricsSource interface.

type TLSTunnelListener

type TLSTunnelListener struct {
	net.Listener
	// contains filtered or unexported fields
}

TLSTunnelListener implements the net.Listener interface. Accept returns a net.Conn which implements the common.MetricsSource interface.

func NewTLSTunnelListener

func NewTLSTunnelListener(listener net.Listener, server *TLSTunnelServer) *TLSTunnelListener

NewTLSTunnelListener initializes a new TLSTunnelListener.

func (*TLSTunnelListener) Accept

func (l *TLSTunnelListener) Accept() (net.Conn, error)

type TLSTunnelServer

type TLSTunnelServer struct {
	// contains filtered or unexported fields
}

TLSTunnelServer tunnels TCP traffic (in the case of Psiphon, Obfuscated SSH traffic) over TLS.

func NewTLSTunnelServer

func NewTLSTunnelServer(
	support *SupportServices,
	listener net.Listener,
	listenerTunnelProtocol string,
	listenerPort int) (*TLSTunnelServer, error)

NewTLSTunnelServer initializes a new TLSTunnelServer.

type TacticsListener

type TacticsListener struct {
	net.Listener
	// contains filtered or unexported fields
}

TacticsListener wraps a net.Listener and applies server-side implementation of certain tactics parameters to accepted connections. Tactics filtering is limited to GeoIP attributes as the client has not yet sent API parameters. GeoIP uses the immediate peer IP, and so TacticsListener is suitable only for tactics that do not require the original client GeoIP when fronted.

In the case of inproxy tunnel protocols, the peer IP is the inproxy proxy IP, and the tactics apply to the 2nd hop.

func NewTacticsListener

func NewTacticsListener(
	support *SupportServices,
	listener net.Listener,
	tunnelProtocol string,
	geoIPLookup func(IPaddress string) GeoIPData) *TacticsListener

NewTacticsListener creates a new TacticsListener.

func (*TacticsListener) Accept

func (listener *TacticsListener) Accept() (net.Conn, error)

Accept calls the underlying listener's Accept, and then applies server-side tactics to new connections.

type TraceLogger

type TraceLogger struct {
	*logrus.Logger
}

TraceLogger adds single frame stack trace information to the underlying logging facilities.

func (*TraceLogger) LogPanicRecover

func (logger *TraceLogger) LogPanicRecover(recoverValue interface{}, stack []byte)

LogPanicRecover calls LogRawFieldsWithTimestamp with standard fields for logging recovered panics.

func (*TraceLogger) LogRawFieldsWithTimestamp

func (logger *TraceLogger) LogRawFieldsWithTimestamp(fields LogFields)

LogRawFieldsWithTimestamp directly logs the supplied fields adding only an additional "timestamp" field; and "host_id", "provider", and "build_rev" fields identifying this server and build. The stock "msg" and "level" fields are omitted.

This log is emitted at the Error level. This function exists to support API logs which have neither a natural message nor severity; and omitting these values here makes it easier to ship these logs to existing API log consumers.

Note that any existing "trace"/"host_id"/"provider"/"build_rev" field will be renamed to "field.<name>".

func (*TraceLogger) WithTrace

func (logger *TraceLogger) WithTrace() *logrus.Entry

WithTrace adds a "trace" field containing the caller's function name and source file line number; and "host_id", "provider", and "build_rev" fields identifying this server and build. Use this function when the log has no fields.

func (*TraceLogger) WithTraceFields

func (logger *TraceLogger) WithTraceFields(fields LogFields) *logrus.Entry

WithTraceFields adds a "trace" field containing the caller's function name and source file line number; and "host_id", "provider", and "build_rev" fields identifying this server and build. Use this function when the log has fields.

Note that any existing "trace"/"host_id"/"provider"/build_rev" field will be renamed to "field.<name>".

type TrafficRules

type TrafficRules struct {

	// RateLimits specifies data transfer rate limits for the
	// client traffic.
	RateLimits RateLimits

	// DialTCPPortForwardTimeoutMilliseconds is the timeout period
	// for dialing TCP port forwards. A value of 0 specifies no timeout.
	// When omitted in DefaultRules,
	// DEFAULT_TCP_PORT_FORWARD_DIAL_TIMEOUT_MILLISECONDS is used.
	DialTCPPortForwardTimeoutMilliseconds *int

	// IdleTCPPortForwardTimeoutMilliseconds is the timeout period
	// after which idle (no bytes flowing in either direction)
	// client TCP port forwards are preemptively closed.
	// A value of 0 specifies no idle timeout. When omitted in
	// DefaultRules, DEFAULT_IDLE_TCP_PORT_FORWARD_TIMEOUT_MILLISECONDS
	// is used.
	IdleTCPPortForwardTimeoutMilliseconds *int

	// IdleUDPPortForwardTimeoutMilliseconds is the timeout period
	// after which idle (no bytes flowing in either direction)
	// client UDP port forwards are preemptively closed.
	// A value of 0 specifies no idle timeout. When omitted in
	// DefaultRules, DEFAULT_IDLE_UDP_PORT_FORWARD_TIMEOUT_MILLISECONDS
	// is used.
	IdleUDPPortForwardTimeoutMilliseconds *int

	// MaxTCPDialingPortForwardCount is the maximum number of dialing
	// TCP port forwards each client may have open concurrently. When
	// persistently at the limit, new TCP port forwards are rejected.
	// A value of 0 specifies no maximum. When omitted in
	// DefaultRules, DEFAULT_MAX_TCP_DIALING_PORT_FORWARD_COUNT is used.
	MaxTCPDialingPortForwardCount *int

	// MaxTCPPortForwardCount is the maximum number of established TCP
	// port forwards each client may have open concurrently. If at the
	// limit when a new TCP port forward is established, the LRU
	// established TCP port forward is closed.
	// A value of 0 specifies no maximum. When omitted in
	// DefaultRules, DEFAULT_MAX_TCP_PORT_FORWARD_COUNT is used.
	MaxTCPPortForwardCount *int

	// MaxUDPPortForwardCount is the maximum number of UDP port
	// forwards each client may have open concurrently. If at the
	// limit when a new UDP port forward is created, the LRU
	// UDP port forward is closed.
	// A value of 0 specifies no maximum. When omitted in
	// DefaultRules, DEFAULT_MAX_UDP_PORT_FORWARD_COUNT is used.
	MaxUDPPortForwardCount *int

	// AllowTCPPorts specifies a list of TCP ports that are permitted for port
	// forwarding. When set, only ports in the list are accessible to clients.
	AllowTCPPorts *common.PortList

	// AllowUDPPorts specifies a list of UDP ports that are permitted for port
	// forwarding. When set, only ports in the list are accessible to clients.
	AllowUDPPorts *common.PortList

	// DisallowTCPPorts specifies a list of TCP ports that are not permitted for
	// port forwarding. DisallowTCPPorts takes priority over AllowTCPPorts and
	// AllowSubnets.
	DisallowTCPPorts *common.PortList

	// DisallowUDPPorts specifies a list of UDP ports that are not permitted for
	// port forwarding. DisallowUDPPorts takes priority over AllowUDPPorts and
	// AllowSubnets.
	DisallowUDPPorts *common.PortList

	// AllowSubnets specifies a list of IP address subnets for which all TCP
	// and UDP ports are allowed. This list is consulted if a port is not
	// allowed by the AllowTCPPorts or AllowUDPPorts configuration; but not
	// if a port is disallowed by DisallowTCPPorts, DisallowUDPPorts,
	// DisallowSubnets or DisallowASNs. Each entry is a IP subnet in CIDR
	// notation.
	AllowSubnets []string

	// AllowASNs specifies a list of ASNs for which all TCP and UDP ports are
	// allowed. This list is consulted if a port is not allowed by the
	// AllowTCPPorts or AllowUDPPorts configuration; but not if a port is
	// disallowed by DisallowTCPPorts, DisallowUDPPorts, DisallowSubnets or
	// DisallowASNs.
	AllowASNs []string

	// DisallowSubnets specifies a list of IP address subnets for which all
	// TCP and UDP ports are disallowed. Each entry is a IP subnet in CIDR
	// notation.
	DisallowSubnets []string

	// DisallowASNs specifies a list of ASNs for which all TCP and UDP ports
	// are disallowed.
	DisallowASNs []string

	// DisableDiscovery specifies whether to disable server entry discovery,
	// to manage load on discovery servers.
	DisableDiscovery *bool
}

TrafficRules specify the limits placed on client traffic.

func (*TrafficRules) AllowTCPPort

func (rules *TrafficRules) AllowTCPPort(
	geoIPService *GeoIPService, remoteIP net.IP, port int) bool

func (*TrafficRules) AllowUDPPort

func (rules *TrafficRules) AllowUDPPort(
	geoIPService *GeoIPService, remoteIP net.IP, port int) bool

type TrafficRulesFilter

type TrafficRulesFilter struct {

	// TunnelProtocols is a list of client tunnel protocols that must be
	// in use to match this filter. When omitted or empty, any protocol
	// matches.
	TunnelProtocols []string

	// Regions is a list of countries that the client must geolocate to in
	// order to match this filter. When omitted or empty, any client country
	// matches.
	Regions []string

	// ISPs is a list of ISPs that the client must geolocate to in order to
	// match this filter. When omitted or empty, any client ISP matches.
	ISPs []string

	// ASNs is a list of ASNs that the client must geolocate to in order to
	// match this filter. When omitted or empty, any client ASN matches.
	ASNs []string

	// Cities is a list of cities that the client must geolocate to in order to
	// match this filter. When omitted or empty, any client city matches.
	Cities []string

	// APIProtocol specifies whether the client must use the SSH
	// API protocol (when "ssh") or the web API protocol (when "web").
	// When omitted or blank, any API protocol matches.
	APIProtocol string

	// HandshakeParameters specifies handshake API parameter names and
	// a list of values, one of which must be specified to match this
	// filter. Only scalar string API parameters may be filtered.
	// Values may be patterns containing the '*' wildcard.
	HandshakeParameters map[string][]string

	// AuthorizedAccessTypes specifies a list of access types, at least
	// one of which the client must have presented an active authorization
	// for and which must not be revoked.
	// AuthorizedAccessTypes is ignored when AuthorizationsRevoked is true.
	AuthorizedAccessTypes []string

	// ActiveAuthorizationIDs specifies a list of authorization IDs, at least
	// one of which the client must have presented an active authorization
	// for and which must not be revoked.
	// ActiveAuthorizationIDs is ignored when AuthorizationsRevoked is true.
	ActiveAuthorizationIDs []string

	// AuthorizationsRevoked indicates whether the client's authorizations
	// must have been revoked. When true, authorizations must have been
	// revoked. When omitted or false, this field is ignored.
	AuthorizationsRevoked bool
	// contains filtered or unexported fields
}

TrafficRulesFilter defines a filter to match against client attributes.

type TrafficRulesSet

type TrafficRulesSet struct {
	common.ReloadableFile

	// DefaultRules are the base values to use as defaults for all
	// clients.
	DefaultRules TrafficRules

	// FilteredTrafficRules is an ordered list of filter/rules pairs.
	// For each client, the first matching Filter in FilteredTrafficRules
	// determines the additional Rules that are selected and applied
	// on top of DefaultRules.
	//
	// When ExceptFilter is present, a client must match Filter and not match
	// ExceptFilter.
	FilteredRules []struct {
		Filter       TrafficRulesFilter
		ExceptFilter *TrafficRulesFilter
		Rules        TrafficRules
	}

	// MeekRateLimiterHistorySize enables the late-stage meek rate limiter and
	// sets its history size. The late-stage meek rate limiter acts on client
	// IPs relayed in MeekProxyForwardedForHeaders, and so it must wait for
	// the HTTP headers to be read. This rate limiter immediately terminates
	// any client endpoint request or any request to create a new session, but
	// not any meek request for an existing session, if the
	// MeekRateLimiterHistorySize requests occur in
	// MeekRateLimiterThresholdSeconds.
	//
	// A use case for the the meek rate limiter is to mitigate dangling resource
	// usage that results from meek connections that are partially established
	// and then interrupted (e.g, drop packets after allowing up to the initial
	// HTTP request and header lines). In the case of CDN fronted meek, the CDN
	// itself may hold open the interrupted connection.
	//
	// The scope of rate limiting may be
	// limited using LimitMeekRateLimiterTunnelProtocols/Regions/ISPs/ASNs/Cities.
	//
	// Upon hot reload,
	// MeekRateLimiterHistorySize/MeekRateLimiterThresholdSeconds are not
	// changed for currently tracked client IPs; new values will apply to
	// newly tracked client IPs.
	MeekRateLimiterHistorySize int

	// MeekRateLimiterThresholdSeconds is part of the meek rate limiter
	// specification and must be set when MeekRateLimiterHistorySize is set.
	MeekRateLimiterThresholdSeconds int

	// MeekRateLimiterTunnelProtocols, if set, limits application of the meek
	// late-stage rate limiter to the specified meek protocols. When omitted or
	// empty, meek rate limiting is applied to all meek protocols.
	MeekRateLimiterTunnelProtocols []string

	// MeekRateLimiterRegions, if set, limits application of the meek
	// late-stage rate limiter to clients in the specified list of GeoIP
	// countries. When omitted or empty, meek rate limiting, if configured,
	// is applied to any client country.
	MeekRateLimiterRegions []string

	// MeekRateLimiterISPs, if set, limits application of the meek
	// late-stage rate limiter to clients in the specified list of GeoIP
	// ISPs. When omitted or empty, meek rate limiting, if configured,
	// is applied to any client ISP.
	MeekRateLimiterISPs []string

	// MeekRateLimiterASNs, if set, limits application of the meek
	// late-stage rate limiter to clients in the specified list of GeoIP
	// ASNs. When omitted or empty, meek rate limiting, if configured,
	// is applied to any client ASN.
	MeekRateLimiterASNs []string

	// MeekRateLimiterCities, if set, limits application of the meek
	// late-stage rate limiter to clients in the specified list of GeoIP
	// cities. When omitted or empty, meek rate limiting, if configured,
	// is applied to any client city.
	MeekRateLimiterCities []string

	// MeekRateLimiterGarbageCollectionTriggerCount specifies the number of
	// rate limit events after which garbage collection is manually triggered
	// in order to reclaim memory used by rate limited and other rejected
	// requests.
	//
	// A default of DEFAULT_MEEK_RATE_LIMITER_GARBAGE_COLLECTOR_TRIGGER_COUNT
	// is used when MeekRateLimiterGarbageCollectionTriggerCount is 0.
	MeekRateLimiterGarbageCollectionTriggerCount int

	// MeekRateLimiterReapHistoryFrequencySeconds specifies a schedule for
	// reaping old records from the rate limit history.
	//
	// A default of DEFAULT_MEEK_RATE_LIMITER_REAP_HISTORY_FREQUENCY_SECONDS
	// is used when MeekRateLimiterReapHistoryFrequencySeconds is 0.
	//
	// MeekRateLimiterReapHistoryFrequencySeconds is not applied upon hot
	// reload.
	MeekRateLimiterReapHistoryFrequencySeconds int

	// MeekRateLimiterMaxEntries specifies a maximum size for the rate limit
	// history.
	MeekRateLimiterMaxEntries int
}

TrafficRulesSet represents the various traffic rules to apply to Psiphon client tunnels. The Reload function supports hot reloading of rules data while the server is running.

For a given client, the traffic rules are determined by starting with DefaultRules, then finding the first (if any) FilteredTrafficRules match and overriding the defaults with fields set in the selected FilteredTrafficRules.

func NewTrafficRulesSet

func NewTrafficRulesSet(filename string) (*TrafficRulesSet, error)

NewTrafficRulesSet initializes a TrafficRulesSet with the rules data in the specified config file.

func (*TrafficRulesSet) GetMeekRateLimiterConfig

func (set *TrafficRulesSet) GetMeekRateLimiterConfig() (
	int, int, []string, []string, []string, []string, []string, int, int, int)

GetMeekRateLimiterConfig gets a snapshot of the meek rate limiter configuration values.

func (*TrafficRulesSet) GetTrafficRules

func (set *TrafficRulesSet) GetTrafficRules(
	isFirstTunnelInSession bool,
	tunnelProtocol string,
	geoIPData GeoIPData,
	state handshakeState) TrafficRules

GetTrafficRules determines the traffic rules for a client based on its attributes. For the return value TrafficRules, all pointer and slice fields are initialized, so nil checks are not required. The caller must not modify the returned TrafficRules.

func (*TrafficRulesSet) Validate

func (set *TrafficRulesSet) Validate() error

Validate checks for correct input formats in a TrafficRulesSet.

type TunnelServer

type TunnelServer struct {
	// contains filtered or unexported fields
}

TunnelServer is the main server that accepts Psiphon client connections, via various obfuscation protocols, and provides port forwarding (TCP and UDP) services to the Psiphon client. At its core, TunnelServer is an SSH server. SSH is the base protocol that provides port forward multiplexing, and transport security. Layered on top of SSH, optionally, is Obfuscated SSH and meek protocols, which provide further circumvention capabilities.

func NewTunnelServer

func NewTunnelServer(
	support *SupportServices,
	shutdownBroadcast <-chan struct{}) (*TunnelServer, error)

NewTunnelServer initializes a new tunnel server.

func (*TunnelServer) CheckEstablishTunnels

func (server *TunnelServer) CheckEstablishTunnels() bool

CheckEstablishTunnels returns whether new tunnels may be established or not, and increments a metrics counter when establishment is disallowed.

func (*TunnelServer) GetEstablishTunnelsMetrics

func (server *TunnelServer) GetEstablishTunnelsMetrics() (bool, int64)

GetEstablishTunnelsMetrics returns whether tunnel establishment is currently allowed and the number of tunnels rejected since due to not establishing since the last GetEstablishTunnelsMetrics call.

func (*TunnelServer) GetEstablishedClientCount

func (server *TunnelServer) GetEstablishedClientCount() int

GetEstablishedClientCount returns the number of currently established clients.

func (*TunnelServer) GetLoadStats

func (server *TunnelServer) GetLoadStats() (
	UpstreamStats, ProtocolStats, RegionStats)

GetLoadStats returns load stats for the tunnel server. The stats are broken down by protocol ("SSH", "OSSH", etc.) and type. Types of stats include current connected client count, total number of current port forwards.

func (*TunnelServer) ReloadTactics

func (server *TunnelServer) ReloadTactics() error

ReloadTactics signals components that use server-side tactics for one-time initialization to reload and use potentially changed parameters.

func (*TunnelServer) ResetAllClientOSLConfigs

func (server *TunnelServer) ResetAllClientOSLConfigs()

ResetAllClientOSLConfigs resets all established client OSL state to use the latest OSL config. Any existing OSL state is lost, including partial progress towards SLOKs.

func (*TunnelServer) ResetAllClientTrafficRules

func (server *TunnelServer) ResetAllClientTrafficRules()

ResetAllClientTrafficRules resets all established client traffic rules to use the latest config and client properties. Any existing traffic rule state is lost, including throttling state.

func (*TunnelServer) Run

func (server *TunnelServer) Run() error

Run runs the tunnel server; this function blocks while running a selection of listeners that handle connections using various obfuscation protocols.

Run listens on each designated tunnel port and spawns new goroutines to handle each client connection. It halts when shutdownBroadcast is signaled. A list of active clients is maintained, and when halting all clients are cleanly shutdown.

Each client goroutine handles its own obfuscation (optional), SSH handshake, SSH authentication, and then looping on client new channel requests. "direct-tcpip" channels, dynamic port fowards, are supported. When the UDPInterceptUdpgwServerAddress config parameter is configured, UDP port forwards over a TCP stream, following the udpgw protocol, are handled.

A new goroutine is spawned to handle each port forward for each client. Each port forward tracks its bytes transferred. Overall per-client stats for connection duration, GeoIP, number of port forwards, and bytes transferred are tracked and logged when the client shuts down.

Note: client handler goroutines may still be shutting down after Run() returns. See comment in sshClient.stop(). TODO: fully synchronized shutdown.

func (*TunnelServer) SetEstablishTunnels

func (server *TunnelServer) SetEstablishTunnels(establish bool)

SetEstablishTunnels sets whether new tunnels may be established or not. When not establishing, incoming connections are immediately closed.

type UpstreamStats

type UpstreamStats map[string]interface{}

Directories

Path Synopsis
Package discovery implements the Psiphon discovery algorithms.
Package discovery implements the Psiphon discovery algorithms.
Package psinet implements psinet database services.
Package psinet implements psinet database services.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL