psiphon

package
v0.0.12-alpha Latest Latest
Warning

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

Go to latest
Published: Dec 5, 2016 License: GPL-3.0 Imports: 45 Imported by: 0

Documentation

Overview

Package psiphon implements the core tunnel functionality of a Psiphon client. The main function is RunForever, which runs a Controller that obtains lists of servers, establishes tunnel connections, and runs local proxies through which tunneled traffic may be sent.

Index

Constants

View Source
const (
	LEGACY_DATA_STORE_FILENAME                           = "psiphon.db"
	DATA_STORE_FILENAME                                  = "psiphon.boltdb"
	CONNECTION_WORKER_POOL_SIZE                          = 10
	TUNNEL_POOL_SIZE                                     = 1
	TUNNEL_CONNECT_TIMEOUT_SECONDS                       = 20
	TUNNEL_OPERATE_SHUTDOWN_TIMEOUT                      = 1 * time.Second
	TUNNEL_PORT_FORWARD_DIAL_TIMEOUT_SECONDS             = 10
	TUNNEL_SSH_KEEP_ALIVE_PAYLOAD_MAX_BYTES              = 256
	TUNNEL_SSH_KEEP_ALIVE_PERIOD_MIN                     = 60 * time.Second
	TUNNEL_SSH_KEEP_ALIVE_PERIOD_MAX                     = 120 * time.Second
	TUNNEL_SSH_KEEP_ALIVE_PERIODIC_TIMEOUT_SECONDS       = 30
	TUNNEL_SSH_KEEP_ALIVE_PERIODIC_INACTIVE_PERIOD       = 10 * time.Second
	TUNNEL_SSH_KEEP_ALIVE_PROBE_TIMEOUT_SECONDS          = 5
	TUNNEL_SSH_KEEP_ALIVE_PROBE_INACTIVE_PERIOD          = 10 * time.Second
	ESTABLISH_TUNNEL_TIMEOUT_SECONDS                     = 300
	ESTABLISH_TUNNEL_WORK_TIME                           = 60 * time.Second
	ESTABLISH_TUNNEL_PAUSE_PERIOD_SECONDS                = 5
	ESTABLISH_TUNNEL_SERVER_AFFINITY_GRACE_PERIOD        = 1 * time.Second
	HTTP_PROXY_ORIGIN_SERVER_TIMEOUT_SECONDS             = 15
	HTTP_PROXY_MAX_IDLE_CONNECTIONS_PER_HOST             = 50
	FETCH_REMOTE_SERVER_LIST_TIMEOUT_SECONDS             = 30
	FETCH_REMOTE_SERVER_LIST_RETRY_PERIOD_SECONDS        = 30
	FETCH_REMOTE_SERVER_LIST_STALE_PERIOD                = 6 * time.Hour
	PSIPHON_API_SERVER_TIMEOUT_SECONDS                   = 20
	PSIPHON_API_SHUTDOWN_SERVER_TIMEOUT                  = 1 * time.Second
	PSIPHON_API_STATUS_REQUEST_PERIOD_MIN                = 5 * time.Minute
	PSIPHON_API_STATUS_REQUEST_PERIOD_MAX                = 10 * time.Minute
	PSIPHON_API_STATUS_REQUEST_SHORT_PERIOD_MIN          = 5 * time.Second
	PSIPHON_API_STATUS_REQUEST_SHORT_PERIOD_MAX          = 10 * time.Second
	PSIPHON_API_STATUS_REQUEST_PADDING_MAX_BYTES         = 256
	PSIPHON_API_CONNECTED_REQUEST_PERIOD                 = 24 * time.Hour
	PSIPHON_API_CONNECTED_REQUEST_RETRY_PERIOD           = 5 * time.Second
	PSIPHON_API_PERSISTENT_STATS_MAX_COUNT               = 100
	PSIPHON_API_CLIENT_VERIFICATION_REQUEST_RETRY_PERIOD = 5 * time.Second
	PSIPHON_API_CLIENT_VERIFICATION_REQUEST_MAX_RETRIES  = 10
	FETCH_ROUTES_TIMEOUT_SECONDS                         = 60
	DOWNLOAD_UPGRADE_TIMEOUT                             = 15 * time.Minute
	DOWNLOAD_UPGRADE_RETRY_PERIOD_SECONDS                = 30
	DOWNLOAD_UPGRADE_STALE_PERIOD                        = 6 * time.Hour
	IMPAIRED_PROTOCOL_CLASSIFICATION_DURATION            = 2 * time.Minute
	IMPAIRED_PROTOCOL_CLASSIFICATION_THRESHOLD           = 3
	TOTAL_BYTES_TRANSFERRED_NOTICE_PERIOD                = 5 * time.Minute
)
View Source
const (
	DATA_STORE_LAST_CONNECTED_KEY           = "lastConnected"
	DATA_STORE_OSL_REGISTRY_KEY             = "OSLRegistry"
	PERSISTENT_STAT_TYPE_TUNNEL             = tunnelStatsBucket
	PERSISTENT_STAT_TYPE_REMOTE_SERVER_LIST = remoteServerListStatsBucket
)
View Source
const (
	FEEDBACK_UPLOAD_MAX_RETRIES         = 5
	FEEDBACK_UPLOAD_RETRY_DELAY_SECONDS = 300
	FEEDBACK_UPLOAD_TIMEOUT_SECONDS     = 30
)
View Source
const (
	URL_PROXY_TUNNELED_REQUEST_PATH = "/tunneled/"
	URL_PROXY_DIRECT_REQUEST_PATH   = "/direct/"
)
View Source
const (
	MEEK_PROTOCOL_VERSION          = 2
	MEEK_COOKIE_MAX_PADDING        = 32
	MAX_SEND_PAYLOAD_LENGTH        = 65536
	FULL_RECEIVE_BUFFER_LENGTH     = 4194304
	READ_PAYLOAD_CHUNK_LENGTH      = 65536
	MIN_POLL_INTERVAL              = 100 * time.Millisecond
	MAX_POLL_INTERVAL              = 5 * time.Second
	POLL_INTERNAL_MULTIPLIER       = 1.5
	MEEK_ROUND_TRIP_RETRY_DEADLINE = 1 * time.Second
	MEEK_ROUND_TRIP_RETRY_DELAY    = 50 * time.Millisecond
	MEEK_ROUND_TRIP_TIMEOUT        = 20 * time.Second
)
View Source
const DNS_PORT = 53

Variables

This section is empty.

Functions

func AddPKCS7Padding

func AddPKCS7Padding(src []byte, blockSize int) []byte

Pad src to the next block boundary with PKCS7 padding (https://tools.ietf.org/html/rfc5652#section-6.3).

func ClearReportedPersistentStats

func ClearReportedPersistentStats(stats map[string][][]byte) error

ClearReportedPersistentStats deletes a list of persistent stat records that were successfully reported.

func CountServerEntries

func CountServerEntries(region, tunnelProtocol string) int

CountServerEntries returns a count of stored servers for the specified region and protocol.

func CountUnreportedPersistentStats

func CountUnreportedPersistentStats() int

CountUnreportedPersistentStats returns the number of persistent stat records in StateUnreported.

func CustomTLSDial

func CustomTLSDial(network, addr string, config *CustomTLSConfig) (net.Conn, error)

CustomTLSDialWithDialer is a customized replacement for tls.Dial. Based on tlsdialer.DialWithDialer which is based on crypto/tls.DialWithDialer.

tlsdialer comment:

Note - if sendServerName is false, the VerifiedChains field on the
connection's ConnectionState will never get populated.

func DecodeCertificate

func DecodeCertificate(encodedCertificate string) (certificate *x509.Certificate, err error)

func DeleteSLOKs

func DeleteSLOKs() error

DeleteSLOKs deletes all SLOK records.

func DialTCP

func DialTCP(addr string, config *DialConfig) (conn net.Conn, err error)

DialTCP creates a new, connected TCPConn.

func DownloadUpgrade

func DownloadUpgrade(
	config *Config,
	handshakeVersion string,
	tunnel *Tunnel,
	untunneledDialConfig *DialConfig) error

DownloadUpgrade performs a resumable download of client upgrade files.

While downloading/resuming, a temporary file is used. Once the download is complete, a notice is issued and the upgrade is available at the destination specified in config.UpgradeDownloadFilename.

The upgrade download may be either tunneled or untunneled. As the untunneled case may happen with no handshake request response, the downloader cannot rely on having the upgrade_client_version output from handshake and instead this logic performs a comparison between the config.ClientVersion and the client version recorded in the remote entity's UpgradeDownloadClientVersionHeader. A HEAD request is made to check the version before proceeding with a full download.

NOTE: This code does not check that any existing file at config.UpgradeDownloadFilename is actually the version specified in handshakeVersion.

TODO: This logic requires the outer client to *omit* config.UpgradeDownloadFilename when there's already a downloaded upgrade pending. Because the outer client currently handles the authenticated package phase, and because the outer client deletes the intermediate files (including config.UpgradeDownloadFilename), if the outer client does not omit config.UpgradeDownloadFilename then the new version will be downloaded repeatedly. Implement a new scheme where tunnel core does the authenticated package phase and tracks the the output by version number so that (a) tunnel core knows when it's not necessary to re-download; (b) newer upgrades will be downloaded even when an older upgrade is still pending install by the outer client.

func FetchCommonRemoteServerList

func FetchCommonRemoteServerList(
	config *Config,
	tunnel *Tunnel,
	untunneledDialConfig *DialConfig) error

FetchCommonRemoteServerList downloads the common remote server list from config.RemoteServerListUrl. It validates its digital signature using the public key config.RemoteServerListSignaturePublicKey and parses the data field into ServerEntry records. config.RemoteServerListDownloadFilename is the location to store the download. As the download is resumed after failure, this filename must be unique and persistent.

func FetchObfuscatedServerLists

func FetchObfuscatedServerLists(
	config *Config,
	tunnel *Tunnel,
	untunneledDialConfig *DialConfig) error

FetchObfuscatedServerLists downloads the obfuscated remote server lists from config.ObfuscatedServerListRootURL. It first downloads the OSL registry, and then downloads each seeded OSL advertised in the registry. All downloads are resumable, ETags are used to skip both an unchanged registry or unchanged OSL files, and when an individual download fails, the fetch proceeds if it can. Authenticated package digital signatures are validated using the public key config.RemoteServerListSignaturePublicKey. config.ObfuscatedServerListDownloadDirectory is the location to store the downloaded files. As downloads are resumed after failure, this directory must be unique and persistent.

func FilterUrlError

func FilterUrlError(err error) error

FilterUrlError transforms an error, when it is a url.Error, removing the URL value. This is to avoid logging private user data in cases where the URL may be a user input value. This function is used with errors returned by net/http and net/url, which are (currently) of type url.Error. In particular, the round trip function used by our HttpProxy, http.Client.Do, returns errors of type url.Error, with the URL being the url sent from the user's tunneled applications: https://github.com/golang/go/blob/release-branch.go1.4/src/net/http/client.go#L394

func GetEmitDiagnoticNotices

func GetEmitDiagnoticNotices() bool

GetEmitDiagnoticNotices returns the current state of emitting diagnostic notices.

func GetKeyValue

func GetKeyValue(key string) (value string, err error)

GetKeyValue retrieves the value for a given key. If not found, it returns an empty string value.

func GetNotice

func GetNotice(notice []byte) (
	noticeType string, payload map[string]interface{}, err error)

GetNotice receives a JSON encoded object and attempts to parse it as a Notice. The type is returned as a string and the payload as a generic map.

func GetSLOK

func GetSLOK(id []byte) (key []byte, err error)

GetSLOK returns a SLOK key for the specified ID. The return value is nil if the SLOK is not found.

func GetServerEntryIpAddresses

func GetServerEntryIpAddresses() (ipAddresses []string, err error)

GetServerEntryIpAddresses returns an array containing all stored server IP addresses.

func GetSplitTunnelRoutesData

func GetSplitTunnelRoutesData(region string) (data []byte, err error)

GetSplitTunnelRoutesData retrieves the cached routes data for the specified region. If not found, it returns a nil value.

func GetSplitTunnelRoutesETag

func GetSplitTunnelRoutesETag(region string) (etag string, err error)

GetSplitTunnelRoutesETag retrieves the etag for cached routes data for the specified region. If not found, it returns an empty string value.

func GetUrlETag

func GetUrlETag(url string) (etag string, err error)

GetUrlETag retrieves a previously stored an ETag for the specfied URL. If not found, it returns an empty string value.

func HandleOSLRequest

func HandleOSLRequest(
	tunnelOwner TunnelOwner, tunnel *Tunnel, payload []byte) error

func HandleServerRequest

func HandleServerRequest(
	tunnelOwner TunnelOwner, tunnel *Tunnel, name string, payload []byte) error

func InitDataStore

func InitDataStore(config *Config) (err error)

InitDataStore initializes the singleton instance of dataStore. This function uses a sync.Once and is safe for use by concurrent goroutines. The underlying sql.DB connection pool is also safe.

Note: the sync.Once was more useful when initDataStore was private and called on-demand by the public functions below. Now we require an explicit InitDataStore() call with the filename passed in. The on-demand calls have been replaced by checkInitDataStore() to assert that Init was called.

func IsAddressInUseError

func IsAddressInUseError(err error) bool

IsAddressInUseError returns true when the err is due to EADDRINUSE/WSAEADDRINUSE.

func LocalProxyRelay

func LocalProxyRelay(proxyType string, localConn, remoteConn net.Conn)

LocalProxyRelay sends to remoteConn bytes received from localConn, and sends to localConn bytes received from remoteConn.

func LookupIP

func LookupIP(host string, config *DialConfig) (addrs []net.IP, err error)

LookupIP resolves a hostname. When BindToDevice is not required, it simply uses net.LookupIP. When BindToDevice is required, LookupIP explicitly creates a UDP socket, binds it to the device, and makes an explicit DNS request to the specified DNS resolver.

func MakeCompatibleServerEntry

func MakeCompatibleServerEntry(serverEntry *protocol.ServerEntry) *protocol.ServerEntry

MakeCompatibleServerEntry provides backwards compatibility with old server entries which have a single meekFrontingDomain and not a meekFrontingAddresses array. By copying this one meekFrontingDomain into meekFrontingAddresses, this client effectively uses that single value as legacy clients do.

func MakeDownloadHttpClient

func MakeDownloadHttpClient(
	config *Config,
	tunnel *Tunnel,
	untunneledDialConfig *DialConfig,
	requestUrl string,
	requestTimeout time.Duration) (*http.Client, string, error)

MakeDownloadHttpClient is a resusable helper that sets up a http.Client for use either untunneled or through a tunnel. See MakeUntunneledHttpsClient for a note about request URL rewritting.

func MakeSessionId

func MakeSessionId() (sessionId string, err error)

MakeSessionId creates a new session ID. The same session ID is used across multi-tunnel controller runs, where each tunnel has its own ServerContext instance. In server-side stats, we now consider a "session" to be the lifetime of the Controller (e.g., the user's commanded start and stop) and we measure this duration as well as the duration of each tunnel within the session.

func MakeTunneledHttpClient

func MakeTunneledHttpClient(
	config *Config,
	tunnel *Tunnel,
	requestTimeout time.Duration) (*http.Client, error)

MakeTunneledHttpClient returns a net/http.Client which is configured to use custom dialing features including tunneled dialing and, optionally, UseTrustedCACertificatesForStockTLS. Unlike MakeUntunneledHttpsClient and makePsiphonHttpsClient, This http.Client uses stock TLS and no scheme transformation hack is required.

func MakeUntunneledHttpsClient

func MakeUntunneledHttpsClient(
	dialConfig *DialConfig,
	verifyLegacyCertificate *x509.Certificate,
	requestUrl string,
	requestTimeout time.Duration) (*http.Client, string, error)

MakeUntunneledHttpsClient returns a net/http.Client which is configured to use custom dialing features -- including BindToDevice, UseIndistinguishableTLS, etc. -- for a specific HTTPS request URL. If verifyLegacyCertificate is not nil, it's used for certificate verification.

Because UseIndistinguishableTLS requires a hack to work with net/http, MakeUntunneledHttpClient may return a modified request URL to be used. Callers should always use this return value to make requests, not the input value.

MakeUntunneledHttpsClient ignores the input requestUrl scheme, which may be "http" or "https", and always performs HTTPS requests.

func NoticeActiveTunnel

func NoticeActiveTunnel(ipAddress, protocol string)

NoticeActiveTunnel is a successful connection that is used as an active tunnel for port forwarding

func NoticeAlert

func NoticeAlert(format string, args ...interface{})

NoticeAlert is an alert message; typically a recoverable error condition

func NoticeAvailableEgressRegions

func NoticeAvailableEgressRegions(regions []string)

NoticeAvailableEgressRegions is what regions are available for egress from. Consecutive reports of the same list of regions are suppressed.

func NoticeBuildInfo

func NoticeBuildInfo()

NoticeBuildInfo reports build version info.

func NoticeBytesTransferred

func NoticeBytesTransferred(ipAddress string, sent, received int64)

NoticeBytesTransferred reports how many tunneled bytes have been transferred since the last NoticeBytesTransferred, for the tunnel to the server at ipAddress.

func NoticeCandidateServers

func NoticeCandidateServers(region, protocol string, count int)

NoticeCandidateServers is how many possible servers are available for the selected region and protocol

func NoticeClientIsLatestVersion

func NoticeClientIsLatestVersion(availableVersion string)

NoticeClientIsLatestVersion reports that an upgrade check was made and the client is already the latest version. availableVersion is the version available for download, if known.

func NoticeClientRegion

func NoticeClientRegion(region string)

NoticeClientRegion is the client's region, as determined by the server and reported to the client in the handshake.

func NoticeClientUpgradeAvailable

func NoticeClientUpgradeAvailable(version string)

NoticeClientUpgradeAvailable is an available client upgrade, as per the handshake. The client should download and install an upgrade.

func NoticeClientUpgradeDownloaded

func NoticeClientUpgradeDownloaded(filename string)

NoticeClientUpgradeDownloaded indicates that a client upgrade download is complete and available at the destination specified.

func NoticeClientUpgradeDownloadedBytes

func NoticeClientUpgradeDownloadedBytes(bytes int64)

NoticeClientUpgradeDownloadedBytes reports client upgrade download progress.

func NoticeClientVerificationRequestCompleted

func NoticeClientVerificationRequestCompleted(ipAddress string)

func NoticeClientVerificationRequired

func NoticeClientVerificationRequired(nonce string, ttlSeconds int, resetCache bool)

NoticeClientVerificationRequired indicates that client verification is required, as indicated by the handshake. The client should submit a client verification payload. Empty nonce is allowed, if ttlSeconds is 0 the client should not send verification payload to the server. If resetCache is set the client must always perform a new verification and update its cache

func NoticeConnectedTunnelDialStats

func NoticeConnectedTunnelDialStats(ipAddress string, tunnelDialStats *TunnelDialStats)

NoticeConnectedTunnelDialStats reports extra network details for tunnel connections that required extra configuration.

func NoticeConnectingServer

func NoticeConnectingServer(ipAddress, region, protocol, directTCPDialAddress string, meekConfig *MeekConfig)

NoticeConnectingServer is details on a connection attempt

func NoticeError

func NoticeError(format string, args ...interface{})

NoticeError is an error message; typically an unrecoverable error condition

func NoticeExiting

func NoticeExiting()

NoticeExiting indicates that tunnel-core is exiting imminently.

func NoticeHomepage

func NoticeHomepage(url string)

NoticeHomepage is a sponsor homepage, as per the handshake. The client should display the sponsor's homepage.

func NoticeHttpProxyPortInUse

func NoticeHttpProxyPortInUse(port int)

NoticeSocksProxyPortInUse is a failure to use the configured LocalHttpProxyPort

func NoticeImpairedProtocolClassification

func NoticeImpairedProtocolClassification(impairedProtocolClassification map[string]int)

func NoticeInfo

func NoticeInfo(format string, args ...interface{})

NoticeInfo is an informational message

func NoticeListeningHttpProxyPort

func NoticeListeningHttpProxyPort(port int)

NoticeListeningSocksProxyPort is the selected port for the listening local HTTP proxy

func NoticeListeningSocksProxyPort

func NoticeListeningSocksProxyPort(port int)

NoticeListeningSocksProxyPort is the selected port for the listening local SOCKS proxy

func NoticeLocalProxyError

func NoticeLocalProxyError(proxyType string, err error)

NoticeLocalProxyError reports a local proxy error message. Repetitive errors for a given proxy type are suppressed.

func NoticeRemoteServerListResourceDownloaded

func NoticeRemoteServerListResourceDownloaded(url string)

NoticeRemoteServerListResourceDownloaded indicates that a remote server list download completed successfully.

func NoticeRemoteServerListResourceDownloadedBytes

func NoticeRemoteServerListResourceDownloadedBytes(url string, bytes int64)

NoticeRemoteServerListResourceDownloadedBytes reports remote server list download progress.

func NoticeSLOKSeeded

func NoticeSLOKSeeded(slokID string, duplicate bool)

NoticeSLOKSeeded indicates that the SLOK with the specified ID was received from the Psiphon server. The "duplicate" flags indicates whether the SLOK was previously known.

func NoticeSessionId

func NoticeSessionId(sessionId string)

NoticeSessionId is the session ID used across all tunnels established by the controller.

func NoticeSocksProxyPortInUse

func NoticeSocksProxyPortInUse(port int)

NoticeSocksProxyPortInUse is a failure to use the configured LocalSocksProxyPort

func NoticeSplitTunnelRegion

func NoticeSplitTunnelRegion(region string)

NoticeSplitTunnelRegion reports that split tunnel is on for the given region.

func NoticeTotalBytesTransferred

func NoticeTotalBytesTransferred(ipAddress string, sent, received int64)

NoticeTotalBytesTransferred reports how many tunneled bytes have been transferred in total up to this point, for the tunnel to the server at ipAddress.

func NoticeTunnels

func NoticeTunnels(count int)

NoticeTunnels is how many active tunnels are available. The client should use this to determine connecting/unexpected disconnect state transitions. When count is 0, the core is disconnected; when count > 1, the core is connected.

func NoticeUntunneled

func NoticeUntunneled(address string)

NoticeUntunneled indicates than an address has been classified as untunneled and is being accessed directly.

Note: "address" should remain private; this notice should only be used for alerting users, not for diagnostics logs.

func NoticeUpstreamProxyError

func NoticeUpstreamProxyError(err error)

NoticeUpstreamProxyError reports an error when connecting to an upstream proxy. The user may have input, for example, an incorrect address or incorrect credentials.

func PromoteServerEntry

func PromoteServerEntry(ipAddress string) error

PromoteServerEntry assigns the top rank (one more than current max rank) to the specified server entry. Server candidates are iterated in decending rank order, so this server entry will be the first candidate in a subsequent tunnel establishment.

func PutBackUnreportedPersistentStats

func PutBackUnreportedPersistentStats(stats map[string][][]byte) error

PutBackUnreportedPersistentStats restores a list of persistent stat records to StateUnreported.

func RecordRemoteServerListStat

func RecordRemoteServerListStat(
	url, etag string) error

RecordRemoteServerListStat records a completed common or OSL remote server list resource download. These stats use the same persist-until-reported mechanism described in RecordTunnelStats.

func RecordTunnelStat

func RecordTunnelStat(
	sessionId string,
	tunnelNumber int64,
	tunnelServerIpAddress string,
	establishmentDuration string,
	serverHandshakeTimestamp string,
	tunnelDuration string,
	totalBytesSent int64,
	totalBytesReceived int64) error

RecordTunnelStat records a tunnel duration and bytes sent and received for subsequent reporting and quality analysis.

Tunnel durations are precisely measured client-side and reported in status requests. As the duration is not determined until the tunnel is closed, tunnel stats records are stored in the persistent datastore and reported via subsequent status requests sent to any Psiphon server.

Since the status request that reports a tunnel stats record is not necessarily handled by the same server, the tunnel stats records include the original server ID.

Other fields that may change between tunnel stats recording and reporting include client geo data, propagation channel, sponsor ID, client version. These are not stored in the datastore (client region, in particular, since that would create an on-disk record of user location). TODO: the server could encrypt, with a nonce and key unknown to the client, a blob containing this data; return it in the handshake response; and the client could store and later report this blob with its tunnel stats records.

Multiple "status" requests may be in flight at once (due to multi-tunnel, asynchronous final status retry, and aggressive status requests for pre-registered tunnels), To avoid duplicate reporting, tunnel stats records are "taken-out" by a status request and then "put back" in case the request fails.

Note: since tunnel stats records have a globally unique identifier (sessionId + tunnelNumber), we could tolerate duplicate reporting and filter our duplicates on the server-side. Permitting duplicate reporting could increase the velocity of reporting (for example, both the asynchronous untunneled final status requests and the post-connected immediate startus requests could try to report the same tunnel stats). Duplicate reporting may also occur when a server receives and processes a status request but the client fails to receive the response.

func ReportAvailableRegions

func ReportAvailableRegions()

ReportAvailableRegions prints a notice with the available egress regions. Note that this report ignores config.TunnelProtocol.

func ResolveIP

func ResolveIP(host string, conn net.Conn) (addrs []net.IP, ttls []time.Duration, err error)

ResolveIP uses a custom dns stack to make a DNS query over the given TCP or UDP conn. This is used, e.g., when we need to ensure that a DNS connection bypasses a VPN interface (BindToDevice) or when we need to ensure that a DNS connection is tunneled. Caller must set timeouts or interruptibility as required for conn.

func ResumeDownload

func ResumeDownload(
	httpClient *http.Client,
	requestUrl string,
	downloadFilename string,
	ifNoneMatchETag string) (int64, string, error)

ResumeDownload is a resuable helper that downloads requestUrl via the httpClient, storing the result in downloadFilename when the download is complete. Intermediate, partial downloads state is stored in downloadFilename.part and downloadFilename.part.etag. Any existing downloadFilename file will be overwritten.

In the case where the remote object has changed while a partial download is to be resumed, the partial state is reset and resumeDownload fails. The caller must restart the download.

When ifNoneMatchETag is specified, no download is made if the remote object has the same ETag. ifNoneMatchETag has an effect only when no partial download is in progress.

func SendFeedback

func SendFeedback(configJson, diagnosticsJson, b64EncodedPublicKey, uploadServer, uploadPath, uploadServerHeaders string) error

Encrypt feedback and upload to server. If upload fails the feedback thread will sleep and retry multiple times.

func SetEmitDiagnosticNotices

func SetEmitDiagnosticNotices(enable bool)

SetEmitDiagnosticNotices toggles whether diagnostic notices are emitted. Diagnostic notices contain potentially sensitive circumvention network information; only enable this in environments where notices are handled securely (for example, don't include these notices in log files which users could post to public forums).

func SetKeyValue

func SetKeyValue(key, value string) error

SetKeyValue stores a key/value pair.

func SetNoticeOutput

func SetNoticeOutput(output io.Writer)

SetNoticeOutput sets a target writer to receive notices. By default, notices are written to stderr.

Notices are encoded in JSON. Here's an example:

{"data":{"message":"shutdown operate tunnel"},"noticeType":"Info","showUser":false,"timestamp":"2015-01-28T17:35:13Z"}

All notices have the following fields: - "noticeType": the type of notice, which indicates the meaning of the notice along with what's in the data payload. - "data": additional structured data payload. For example, the "ListeningSocksProxyPort" notice type has a "port" integer data in its payload. - "showUser": whether the information should be displayed to the user. For example, this flag is set for "SocksProxyPortInUse" as the user should be informed that their configured choice of listening port could not be used. Core clients should anticipate that the core will add additional "showUser"=true notices in the future and emit at least the raw notice. - "timestamp": UTC timezone, RFC3339 format timestamp for notice event

See the Notice* functions for details on each notice meaning and payload.

func SetSLOK

func SetSLOK(id, key []byte) (bool, error)

SetSLOK stores a SLOK key, referenced by its ID. The bool return value indicates whether the SLOK was already stored.

func SetSplitTunnelRoutes

func SetSplitTunnelRoutes(region, etag string, data []byte) error

SetSplitTunnelRoutes updates the cached routes data for the given region. The associated etag is also stored and used to make efficient web requests for updates to the data.

func SetUrlETag

func SetUrlETag(url, etag string) error

SetUrlETag stores an ETag for the specfied URL. Note: input URL is treated as a string, and is not encoded or decoded or otherwise canonicalized.

func StorePersistentStat

func StorePersistentStat(statType string, stat []byte) error

StorePersistentStats adds a new persistent stat record, which is set to StateUnreported and is an immediate candidate for reporting.

The stat is a JSON byte array containing fields as required by the Psiphon server API. It's assumed that the JSON value contains enough unique information for the value to function as a key in the key/value datastore. This assumption is currently satisfied by the fields sessionId + tunnelNumber for tunnel stats, and URL + ETag for remote server list stats.

func StoreServerEntries

func StoreServerEntries(serverEntries []*protocol.ServerEntry, replaceIfExists bool) error

StoreServerEntries shuffles and stores a list of server entries. Shuffling is performed on imported server entrues as part of client-side load balancing. There is an independent transaction for each entry insert/update.

func StoreServerEntry

func StoreServerEntry(serverEntry *protocol.ServerEntry, replaceIfExists bool) error

StoreServerEntry adds the server entry to the data store. A newly stored (or re-stored) server entry is assigned the next-to-top rank for iteration order (the previous top ranked entry is promoted). The purpose of inserting at next-to-top is to keep the last selected server as the top ranked server. When replaceIfExists is true, an existing server entry record is overwritten; otherwise, the existing record is unchanged. If the server entry data is malformed, an alert notice is issued and the entry is skipped; no error is returned.

func TakeOutUnreportedPersistentStats

func TakeOutUnreportedPersistentStats(maxCount int) (map[string][][]byte, error)

TakeOutUnreportedPersistentStats returns up to maxCount persistent stats records that are in StateUnreported. The records are set to StateReporting. If the records are successfully reported, clear them with ClearReportedPersistentStats. If the records are not successfully reported, restore them with PutBackUnreportedPersistentStats.

func TrimError

func TrimError(err error) error

TrimError removes the middle of over-long error message strings

func WaitForNetworkConnectivity

func WaitForNetworkConnectivity(
	connectivityChecker NetworkConnectivityChecker, stopBroadcasts ...<-chan struct{}) bool

WaitForNetworkConnectivity uses a NetworkConnectivityChecker to periodically check for network connectivity. It returns true if no NetworkConnectivityChecker is provided (waiting is disabled) or when NetworkConnectivityChecker.HasNetworkConnectivity() indicates connectivity. It waits and polls the checker once a second. If any stop is broadcast, false is returned immediately.

Types

type Config

type Config struct {
	// LogFilename specifies a file to receive event notices (JSON format)
	// By default, notices are emitted to stdout.
	LogFilename string

	// DataStoreDirectory is the directory in which to store the persistent
	// database, which contains information such as server entries.
	// By default, current working directory.
	//
	// Warning: If the datastore file, DataStoreDirectory/DATA_STORE_FILENAME,
	// exists but fails to open for any reason (checksum error, unexpected file
	// format, etc.) it will be deleted in order to pave a new datastore and
	// continue running.
	DataStoreDirectory string

	// PropagationChannelId is a string identifier which indicates how the
	// Psiphon client was distributed. This parameter is required.
	// This value is supplied by and depends on the Psiphon Network, and is
	// typically embedded in the client binary.
	PropagationChannelId string

	// PropagationChannelId is a string identifier which indicates who
	// is sponsoring this Psiphon client. One purpose of this value is to
	// determine the home pages for display. This parameter is required.
	// This value is supplied by and depends on the Psiphon Network, and is
	// typically embedded in the client binary.
	SponsorId string

	// RemoteServerListUrl is a URL which specifies a location to fetch
	// out-of-band server entries. This facility is used when a tunnel cannot
	// be established to known servers.
	// This value is supplied by and depends on the Psiphon Network, and is
	// typically embedded in the client binary.
	RemoteServerListUrl string

	// RemoteServerListDownloadFilename specifies a target filename for
	// storing the remote server list download. Data is stored in co-located
	// files (RemoteServerListDownloadFilename.part*) to allow for resumable
	// downloading.
	RemoteServerListDownloadFilename string

	// RemoteServerListSignaturePublicKey specifies a public key that's
	// used to authenticate the remote server list payload.
	// This value is supplied by and depends on the Psiphon Network, and is
	// typically embedded in the client binary.
	RemoteServerListSignaturePublicKey string

	// ObfuscatedServerListRootURL is a URL which specifies the root location
	// from which to fetch obfuscated server list files.
	// This value is supplied by and depends on the Psiphon Network, and is
	// typically embedded in the client binary.
	ObfuscatedServerListRootURL string

	// ObfuscatedServerListDownloadDirectory specifies a target directory for
	// storing the obfuscated remote server list downloads. Data is stored in
	// co-located files (<OSL filename>.part*) to allow for resumable
	// downloading.
	ObfuscatedServerListDownloadDirectory string

	// ClientVersion is the client version number that the client reports
	// to the server. The version number refers to the host client application,
	// not the core tunnel library. One purpose of this value is to enable
	// automatic updates.
	// This value is supplied by and depends on the Psiphon Network, and is
	// typically embedded in the client binary.
	// Note that sending a ClientPlatform string which includes "windows"
	// (case insensitive) and a ClientVersion of <= 44 will cause an
	// error in processing the response to DoConnectedRequest calls.
	ClientVersion string

	// ClientPlatform is the client platform ("Windows", "Android", etc.) that
	// the client reports to the server.
	ClientPlatform string

	// TunnelWholeDevice is a flag that is passed through to the handshake
	// request for stats purposes. Set to 1 when the host application is tunneling
	// the whole device, 0 otherwise.
	TunnelWholeDevice int

	// EgressRegion is a ISO 3166-1 alpha-2 country code which indicates which
	// country to egress from. For the default, "", the best performing server
	// in any country is selected.
	EgressRegion string

	// TunnelProtocol indicates which protocol to use. Valid values include:
	// "SSH", "OSSH", "UNFRONTED-MEEK-OSSH", "UNFRONTED-MEEK-HTTPS-OSSH",
	// "FRONTED-MEEK-OSSH", "FRONTED-MEEK-HTTP-OSSH". For the default, "",
	// the best performing protocol is used.
	TunnelProtocol string

	// EstablishTunnelTimeoutSeconds specifies a time limit after which to halt
	// the core tunnel controller if no tunnel has been established. The default
	// is ESTABLISH_TUNNEL_TIMEOUT_SECONDS.
	EstablishTunnelTimeoutSeconds *int

	// ListenInterface specifies which interface to listen on.  If no interface
	// is provided then listen on 127.0.0.1.
	// If 'any' is provided then use 0.0.0.0.
	// If there are multiple IP addresses on an interface use the first IPv4 address.
	ListenInterface string

	// LocalSocksProxyPort specifies a port number for the local SOCKS proxy
	// running at 127.0.0.1. For the default value, 0, the system selects a free
	// port (a notice reporting the selected port is emitted).
	LocalSocksProxyPort int

	// LocalHttpProxyPort specifies a port number for the local HTTP proxy
	// running at 127.0.0.1. For the default value, 0, the system selects a free
	// port (a notice reporting the selected port is emitted).
	LocalHttpProxyPort int

	// ConnectionWorkerPoolSize specifies how many connection attempts to attempt
	// in parallel. The default, 0, uses CONNECTION_WORKER_POOL_SIZE which is
	// recommended.
	ConnectionWorkerPoolSize int

	// TunnelPoolSize specifies how many tunnels to run in parallel. Port forwards
	// are multiplexed over multiple tunnels. The default, 0, uses TUNNEL_POOL_SIZE
	// which is recommended.
	TunnelPoolSize int

	// UpstreamProxyUrl is a URL specifying an upstream proxy to use for all
	// outbound connections. The URL should include proxy type and authentication
	// information, as required. See example URLs here:
	// https://github.com/Psiphon-Labs/psiphon-tunnel-core/tree/master/psiphon/upstreamproxy
	UpstreamProxyUrl string

	// UpstreamProxyCustomHeaders is a set of additional arbitrary HTTP headers that are
	// added to all requests made through the upstream proxy specified by UpstreamProxyUrl
	// NOTE: Only HTTP(s) proxies use this if specified
	UpstreamProxyCustomHeaders http.Header

	// NetworkConnectivityChecker is an interface that enables the core tunnel to call
	// into the host application to check for network connectivity. This parameter is
	// only applicable to library deployments.
	NetworkConnectivityChecker NetworkConnectivityChecker

	// DeviceBinder is an interface that enables the core tunnel to call
	// into the host application to bind sockets to specific devices. This is used
	// for VPN routing exclusion. This parameter is only applicable to library
	// deployments.
	DeviceBinder DeviceBinder

	// DnsServerGetter is an interface that enables the core tunnel to call
	// into the host application to discover the native network DNS server settings.
	// This parameter is only applicable to library deployments.
	DnsServerGetter DnsServerGetter

	// HostNameTransformer is an interface that enables pluggable hostname
	// transformation circumvention strategies.
	HostNameTransformer HostNameTransformer

	// TargetServerEntry is an encoded server entry. When specified, this server entry
	// is used exclusively and all other known servers are ignored.
	TargetServerEntry string

	// DisableApi disables Psiphon server API calls including handshake, connected,
	// status, etc. This is used for special case temporary tunnels (Windows VPN mode).
	DisableApi bool

	// TargetApiProtocol specifies whether to force use of "ssh" or "web" API protocol.
	// When blank, the default, the optimal API protocol is used. Note that this
	// capability check is not applied before the "CandidateServers" count is emitted.
	// This parameter is intended for testing and debugging only.
	TargetApiProtocol string

	// DisableRemoteServerListFetcher disables fetching remote server lists. This is
	// used for special case temporary tunnels.
	DisableRemoteServerListFetcher bool

	// SplitTunnelRoutesUrlFormat is an URL which specifies the location of a routes
	// file to use for split tunnel mode. The URL must include a placeholder for the
	// client region to be supplied. Split tunnel mode uses the routes file to classify
	// port forward destinations as foreign or domestic and does not tunnel domestic
	// destinations. Split tunnel mode is on when all the SplitTunnel parameters are
	// supplied.
	// This value is supplied by and depends on the Psiphon Network, and is
	// typically embedded in the client binary.
	SplitTunnelRoutesUrlFormat string

	// SplitTunnelRoutesSignaturePublicKey specifies a public key that's
	// used to authenticate the split tunnel routes payload.
	// This value is supplied by and depends on the Psiphon Network, and is
	// typically embedded in the client binary.
	SplitTunnelRoutesSignaturePublicKey string

	// SplitTunnelDnsServer specifies a DNS server to use when resolving port
	// forward target domain names to IP addresses for classification. The DNS
	// server must support TCP requests.
	SplitTunnelDnsServer string

	// UpgradeDownloadUrl specifies a URL from which to download a host client upgrade
	// file, when one is available. The core tunnel controller provides a resumable
	// download facility which downloads this resource and emits a notice when complete.
	// This value is supplied by and depends on the Psiphon Network, and is
	// typically embedded in the client binary.
	UpgradeDownloadUrl string

	// UpgradeDownloadClientVersionHeader specifies the HTTP header name for the
	// entity at UpgradeDownloadUrl which specifies the client version (an integer
	// value). A HEAD request may be made to check the version number available at
	// UpgradeDownloadUrl. UpgradeDownloadClientVersionHeader is required when
	// UpgradeDownloadUrl is specified.
	UpgradeDownloadClientVersionHeader string

	// UpgradeDownloadFilename is the local target filename for an upgrade download.
	// This parameter is required when UpgradeDownloadUrl is specified.
	// Data is stored in co-located files (UpgradeDownloadFilename.part*) to allow
	// for resumable downloading.
	UpgradeDownloadFilename string

	// EmitBytesTransferred indicates whether to emit periodic notices showing
	// bytes sent and received.
	EmitBytesTransferred bool

	// UseIndistinguishableTLS enables use of an alternative TLS stack with a less
	// distinct fingerprint (ClientHello content) than the stock Go TLS.
	// UseIndistinguishableTLS only applies to untunneled TLS connections. This
	// parameter is only supported on platforms built with OpenSSL.
	// Requires TrustedCACertificatesFilename to be set.
	UseIndistinguishableTLS bool

	// UseTrustedCACertificates toggles use of the trusted CA certs, specified
	// in TrustedCACertificatesFilename, for tunneled TLS connections that expect
	// server certificates signed with public certificate authorities (currently,
	// only upgrade downloads). This option is used with stock Go TLS in cases where
	// Go may fail to obtain a list of root CAs from the operating system.
	// Requires TrustedCACertificatesFilename to be set.
	UseTrustedCACertificatesForStockTLS bool

	// TrustedCACertificatesFilename specifies a file containing trusted CA certs.
	// The file contents should be compatible with OpenSSL's SSL_CTX_load_verify_locations.
	// When specified, this enables use of indistinguishable TLS for HTTPS requests
	// that require typical (system CA) server authentication.
	TrustedCACertificatesFilename string

	// DisablePeriodicSshKeepAlive indicates whether to send an SSH keepalive every
	// 1-2 minutes, when the tunnel is idle. If the SSH keepalive times out, the tunnel
	// is considered to have failed.
	DisablePeriodicSshKeepAlive bool

	// DeviceRegion is the optional, reported region the host device is running in.
	// This input value should be a ISO 3166-1 alpha-2 country code. The device region
	// is reported to the server in the connected request and recorded for Psiphon
	// stats.
	// When provided, this value may be used, pre-connection, to select performance
	// or circumvention optimization strategies for the given region.
	DeviceRegion string

	// EmitDiagnosticNotices indicates whether to output notices containing detailed
	// information about the Psiphon session. As these notices may contain sensitive
	// network information, they should not be insecurely distributed or displayed
	// to users. Default is off.
	EmitDiagnosticNotices bool

	// TunnelConnectTimeoutSeconds specifies a single tunnel connection sequence timeout.
	// Zero value means that connection process will not time out.
	// If omitted, the default value is TUNNEL_CONNECT_TIMEOUT_SECONDS.
	TunnelConnectTimeoutSeconds *int

	// TunnelPortForwardDialTimeoutSeconds specifies a dial timeout per SSH port forward.
	// Zero value means a port forward dial will not time out.
	// If omitted, the default value is TUNNEL_PORT_FORWARD_DIAL_TIMEOUT_SECONDS.
	TunnelPortForwardDialTimeoutSeconds *int

	// TunnelSshKeepAliveProbeTimeoutSeconds specifies a timeout value for "probe"
	// SSH keep-alive that is sent upon port forward failure.
	// Zero value means keep-alive request will not time out.
	// If omitted, the default value is TUNNEL_SSH_KEEP_ALIVE_PROBE_TIMEOUT_SECONDS.
	TunnelSshKeepAliveProbeTimeoutSeconds *int

	// TunnelSshKeepAlivePeriodicTimeoutSeconds specifies a timeout value for regular
	// SSH keep-alives that are sent periodically.
	// Zero value means keep-alive request will not time out.
	// If omitted, the default value is TUNNEL_SSH_KEEP_ALIVE_PERIODIC_TIMEOUT_SECONDS.
	TunnelSshKeepAlivePeriodicTimeoutSeconds *int

	// FetchRemoteServerListTimeoutSeconds specifies a timeout value for remote server list
	// HTTP request. Zero value means that request will not time out.
	// If omitted, the default value is FETCH_REMOTE_SERVER_LIST_TIMEOUT_SECONDS.
	FetchRemoteServerListTimeoutSeconds *int

	// PsiphonApiServerTimeoutSeconds specifies a timeout for periodic API HTTP
	// requests to Psiphon server such as stats, home pages, etc.
	// Zero value means that request will not time out.
	// If omitted, the default value is PSIPHON_API_SERVER_TIMEOUT_SECONDS.
	// Note that this value is overridden for final stats requests during shutdown
	// process in order to prevent hangs.
	PsiphonApiServerTimeoutSeconds *int

	// FetchRoutesTimeoutSeconds specifies a timeout value for split tunnel routes
	// HTTP request. Zero value means that request will not time out.
	// If omitted, the default value is FETCH_ROUTES_TIMEOUT_SECONDS.
	FetchRoutesTimeoutSeconds *int

	// HttpProxyOriginServerTimeoutSeconds specifies an HTTP response header timeout
	// value in various HTTP relays found in httpProxy.
	// Zero value means that request will not time out.
	// If omitted, the default value is HTTP_PROXY_ORIGIN_SERVER_TIMEOUT_SECONDS.
	HttpProxyOriginServerTimeoutSeconds *int

	// FetchRemoteServerListRetryPeriodSeconds specifies the delay before
	// resuming a remote server list download after a failure.
	// If omitted, the default value FETCH_REMOTE_SERVER_LIST_RETRY_PERIOD_SECONDS.
	FetchRemoteServerListRetryPeriodSeconds *int

	// DownloadUpgradestRetryPeriodSeconds specifies the delay before
	// resuming a client upgrade download after a failure.
	// If omitted, the default value DOWNLOAD_UPGRADE_RETRY_PERIOD_SECONDS.
	DownloadUpgradeRetryPeriodSeconds *int

	// EstablishTunnelPausePeriodSeconds specifies the delay between attempts
	// to establish tunnels. Briefly pausing allows for network conditions to improve
	// and for asynchronous operations such as fetch remote server list to complete.
	// If omitted, the default value is ESTABLISH_TUNNEL_PAUSE_PERIOD_SECONDS.
	EstablishTunnelPausePeriodSeconds *int

	// RateLimits specify throttling configuration for the tunnel.
	RateLimits common.RateLimits

	// EmitSLOKs indicates whether to emit notices for each seeded SLOK. As this
	// could reveal user browsing activity, it's intended for debugging and testing
	// only.
	EmitSLOKs bool
}

Config is the Psiphon configuration specified by the application. This configuration controls the behavior of the core tunnel functionality.

func LoadConfig

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

LoadConfig parses and validates a JSON format Psiphon config JSON string and returns a Config struct populated with config values.

type Controller

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

Controller is a tunnel lifecycle coordinator. It manages lists of servers to connect to; establishes and monitors tunnels; and runs local proxies which route traffic through the tunnels.

func NewController

func NewController(config *Config) (controller *Controller, err error)

NewController initializes a new controller.

func (*Controller) Dial

func (controller *Controller) Dial(
	remoteAddr string, alwaysTunnel bool, downstreamConn net.Conn) (conn net.Conn, err error)

Dial selects an active tunnel and establishes a port forward connection through the selected tunnel. Failure to connect is considered a port foward failure, for the purpose of monitoring tunnel health.

func (*Controller) Run

func (controller *Controller) Run(shutdownBroadcast <-chan struct{})

Run executes the controller. It launches components and then monitors for a shutdown signal; after receiving the signal it shuts down the controller. The components include: - the periodic remote server list fetcher - the connected reporter - the tunnel manager - a local SOCKS proxy that port forwards through the pool of tunnels - a local HTTP proxy that port forwards through the pool of tunnels

func (*Controller) SetClientVerificationPayloadForActiveTunnels

func (controller *Controller) SetClientVerificationPayloadForActiveTunnels(clientVerificationPayload string)

SetClientVerificationPayloadForActiveTunnels sets the client verification payload that is to be sent in client verification requests to all established tunnels.

Client verification is used to verify that the client is a valid Psiphon client, which will determine how the server treats the client traffic. The proof-of-validity is platform-specific and the payload is opaque to this function but assumed to be JSON.

Since, in some cases, verification payload cannot be determined until after tunnel-core starts, the payload cannot be simply specified in the Config.

SetClientVerificationPayloadForActiveTunnels will not block enqueuing a new verification payload. One new payload can be enqueued, after which additional payloads will be dropped if a payload is still enqueued.

func (*Controller) SignalComponentFailure

func (controller *Controller) SignalComponentFailure()

SignalComponentFailure notifies the controller that an associated component has failed. This will terminate the controller.

func (*Controller) SignalSeededNewSLOK

func (controller *Controller) SignalSeededNewSLOK()

SignalSeededNewSLOK implements the TunnelOwner interface. This function is called by Tunnel.operateTunnel when the tunnel has received a new, previously unknown SLOK from the server. The Controller triggers an OSL fetch, as the new SLOK may be sufficient to access new OSLs.

func (*Controller) SignalTunnelFailure

func (controller *Controller) SignalTunnelFailure(tunnel *Tunnel)

SignalTunnelFailure implements the TunnelOwner interface. This function is called by Tunnel.operateTunnel when the tunnel has detected that it has failed. The Controller will signal runTunnels to create a new tunnel and/or remove the tunnel from the list of active tunnels.

type CustomTLSConfig

type CustomTLSConfig struct {

	// Dial is the network connection dialer. TLS is layered on
	// top of a new network connection created with dialer.
	Dial Dialer

	// Timeout is and optional timeout for combined network
	// connection dial and TLS handshake.
	Timeout time.Duration

	// DialAddr overrides the "addr" input to Dial when specified
	DialAddr string

	// SNIServerName specifies the value to set in the SNI
	// server_name field. When blank, SNI is omitted. Note that
	// underlying TLS code also automatically omits SNI when
	// the server_name is an IP address.
	SNIServerName string

	// SkipVerify completely disables server certificate verification.
	SkipVerify bool

	// VerifyLegacyCertificate is a special case self-signed server
	// certificate case. Ignores IP SANs and basic constraints. No
	// certificate chain. Just checks that the server presented the
	// specified certificate. SNI is disbled when this is set.
	VerifyLegacyCertificate *x509.Certificate

	// UseIndistinguishableTLS specifies whether to try to use an
	// alternative stack for TLS. From a circumvention perspective,
	// Go's TLS has a distinct fingerprint that may be used for blocking.
	UseIndistinguishableTLS bool

	// TrustedCACertificatesFilename specifies a file containing trusted
	// CA certs. Directory contents should be compatible with OpenSSL's
	// SSL_CTX_load_verify_locations
	// Only applies to UseIndistinguishableTLS connections.
	TrustedCACertificatesFilename string
}

CustomTLSConfig contains parameters to determine the behavior of CustomTLSDial.

type DeviceBinder

type DeviceBinder interface {
	BindToDevice(fileDescriptor int) error
}

DeviceBinder defines the interface to the external BindToDevice provider

type DialConfig

type DialConfig struct {

	// UpstreamProxyUrl specifies a proxy to connect through.
	// E.g., "http://proxyhost:8080"
	//       "socks5://user:password@proxyhost:1080"
	//       "socks4a://proxyhost:1080"
	//       "http://NTDOMAIN\NTUser:password@proxyhost:3375"
	//
	// Certain tunnel protocols require HTTP CONNECT support
	// when a HTTP proxy is specified. If CONNECT is not
	// supported, those protocols will not connect.
	UpstreamProxyUrl string

	// UpstreamProxyCustomHeader is a set of additional arbitrary HTTP headers that are
	// added to all HTTP requests made through the upstream proxy specified by UpstreamProxyUrl
	// in case of HTTP proxy
	UpstreamProxyCustomHeaders http.Header

	ConnectTimeout time.Duration

	// PendingConns is used to track and interrupt dials in progress.
	// Dials may be interrupted using PendingConns.CloseAll(). Once instantiated,
	// a conn is added to pendingConns before the network connect begins and
	// removed from pendingConns once the connect succeeds or fails.
	// May be nil.
	PendingConns *common.Conns

	// BindToDevice parameters are used to exclude connections and
	// associated DNS requests from VPN routing.
	// When DeviceBinder is set, any underlying socket is
	// submitted to the device binding servicebefore connecting.
	// The service should bind the socket to a device so that it doesn't route
	// through a VPN interface. This service is also used to bind UDP sockets used
	// for DNS requests, in which case DnsServerGetter is used to get the
	// current active untunneled network DNS server.
	DeviceBinder    DeviceBinder
	DnsServerGetter DnsServerGetter

	// UseIndistinguishableTLS specifies whether to try to use an
	// alternative stack for TLS. From a circumvention perspective,
	// Go's TLS has a distinct fingerprint that may be used for blocking.
	// Only applies to TLS connections.
	UseIndistinguishableTLS bool

	// TrustedCACertificatesFilename specifies a file containing trusted
	// CA certs. The file contents should be compatible with OpenSSL's
	// SSL_CTX_load_verify_locations.
	// Only applies to UseIndistinguishableTLS connections.
	TrustedCACertificatesFilename string

	// DeviceRegion is the reported region the host device is running in.
	// When set, this value may be used, pre-connection, to select performance
	// or circumvention optimization strategies for the given region.
	DeviceRegion string

	// ResolvedIPCallback, when set, is called with the IP address that was
	// dialed. This is either the specified IP address in the dial address,
	// or the resolved IP address in the case where the dial address is a
	// domain name.
	// The callback may be invoked by a concurrent goroutine.
	ResolvedIPCallback func(string)
}

DialConfig contains parameters to determine the behavior of a Psiphon dialer (TCPDial, MeekDial, etc.)

type Dialer

type Dialer func(string, string) (net.Conn, error)

Dialer is a custom dialer compatible with http.Transport.Dial.

func NewCustomTLSDialer

func NewCustomTLSDialer(config *CustomTLSConfig) Dialer

func NewTCPDialer

func NewTCPDialer(config *DialConfig) Dialer

NewTCPDialer creates a TCPDialer.

type DnsServerGetter

type DnsServerGetter interface {
	GetPrimaryDnsServer() string
	GetSecondaryDnsServer() string
}

DnsServerGetter defines the interface to the external GetDnsServer provider

type HostNameTransformer

type HostNameTransformer interface {
	TransformHostName(hostname string) (string, bool)
}

HostNameTransformer defines the interface for pluggable hostname transformation circumvention strategies.

type HttpProxy

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

HttpProxy is a HTTP server that relays HTTP requests through the Psiphon tunnel. It includes support for HTTP CONNECT.

This proxy also offers a "URL proxy" mode that relays requests for HTTP or HTTPS or URLs specified in the proxy request path. This mode relays either through the Psiphon tunnel, or directly.

An example use case for tunneled URL proxy relays is to craft proxied URLs to pass to components that don't support HTTP or SOCKS proxy settings. For example, the Android Media Player (http://developer.android.com/reference/android/media/MediaPlayer.html). To make the Media Player use the Psiphon tunnel, construct a URL such as: "http://127.0.0.1:<proxy-port>/tunneled/<origin media URL>"; and pass this to the player. The <origin media URL> must be escaped in such a way that it can be used inside a URL query. TODO: add ICY protocol to support certain streaming media (e.g., https://gist.github.com/tulskiy/1008126)

An example use case for direct, untunneled, relaying is to make use of Go's TLS stack for HTTPS requests in cases where the native TLS stack is lacking (e.g., WinHTTP on Windows XP). The URL for direct relaying is: "http://127.0.0.1:<proxy-port>/direct/<origin URL>". Again, the <origin URL> must be escaped in such a way that it can be used inside a URL query.

Origin URLs must include the scheme prefix ("http://" or "https://") and must be URL encoded.

func NewHttpProxy

func NewHttpProxy(
	config *Config,
	untunneledDialConfig *DialConfig,
	tunneler Tunneler,
	listenIP string) (proxy *HttpProxy, err error)

NewHttpProxy initializes and runs a new HTTP proxy server.

func (*HttpProxy) Close

func (proxy *HttpProxy) Close()

Close terminates the HTTP server.

func (*HttpProxy) ServeHTTP

func (proxy *HttpProxy) ServeHTTP(responseWriter http.ResponseWriter, request *http.Request)

ServeHTTP receives HTTP requests and proxies them. CONNECT requests are hijacked and all data is relayed. Other HTTP requests are proxied with explicit round trips. In both cases, the tunnel is used for proxied traffic.

Implementation is based on:

https://github.com/justmao945/mallory Copyright (c) 2014 JianjunMao The MIT License (MIT)

https://golang.org/src/pkg/net/http/httputil/reverseproxy.go Copyright 2011 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

type IdentityHostNameTransformer

type IdentityHostNameTransformer struct{}

IdentityHostNameTransformer is the default HostNameTransformer, which returns the hostname unchanged.

func (IdentityHostNameTransformer) TransformHostName

func (IdentityHostNameTransformer) TransformHostName(hostname string) (string, bool)

type MeekConfig

type MeekConfig struct {

	// DialAddress is the actual network address to dial to establish a
	// connection to the meek server. This may be either a fronted or
	// direct address. The address must be in the form "host:port",
	// where host may be a domain name or IP address.
	DialAddress string

	// UseHTTPS indicates whether to use HTTPS (true) or HTTP (false).
	UseHTTPS bool

	// SNIServerName is the value to place in the TLS SNI server_name
	// field when HTTPS is used.
	SNIServerName string

	// HostHeader is the value to place in the HTTP request Host header.
	HostHeader string

	// TransformedHostName records whether a HostNameTransformer
	// transformation is in effect. This value is used for stats reporting.
	TransformedHostName bool

	PsiphonServerAddress          string
	SessionID                     string
	MeekCookieEncryptionPublicKey string
	MeekObfuscatedKey             string
}

MeekConfig specifies the behavior of a MeekConn

type MeekConn

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

MeekConn is a network connection that tunnels TCP over HTTP and supports "fronting". Meek sends client->server flow in HTTP request bodies and receives server->client flow in HTTP response bodies. Polling is used to achieve full duplex TCP.

Fronting is an obfuscation technique in which the connection to a web server, typically a CDN, is indistinguishable from any other HTTPS connection to the generic "fronting domain" -- the HTTP Host header is used to route the requests to the actual destination. See https://trac.torproject.org/projects/tor/wiki/doc/meek for more details.

MeekConn also operates in unfronted mode, in which plain HTTP connections are made without routing through a CDN.

func DialMeek

func DialMeek(
	meekConfig *MeekConfig,
	dialConfig *DialConfig) (meek *MeekConn, err error)

DialMeek returns an initialized meek connection. A meek connection is an HTTP session which does not depend on an underlying socket connection (although persistent HTTP connections are used for performance). This function does not wait for the connection to be "established" before returning. A goroutine is spawned which will eventually start HTTP polling. When frontingAddress is not "", fronting is used. This option assumes caller has already checked server entry capabilities.

func (*MeekConn) Close

func (meek *MeekConn) Close() (err error)

Close terminates the meek connection. Close waits for the relay processing goroutine to stop and releases HTTP transport resources. A mutex is required to support net.Conn concurrency semantics.

func (*MeekConn) LocalAddr

func (meek *MeekConn) LocalAddr() net.Addr

Stub implementation of net.Conn.LocalAddr

func (*MeekConn) Read

func (meek *MeekConn) Read(buffer []byte) (n int, err error)

Read reads data from the connection. net.Conn Deadlines are ignored. net.Conn concurrency semantics are supported.

func (*MeekConn) RemoteAddr

func (meek *MeekConn) RemoteAddr() net.Addr

Stub implementation of net.Conn.RemoteAddr

func (*MeekConn) SetDeadline

func (meek *MeekConn) SetDeadline(t time.Time) error

Stub implementation of net.Conn.SetDeadline

func (*MeekConn) SetReadDeadline

func (meek *MeekConn) SetReadDeadline(t time.Time) error

Stub implementation of net.Conn.SetReadDeadline

func (*MeekConn) SetWriteDeadline

func (meek *MeekConn) SetWriteDeadline(t time.Time) error

Stub implementation of net.Conn.SetWriteDeadline

func (*MeekConn) Write

func (meek *MeekConn) Write(buffer []byte) (n int, err error)

Write writes data to the connection. net.Conn Deadlines are ignored. net.Conn concurrency semantics are supported.

type NetworkConnectivityChecker

type NetworkConnectivityChecker interface {
	// TODO: change to bool return value once gobind supports that type
	HasNetworkConnectivity() int
}

NetworkConnectivityChecker defines the interface to the external HasNetworkConnectivity provider

type NoticeReceiver

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

NoticeReceiver consumes a notice input stream and invokes a callback function for each discrete JSON notice object byte sequence.

func NewNoticeConsoleRewriter

func NewNoticeConsoleRewriter(writer io.Writer) *NoticeReceiver

NewNoticeConsoleRewriter consumes JSON-format notice input and parses each notice and rewrites in a more human-readable format more suitable for console output. The data payload field is left as JSON.

func NewNoticeReceiver

func NewNoticeReceiver(callback func([]byte)) *NoticeReceiver

NewNoticeReceiver initializes a new NoticeReceiver

func (*NoticeReceiver) Write

func (receiver *NoticeReceiver) Write(p []byte) (n int, err error)

Write implements io.Writer.

type RemoteServerListFetcher

type RemoteServerListFetcher func(
	config *Config, tunnel *Tunnel, untunneledDialConfig *DialConfig) error

type ServerContext

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

ServerContext is a utility struct which holds all of the data associated with a Psiphon server connection. In addition to the established tunnel, this includes data and transport mechanisms for Psiphon API requests. Legacy servers offer the Psiphon API through a web service; newer servers offer the Psiphon API through SSH requests made directly through the tunnel's SSH client.

func NewServerContext

func NewServerContext(tunnel *Tunnel, sessionId string) (*ServerContext, error)

NewServerContext makes the tunnelled handshake request to the Psiphon server and returns a ServerContext struct for use with subsequent Psiphon server API requests (e.g., periodic connected and status requests).

func (*ServerContext) DoClientVerificationRequest

func (serverContext *ServerContext) DoClientVerificationRequest(
	verificationPayload string, serverIP string) error

DoClientVerificationRequest performs the "client_verification" API request. This request is used to verify that the client is a valid Psiphon client, which will determine how the server treats the client traffic. The proof-of-validity is platform-specific and the payload is opaque to this function but assumed to be JSON.

func (*ServerContext) DoConnectedRequest

func (serverContext *ServerContext) DoConnectedRequest() error

DoConnectedRequest performs the "connected" API request. This request is used for statistics. The server returns a last_connected token for the client to store and send next time it connects. This token is a timestamp (using the server clock, and should be rounded to the nearest hour) which is used to determine when a connection represents a unique user for a time period.

func (*ServerContext) DoStatusRequest

func (serverContext *ServerContext) DoStatusRequest(tunnel *Tunnel) error

DoStatusRequest makes a "status" API request to the server, sending session stats.

func (*ServerContext) StatsRegexps

func (serverContext *ServerContext) StatsRegexps() *transferstats.Regexps

StatsRegexps gets the Regexps used for the statistics for this tunnel.

func (*ServerContext) TryUntunneledStatusRequest

func (serverContext *ServerContext) TryUntunneledStatusRequest(isShutdown bool) error

TryUntunneledStatusRequest makes direct connections to the specified server (if supported) in an attempt to send useful bytes transferred and tunnel duration stats after a tunnel has alreay failed. The tunnel is assumed to be closed, but its config, protocol, and context values must still be valid. TryUntunneledStatusRequest emits notices detailing failed attempts.

type ServerEntryIterator

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

ServerEntryIterator is used to iterate over stored server entries in rank order.

func NewServerEntryIterator

func NewServerEntryIterator(config *Config) (iterator *ServerEntryIterator, err error)

NewServerEntryIterator creates a new ServerEntryIterator

func (*ServerEntryIterator) Close

func (iterator *ServerEntryIterator) Close()

Close cleans up resources associated with a ServerEntryIterator.

func (*ServerEntryIterator) Next

func (iterator *ServerEntryIterator) Next() (serverEntry *protocol.ServerEntry, err error)

Next returns the next server entry, by rank, for a ServerEntryIterator. Returns nil with no error when there is no next item.

func (*ServerEntryIterator) Reset

func (iterator *ServerEntryIterator) Reset() error

Reset a NewServerEntryIterator to the start of its cycle. The next call to Next will return the first server entry.

type SocksProxy

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

SocksProxy is a SOCKS server that accepts local host connections and, for each connection, establishes a port forward through the tunnel SSH client and relays traffic through the port forward.

func NewSocksProxy

func NewSocksProxy(
	config *Config,
	tunneler Tunneler,
	listenIP string) (proxy *SocksProxy, err error)

NewSocksProxy initializes a new SOCKS server. It begins listening for connections, starts a goroutine that runs an accept loop, and returns leaving the accept loop running.

func (*SocksProxy) Close

func (proxy *SocksProxy) Close()

Close terminates the listener and waits for the accept loop goroutine to complete.

type SplitTunnelClassifier

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

SplitTunnelClassifier determines whether a network destination should be accessed through a tunnel or accessed directly.

The classifier uses tables of IP address data, routes data, to determine if a given IP is to be tunneled or not. If presented with a hostname, the classifier performs a tunneled (uncensored) DNS request to first determine the IP address for that hostname; then a classification is made based on the IP address.

Classification results (both the hostname resolution and the following IP address classification) are cached for the duration of the DNS record TTL.

Classification is by geographical region (country code). When the split tunnel feature is configured to be on, and if the IP address is within the user's region, it may be accessed untunneled. Otherwise, the IP address must be accessed through a tunnel. The user's current region is revealed to a Tunnel via the Psiphon server API handshake.

When a Tunnel has a blank region (e.g., when DisableApi is set and the tunnel registers without performing a handshake) then no routes data is set and all IP addresses are classified as requiring tunneling.

Split tunnel is made on a best effort basis. After the classifier is started, but before routes data is available for the given region, all IP addresses will be classified as requiring tunneling.

Routes data is fetched asynchronously after Start() is called. Routes data is cached in the data store so it need not be downloaded in full when fresh data is in the cache.

func NewSplitTunnelClassifier

func NewSplitTunnelClassifier(config *Config, tunneler Tunneler) *SplitTunnelClassifier

func (*SplitTunnelClassifier) IsUntunneled

func (classifier *SplitTunnelClassifier) IsUntunneled(targetAddress string) bool

IsUntunneled takes a destination hostname or IP address and determines if it should be accessed through a tunnel. When a hostname is presented, it is first resolved to an IP address which can be matched against the routes data. Multiple goroutines may invoke RequiresTunnel simultaneously. Multi-reader locks are used in the implementation to enable concurrent access, with no locks held during network access.

func (*SplitTunnelClassifier) Shutdown

func (classifier *SplitTunnelClassifier) Shutdown()

Shutdown waits until the background setRoutes() goroutine is finished. There is no explicit shutdown signal sent to setRoutes() -- instead we assume that in an overall shutdown situation, the tunnel used for network access in setRoutes() is closed and network events won't delay the completion of the goroutine.

func (*SplitTunnelClassifier) Start

func (classifier *SplitTunnelClassifier) Start(fetchRoutesTunnel *Tunnel)

Start resets the state of the classifier. In the default state, all IP addresses are classified as requiring tunneling. With sufficient configuration and region info, this function starts a goroutine to asynchronously fetch and install the routes data.

type SyncFileWriter

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

SyncFileWriter wraps a file and exposes an io.Writer. At predefined steps, the file is synced (flushed to disk) while writing.

func NewSyncFileWriter

func NewSyncFileWriter(file *os.File) *SyncFileWriter

NewSyncFileWriter creates a SyncFileWriter.

func (*SyncFileWriter) Write

func (writer *SyncFileWriter) Write(p []byte) (n int, err error)

Write implements io.Writer with periodic file syncing.

type TCPConn

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

TCPConn is a customized TCP connection that:

  • can be interrupted while dialing;
  • implements a connect timeout;
  • uses an upstream proxy when specified, and includes upstream proxy dialing in the connect timeout;
  • can be bound to a specific system device (for Android VpnService routing compatibility, for example);

func (*TCPConn) Close

func (conn *TCPConn) Close() (err error)

Close terminates a connected TCPConn or interrupts a dialing TCPConn.

type TimeoutError

type TimeoutError struct{}

TimeoutError implements the error interface

func (TimeoutError) Error

func (TimeoutError) Error() string

func (TimeoutError) Temporary

func (TimeoutError) Temporary() bool

func (TimeoutError) Timeout

func (TimeoutError) Timeout() bool

type Tunnel

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

Tunnel is a connection to a Psiphon server. An established tunnel includes a network connection to the specified server and an SSH session built on top of that transport.

func EstablishTunnel

func EstablishTunnel(
	config *Config,
	untunneledDialConfig *DialConfig,
	sessionId string,
	pendingConns *common.Conns,
	serverEntry *protocol.ServerEntry,
	adjustedEstablishStartTime monotime.Time,
	tunnelOwner TunnelOwner) (tunnel *Tunnel, err error)

EstablishTunnel first makes a network transport connection to the Psiphon server and then establishes an SSH client session on top of that transport. The SSH server is authenticated using the public key in the server entry. Depending on the server's capabilities, the connection may use plain SSH over TCP, obfuscated SSH over TCP, or obfuscated SSH over HTTP (meek protocol). When requiredProtocol is not blank, that protocol is used. Otherwise, the a random supported protocol is used. untunneledDialConfig is used for untunneled final status requests.

func (*Tunnel) Close

func (tunnel *Tunnel) Close(isDiscarded bool)

Close stops operating the tunnel and closes the underlying connection. Supports multiple and/or concurrent calls to Close(). When isDiscarded is set, operateTunnel will not attempt to send final status requests.

func (*Tunnel) Dial

func (tunnel *Tunnel) Dial(
	remoteAddr string, alwaysTunnel bool, downstreamConn net.Conn) (conn net.Conn, err error)

Dial establishes a port forward connection through the tunnel This Dial doesn't support split tunnel, so alwaysTunnel is not referenced

func (*Tunnel) IsDiscarded

func (tunnel *Tunnel) IsDiscarded() bool

IsDiscarded returns the tunnel's discarded flag.

func (*Tunnel) SendAPIRequest

func (tunnel *Tunnel) SendAPIRequest(
	name string, requestPayload []byte) ([]byte, error)

SendAPIRequest sends an API request as an SSH request through the tunnel. This function blocks awaiting a response. Only one request may be in-flight at once; a concurrent SendAPIRequest will block until an active request receives its response (or the SSH connection is terminated).

func (*Tunnel) SetClientVerificationPayload

func (tunnel *Tunnel) SetClientVerificationPayload(clientVerificationPayload string)

SetClientVerificationPayload triggers a client verification request, for this tunnel, with the specified verifiction payload. If the tunnel is not yet established, the payload/request is enqueued. If a payload/request is already eneueued, the new payload is dropped.

func (*Tunnel) SignalComponentFailure

func (tunnel *Tunnel) SignalComponentFailure()

SignalComponentFailure notifies the tunnel that an associated component has failed. This will terminate the tunnel.

type TunnelDialStats

type TunnelDialStats struct {
	UpstreamProxyType              string
	UpstreamProxyCustomHeaderNames []string
	MeekDialAddress                string
	MeekResolvedIPAddress          string
	MeekSNIServerName              string
	MeekHostHeader                 string
	MeekTransformedHostName        bool
}

TunnelDialStats records additional dial config that is sent to the server for stats recording. This data is used to analyze which configuration settings are successful in various circumvention contexts, and includes meek dial params and upstream proxy params. For upstream proxy, only proxy type and custom header names are recorded; proxy address and custom header values are considered PII.

type TunnelOwner

type TunnelOwner interface {
	SignalSeededNewSLOK()
	SignalTunnelFailure(tunnel *Tunnel)
}

TunnerOwner specifies the interface required by Tunnel to notify its owner when it has failed. The owner may, as in the case of the Controller, remove the tunnel from its list of active tunnels.

type TunneledConn

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

TunneledConn implements net.Conn and wraps a port foward connection. It is used to hook into Read and Write to observe I/O errors and report these errors back to the tunnel monitor as port forward failures. TunneledConn optionally tracks a peer connection to be explictly closed when the TunneledConn is closed.

func (*TunneledConn) Close

func (conn *TunneledConn) Close() error

func (*TunneledConn) Read

func (conn *TunneledConn) Read(buffer []byte) (n int, err error)

func (*TunneledConn) Write

func (conn *TunneledConn) Write(buffer []byte) (n int, err error)

type Tunneler

type Tunneler interface {
	Dial(remoteAddr string, alwaysTunnel bool, downstreamConn net.Conn) (conn net.Conn, err error)
	SignalComponentFailure()
}

Tunneler specifies the interface required by components that use a tunnel. Components which use this interface may be serviced by a single Tunnel instance, or a Controller which manages a pool of tunnels, or any other object which implements Tunneler. alwaysTunnel indicates that the connection should always be tunneled. If this is not set, the connection may be made directly, depending on split tunnel classification, when that feature is supported and active. downstreamConn is an optional parameter which specifies a connection to be explictly closed when the Dialed connection is closed. For instance, this is used to close downstreamConn App<->LocalProxy connections when the related LocalProxy<->SshPortForward connections close.

Directories

Path Synopsis
osl
Package osl implements the Obfuscated Server List (OSL) mechanism.
Package osl implements the Obfuscated Server List (OSL) mechanism.
Package psiphon/server implements the core tunnel functionality of a Psiphon server.
Package psiphon/server implements the core tunnel functionality of a Psiphon server.
psinet
Package psiphon/server/psinet implements psinet database services.
Package psiphon/server/psinet implements psinet database services.
Package stats counts and keeps track of session stats.
Package stats counts and keeps track of session stats.
go-ntlm/ntlm
Package NTLM implements the interfaces used for interacting with NTLMv1 and NTLMv2.
Package NTLM implements the interfaces used for interacting with NTLMv1 and NTLMv2.
go-ntlm/ntlm/md4
Package md4 implements the MD4 hash algorithm as defined in RFC 1320.
Package md4 implements the MD4 hash algorithm as defined in RFC 1320.

Jump to

Keyboard shortcuts

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