tunnel.go 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199
  1. /*
  2. * Copyright (c) 2015, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package psiphon
  20. import (
  21. "bytes"
  22. "encoding/base64"
  23. "encoding/json"
  24. "errors"
  25. "fmt"
  26. "io"
  27. "net"
  28. "net/url"
  29. "sync"
  30. "sync/atomic"
  31. "time"
  32. "github.com/Psiphon-Inc/crypto/ssh"
  33. "github.com/Psiphon-Inc/goarista/monotime"
  34. regen "github.com/Psiphon-Inc/goregen"
  35. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  36. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/transferstats"
  37. )
  38. // Tunneler specifies the interface required by components that use a tunnel.
  39. // Components which use this interface may be serviced by a single Tunnel instance,
  40. // or a Controller which manages a pool of tunnels, or any other object which
  41. // implements Tunneler.
  42. // alwaysTunnel indicates that the connection should always be tunneled. If this
  43. // is not set, the connection may be made directly, depending on split tunnel
  44. // classification, when that feature is supported and active.
  45. // downstreamConn is an optional parameter which specifies a connection to be
  46. // explictly closed when the Dialed connection is closed. For instance, this
  47. // is used to close downstreamConn App<->LocalProxy connections when the related
  48. // LocalProxy<->SshPortForward connections close.
  49. type Tunneler interface {
  50. Dial(remoteAddr string, alwaysTunnel bool, downstreamConn net.Conn) (conn net.Conn, err error)
  51. SignalComponentFailure()
  52. }
  53. // TunnerOwner specifies the interface required by Tunnel to notify its
  54. // owner when it has failed. The owner may, as in the case of the Controller,
  55. // remove the tunnel from its list of active tunnels.
  56. type TunnelOwner interface {
  57. SignalTunnelFailure(tunnel *Tunnel)
  58. }
  59. // Tunnel is a connection to a Psiphon server. An established
  60. // tunnel includes a network connection to the specified server
  61. // and an SSH session built on top of that transport.
  62. type Tunnel struct {
  63. mutex *sync.Mutex
  64. config *Config
  65. untunneledDialConfig *DialConfig
  66. isDiscarded bool
  67. isClosed bool
  68. serverEntry *ServerEntry
  69. serverContext *ServerContext
  70. protocol string
  71. conn *common.ActivityMonitoredConn
  72. sshClient *ssh.Client
  73. operateWaitGroup *sync.WaitGroup
  74. shutdownOperateBroadcast chan struct{}
  75. signalPortForwardFailure chan struct{}
  76. totalPortForwardFailures int
  77. establishDuration time.Duration
  78. establishedTime monotime.Time
  79. dialStats *TunnelDialStats
  80. newClientVerificationPayload chan string
  81. }
  82. // TunnelDialStats records additional dial config that is sent to the server for stats
  83. // recording. This data is used to analyze which configuration settings are successful
  84. // in various circumvention contexts, and includes meek dial params and upstream proxy
  85. // params.
  86. // For upstream proxy, only proxy type and custom header names are recorded; proxy
  87. // address and custom header values are considered PII.
  88. type TunnelDialStats struct {
  89. UpstreamProxyType string
  90. UpstreamProxyCustomHeaderNames []string
  91. MeekDialAddress string
  92. MeekResolvedIPAddress string
  93. MeekSNIServerName string
  94. MeekHostHeader string
  95. MeekTransformedHostName bool
  96. }
  97. // EstablishTunnel first makes a network transport connection to the
  98. // Psiphon server and then establishes an SSH client session on top of
  99. // that transport. The SSH server is authenticated using the public
  100. // key in the server entry.
  101. // Depending on the server's capabilities, the connection may use
  102. // plain SSH over TCP, obfuscated SSH over TCP, or obfuscated SSH over
  103. // HTTP (meek protocol).
  104. // When requiredProtocol is not blank, that protocol is used. Otherwise,
  105. // the a random supported protocol is used.
  106. // untunneledDialConfig is used for untunneled final status requests.
  107. func EstablishTunnel(
  108. config *Config,
  109. untunneledDialConfig *DialConfig,
  110. sessionId string,
  111. pendingConns *common.Conns,
  112. serverEntry *ServerEntry,
  113. adjustedEstablishStartTime monotime.Time,
  114. tunnelOwner TunnelOwner) (tunnel *Tunnel, err error) {
  115. selectedProtocol, err := selectProtocol(config, serverEntry)
  116. if err != nil {
  117. return nil, common.ContextError(err)
  118. }
  119. // Build transport layers and establish SSH connection. Note that
  120. // dialConn and monitoredConn are the same network connection.
  121. dialConn, monitoredConn, sshClient, dialStats, err := dialSsh(
  122. config, pendingConns, serverEntry, selectedProtocol, sessionId)
  123. if err != nil {
  124. return nil, common.ContextError(err)
  125. }
  126. // Cleanup on error
  127. defer func() {
  128. if err != nil {
  129. sshClient.Close()
  130. monitoredConn.Close()
  131. pendingConns.Remove(dialConn)
  132. }
  133. }()
  134. // The tunnel is now connected
  135. tunnel = &Tunnel{
  136. mutex: new(sync.Mutex),
  137. config: config,
  138. untunneledDialConfig: untunneledDialConfig,
  139. isClosed: false,
  140. serverEntry: serverEntry,
  141. protocol: selectedProtocol,
  142. conn: monitoredConn,
  143. sshClient: sshClient,
  144. operateWaitGroup: new(sync.WaitGroup),
  145. shutdownOperateBroadcast: make(chan struct{}),
  146. // A buffer allows at least one signal to be sent even when the receiver is
  147. // not listening. Senders should not block.
  148. signalPortForwardFailure: make(chan struct{}, 1),
  149. dialStats: dialStats,
  150. // Buffer allows SetClientVerificationPayload to submit one new payload
  151. // without blocking or dropping it.
  152. newClientVerificationPayload: make(chan string, 1),
  153. }
  154. // Create a new Psiphon API server context for this tunnel. This includes
  155. // performing a handshake request. If the handshake fails, this establishment
  156. // fails.
  157. if !config.DisableApi {
  158. NoticeInfo("starting server context for %s", tunnel.serverEntry.IpAddress)
  159. tunnel.serverContext, err = NewServerContext(tunnel, sessionId)
  160. if err != nil {
  161. return nil, common.ContextError(
  162. fmt.Errorf("error starting server context for %s: %s",
  163. tunnel.serverEntry.IpAddress, err))
  164. }
  165. }
  166. // establishDuration is the elapsed time between the controller starting tunnel
  167. // establishment and this tunnel being established. The reported value represents
  168. // how long the user waited between starting the client and having a usable tunnel;
  169. // or how long between the client detecting an unexpected tunnel disconnect and
  170. // completing automatic reestablishment.
  171. //
  172. // This time period may include time spent unsuccessfully connecting to other
  173. // servers. Time spent waiting for network connectivity is excluded.
  174. tunnel.establishDuration = monotime.Since(adjustedEstablishStartTime)
  175. tunnel.establishedTime = monotime.Now()
  176. // Now that network operations are complete, cancel interruptibility
  177. pendingConns.Remove(dialConn)
  178. // Spawn the operateTunnel goroutine, which monitors the tunnel and handles periodic stats updates.
  179. tunnel.operateWaitGroup.Add(1)
  180. go tunnel.operateTunnel(tunnelOwner)
  181. return tunnel, nil
  182. }
  183. // Close stops operating the tunnel and closes the underlying connection.
  184. // Supports multiple and/or concurrent calls to Close().
  185. // When isDicarded is set, operateTunnel will not attempt to send final
  186. // status requests.
  187. func (tunnel *Tunnel) Close(isDiscarded bool) {
  188. tunnel.mutex.Lock()
  189. tunnel.isDiscarded = isDiscarded
  190. isClosed := tunnel.isClosed
  191. tunnel.isClosed = true
  192. tunnel.mutex.Unlock()
  193. if !isClosed {
  194. // Signal operateTunnel to stop before closing the tunnel -- this
  195. // allows a final status request to be made in the case of an orderly
  196. // shutdown.
  197. // A timer is set, so if operateTunnel takes too long to stop, the
  198. // tunnel is closed, which will interrupt any slow final status request.
  199. // In effect, the TUNNEL_OPERATE_SHUTDOWN_TIMEOUT value will take
  200. // precedence over the PSIPHON_API_SERVER_TIMEOUT http.Client.Timeout
  201. // value set in makePsiphonHttpsClient.
  202. timer := time.AfterFunc(TUNNEL_OPERATE_SHUTDOWN_TIMEOUT, func() { tunnel.conn.Close() })
  203. close(tunnel.shutdownOperateBroadcast)
  204. tunnel.operateWaitGroup.Wait()
  205. timer.Stop()
  206. tunnel.sshClient.Close()
  207. // tunnel.conn.Close() may get called multiple times, which is allowed.
  208. tunnel.conn.Close()
  209. }
  210. }
  211. // IsClosed returns the tunnel's closed status.
  212. func (tunnel *Tunnel) IsClosed() bool {
  213. tunnel.mutex.Lock()
  214. defer tunnel.mutex.Unlock()
  215. return tunnel.isClosed
  216. }
  217. // IsDiscarded returns the tunnel's discarded flag.
  218. func (tunnel *Tunnel) IsDiscarded() bool {
  219. tunnel.mutex.Lock()
  220. defer tunnel.mutex.Unlock()
  221. return tunnel.isDiscarded
  222. }
  223. // SendAPIRequest sends an API request as an SSH request through the tunnel.
  224. // This function blocks awaiting a response. Only one request may be in-flight
  225. // at once; a concurrent SendAPIRequest will block until an active request
  226. // receives its response (or the SSH connection is terminated).
  227. func (tunnel *Tunnel) SendAPIRequest(
  228. name string, requestPayload []byte) ([]byte, error) {
  229. if tunnel.IsClosed() {
  230. return nil, common.ContextError(errors.New("tunnel is closed"))
  231. }
  232. ok, responsePayload, err := tunnel.sshClient.Conn.SendRequest(
  233. name, true, requestPayload)
  234. if err != nil {
  235. return nil, common.ContextError(err)
  236. }
  237. if !ok {
  238. return nil, common.ContextError(errors.New("API request rejected"))
  239. }
  240. return responsePayload, nil
  241. }
  242. // Dial establishes a port forward connection through the tunnel
  243. // This Dial doesn't support split tunnel, so alwaysTunnel is not referenced
  244. func (tunnel *Tunnel) Dial(
  245. remoteAddr string, alwaysTunnel bool, downstreamConn net.Conn) (conn net.Conn, err error) {
  246. if tunnel.IsClosed() {
  247. return nil, common.ContextError(errors.New("tunnel is closed"))
  248. }
  249. type tunnelDialResult struct {
  250. sshPortForwardConn net.Conn
  251. err error
  252. }
  253. resultChannel := make(chan *tunnelDialResult, 2)
  254. if *tunnel.config.TunnelPortForwardDialTimeoutSeconds > 0 {
  255. time.AfterFunc(time.Duration(*tunnel.config.TunnelPortForwardDialTimeoutSeconds)*time.Second, func() {
  256. resultChannel <- &tunnelDialResult{nil, errors.New("tunnel dial timeout")}
  257. })
  258. }
  259. go func() {
  260. sshPortForwardConn, err := tunnel.sshClient.Dial("tcp", remoteAddr)
  261. resultChannel <- &tunnelDialResult{sshPortForwardConn, err}
  262. }()
  263. result := <-resultChannel
  264. if result.err != nil {
  265. // TODO: conditional on type of error or error message?
  266. select {
  267. case tunnel.signalPortForwardFailure <- *new(struct{}):
  268. default:
  269. }
  270. return nil, common.ContextError(result.err)
  271. }
  272. conn = &TunneledConn{
  273. Conn: result.sshPortForwardConn,
  274. tunnel: tunnel,
  275. downstreamConn: downstreamConn}
  276. // Tunnel does not have a serverContext when DisableApi is set. We still use
  277. // transferstats.Conn to count bytes transferred for monitoring tunnel
  278. // quality.
  279. var regexps *transferstats.Regexps
  280. if tunnel.serverContext != nil {
  281. regexps = tunnel.serverContext.StatsRegexps()
  282. }
  283. conn = transferstats.NewConn(conn, tunnel.serverEntry.IpAddress, regexps)
  284. return conn, nil
  285. }
  286. // SignalComponentFailure notifies the tunnel that an associated component has failed.
  287. // This will terminate the tunnel.
  288. func (tunnel *Tunnel) SignalComponentFailure() {
  289. NoticeAlert("tunnel received component failure signal")
  290. tunnel.Close(false)
  291. }
  292. // SetClientVerificationPayload triggers a client verification request, for this
  293. // tunnel, with the specified verifiction payload. If the tunnel is not yet established,
  294. // the payload/request is enqueued. If a payload/request is already eneueued, the
  295. // new payload is dropped.
  296. func (tunnel *Tunnel) SetClientVerificationPayload(clientVerificationPayload string) {
  297. select {
  298. case tunnel.newClientVerificationPayload <- clientVerificationPayload:
  299. default:
  300. }
  301. }
  302. // TunneledConn implements net.Conn and wraps a port foward connection.
  303. // It is used to hook into Read and Write to observe I/O errors and
  304. // report these errors back to the tunnel monitor as port forward failures.
  305. // TunneledConn optionally tracks a peer connection to be explictly closed
  306. // when the TunneledConn is closed.
  307. type TunneledConn struct {
  308. net.Conn
  309. tunnel *Tunnel
  310. downstreamConn net.Conn
  311. }
  312. func (conn *TunneledConn) Read(buffer []byte) (n int, err error) {
  313. n, err = conn.Conn.Read(buffer)
  314. if err != nil && err != io.EOF {
  315. // Report new failure. Won't block; assumes the receiver
  316. // has a sufficient buffer for the threshold number of reports.
  317. // TODO: conditional on type of error or error message?
  318. select {
  319. case conn.tunnel.signalPortForwardFailure <- *new(struct{}):
  320. default:
  321. }
  322. }
  323. return
  324. }
  325. func (conn *TunneledConn) Write(buffer []byte) (n int, err error) {
  326. n, err = conn.Conn.Write(buffer)
  327. if err != nil && err != io.EOF {
  328. // Same as TunneledConn.Read()
  329. select {
  330. case conn.tunnel.signalPortForwardFailure <- *new(struct{}):
  331. default:
  332. }
  333. }
  334. return
  335. }
  336. func (conn *TunneledConn) Close() error {
  337. if conn.downstreamConn != nil {
  338. conn.downstreamConn.Close()
  339. }
  340. return conn.Conn.Close()
  341. }
  342. // selectProtocol is a helper that picks the tunnel protocol
  343. func selectProtocol(config *Config, serverEntry *ServerEntry) (selectedProtocol string, err error) {
  344. // TODO: properly handle protocols (e.g. FRONTED-MEEK-OSSH) vs. capabilities (e.g., {FRONTED-MEEK, OSSH})
  345. // for now, the code is simply assuming that MEEK capabilities imply OSSH capability.
  346. if config.TunnelProtocol != "" {
  347. if !serverEntry.SupportsProtocol(config.TunnelProtocol) {
  348. return "", common.ContextError(fmt.Errorf("server does not have required capability"))
  349. }
  350. selectedProtocol = config.TunnelProtocol
  351. } else {
  352. // Pick at random from the supported protocols. This ensures that we'll eventually
  353. // try all possible protocols. Depending on network configuration, it may be the
  354. // case that some protocol is only available through multi-capability servers,
  355. // and a simpler ranked preference of protocols could lead to that protocol never
  356. // being selected.
  357. candidateProtocols := serverEntry.GetSupportedProtocols()
  358. if len(candidateProtocols) == 0 {
  359. return "", common.ContextError(fmt.Errorf("server does not have any supported capabilities"))
  360. }
  361. index, err := common.MakeSecureRandomInt(len(candidateProtocols))
  362. if err != nil {
  363. return "", common.ContextError(err)
  364. }
  365. selectedProtocol = candidateProtocols[index]
  366. }
  367. return selectedProtocol, nil
  368. }
  369. // selectFrontingParameters is a helper which selects/generates meek fronting
  370. // parameters where the server entry provides multiple options or patterns.
  371. func selectFrontingParameters(
  372. serverEntry *ServerEntry) (frontingAddress, frontingHost string, err error) {
  373. if len(serverEntry.MeekFrontingAddressesRegex) > 0 {
  374. // Generate a front address based on the regex.
  375. frontingAddress, err = regen.Generate(serverEntry.MeekFrontingAddressesRegex)
  376. if err != nil {
  377. return "", "", common.ContextError(err)
  378. }
  379. } else {
  380. // Randomly select, for this connection attempt, one front address for
  381. // fronting-capable servers.
  382. if len(serverEntry.MeekFrontingAddresses) == 0 {
  383. return "", "", common.ContextError(errors.New("MeekFrontingAddresses is empty"))
  384. }
  385. index, err := common.MakeSecureRandomInt(len(serverEntry.MeekFrontingAddresses))
  386. if err != nil {
  387. return "", "", common.ContextError(err)
  388. }
  389. frontingAddress = serverEntry.MeekFrontingAddresses[index]
  390. }
  391. if len(serverEntry.MeekFrontingHosts) > 0 {
  392. index, err := common.MakeSecureRandomInt(len(serverEntry.MeekFrontingHosts))
  393. if err != nil {
  394. return "", "", common.ContextError(err)
  395. }
  396. frontingHost = serverEntry.MeekFrontingHosts[index]
  397. } else {
  398. // Backwards compatibility case
  399. frontingHost = serverEntry.MeekFrontingHost
  400. }
  401. return
  402. }
  403. // initMeekConfig is a helper that creates a MeekConfig suitable for the
  404. // selected meek tunnel protocol.
  405. func initMeekConfig(
  406. config *Config,
  407. serverEntry *ServerEntry,
  408. selectedProtocol,
  409. sessionId string) (*MeekConfig, error) {
  410. // The meek protocol always uses OSSH
  411. psiphonServerAddress := fmt.Sprintf("%s:%d", serverEntry.IpAddress, serverEntry.SshObfuscatedPort)
  412. var dialAddress string
  413. useHTTPS := false
  414. var SNIServerName, hostHeader string
  415. transformedHostName := false
  416. switch selectedProtocol {
  417. case common.TUNNEL_PROTOCOL_FRONTED_MEEK:
  418. frontingAddress, frontingHost, err := selectFrontingParameters(serverEntry)
  419. if err != nil {
  420. return nil, common.ContextError(err)
  421. }
  422. dialAddress = fmt.Sprintf("%s:443", frontingAddress)
  423. useHTTPS = true
  424. if !serverEntry.MeekFrontingDisableSNI {
  425. SNIServerName, transformedHostName =
  426. config.HostNameTransformer.TransformHostName(frontingAddress)
  427. }
  428. hostHeader = frontingHost
  429. case common.TUNNEL_PROTOCOL_FRONTED_MEEK_HTTP:
  430. frontingAddress, frontingHost, err := selectFrontingParameters(serverEntry)
  431. if err != nil {
  432. return nil, common.ContextError(err)
  433. }
  434. dialAddress = fmt.Sprintf("%s:80", frontingAddress)
  435. hostHeader = frontingHost
  436. case common.TUNNEL_PROTOCOL_UNFRONTED_MEEK:
  437. dialAddress = fmt.Sprintf("%s:%d", serverEntry.IpAddress, serverEntry.MeekServerPort)
  438. hostname := serverEntry.IpAddress
  439. hostname, transformedHostName = config.HostNameTransformer.TransformHostName(hostname)
  440. if serverEntry.MeekServerPort == 80 {
  441. hostHeader = hostname
  442. } else {
  443. hostHeader = fmt.Sprintf("%s:%d", hostname, serverEntry.MeekServerPort)
  444. }
  445. case common.TUNNEL_PROTOCOL_UNFRONTED_MEEK_HTTPS:
  446. dialAddress = fmt.Sprintf("%s:%d", serverEntry.IpAddress, serverEntry.MeekServerPort)
  447. useHTTPS = true
  448. SNIServerName, transformedHostName =
  449. config.HostNameTransformer.TransformHostName(serverEntry.IpAddress)
  450. if serverEntry.MeekServerPort == 443 {
  451. hostHeader = serverEntry.IpAddress
  452. } else {
  453. hostHeader = fmt.Sprintf("%s:%d", serverEntry.IpAddress, serverEntry.MeekServerPort)
  454. }
  455. default:
  456. return nil, common.ContextError(errors.New("unexpected selectedProtocol"))
  457. }
  458. // The unnderlying TLS will automatically disable SNI for IP address server name
  459. // values; we have this explicit check here so we record the correct value for stats.
  460. if net.ParseIP(SNIServerName) != nil {
  461. SNIServerName = ""
  462. }
  463. return &MeekConfig{
  464. DialAddress: dialAddress,
  465. UseHTTPS: useHTTPS,
  466. SNIServerName: SNIServerName,
  467. HostHeader: hostHeader,
  468. TransformedHostName: transformedHostName,
  469. PsiphonServerAddress: psiphonServerAddress,
  470. SessionID: sessionId,
  471. MeekCookieEncryptionPublicKey: serverEntry.MeekCookieEncryptionPublicKey,
  472. MeekObfuscatedKey: serverEntry.MeekObfuscatedKey,
  473. }, nil
  474. }
  475. // dialSsh is a helper that builds the transport layers and establishes the SSH connection.
  476. // When additional dial configuration is used, DialStats are recorded and returned.
  477. //
  478. // The net.Conn return value is the value to be removed from pendingConns; additional
  479. // layering (ThrottledConn, ActivityMonitoredConn) is applied, but this return value is the
  480. // base dial conn. The *ActivityMonitoredConn return value is the layered conn passed into
  481. // the ssh.Client.
  482. func dialSsh(
  483. config *Config,
  484. pendingConns *common.Conns,
  485. serverEntry *ServerEntry,
  486. selectedProtocol,
  487. sessionId string) (net.Conn, *common.ActivityMonitoredConn, *ssh.Client, *TunnelDialStats, error) {
  488. // The meek protocols tunnel obfuscated SSH. Obfuscated SSH is layered on top of SSH.
  489. // So depending on which protocol is used, multiple layers are initialized.
  490. useObfuscatedSsh := false
  491. var directTCPDialAddress string
  492. var meekConfig *MeekConfig
  493. var err error
  494. switch selectedProtocol {
  495. case common.TUNNEL_PROTOCOL_OBFUSCATED_SSH:
  496. useObfuscatedSsh = true
  497. directTCPDialAddress = fmt.Sprintf("%s:%d", serverEntry.IpAddress, serverEntry.SshObfuscatedPort)
  498. case common.TUNNEL_PROTOCOL_SSH:
  499. directTCPDialAddress = fmt.Sprintf("%s:%d", serverEntry.IpAddress, serverEntry.SshPort)
  500. default:
  501. useObfuscatedSsh = true
  502. meekConfig, err = initMeekConfig(config, serverEntry, selectedProtocol, sessionId)
  503. if err != nil {
  504. return nil, nil, nil, nil, common.ContextError(err)
  505. }
  506. }
  507. NoticeConnectingServer(
  508. serverEntry.IpAddress,
  509. serverEntry.Region,
  510. selectedProtocol,
  511. directTCPDialAddress,
  512. meekConfig)
  513. // Use an asynchronous callback to record the resolved IP address when
  514. // dialing a domain name. Note that DialMeek doesn't immediately
  515. // establish any HTTPS connections, so the resolved IP address won't be
  516. // reported until during/after ssh session establishment (the ssh traffic
  517. // is meek payload). So don't Load() the IP address value until after that
  518. // has completed to ensure a result.
  519. var resolvedIPAddress atomic.Value
  520. resolvedIPAddress.Store("")
  521. setResolvedIPAddress := func(IPAddress string) {
  522. resolvedIPAddress.Store(IPAddress)
  523. }
  524. // Create the base transport: meek or direct connection
  525. dialConfig := &DialConfig{
  526. UpstreamProxyUrl: config.UpstreamProxyUrl,
  527. UpstreamProxyCustomHeaders: config.UpstreamProxyCustomHeaders,
  528. ConnectTimeout: time.Duration(*config.TunnelConnectTimeoutSeconds) * time.Second,
  529. PendingConns: pendingConns,
  530. DeviceBinder: config.DeviceBinder,
  531. DnsServerGetter: config.DnsServerGetter,
  532. UseIndistinguishableTLS: config.UseIndistinguishableTLS,
  533. TrustedCACertificatesFilename: config.TrustedCACertificatesFilename,
  534. DeviceRegion: config.DeviceRegion,
  535. ResolvedIPCallback: setResolvedIPAddress,
  536. }
  537. var dialConn net.Conn
  538. if meekConfig != nil {
  539. dialConn, err = DialMeek(meekConfig, dialConfig)
  540. if err != nil {
  541. return nil, nil, nil, nil, common.ContextError(err)
  542. }
  543. } else {
  544. dialConn, err = DialTCP(directTCPDialAddress, dialConfig)
  545. if err != nil {
  546. return nil, nil, nil, nil, common.ContextError(err)
  547. }
  548. }
  549. cleanupConn := dialConn
  550. defer func() {
  551. // Cleanup on error
  552. if cleanupConn != nil {
  553. cleanupConn.Close()
  554. pendingConns.Remove(cleanupConn)
  555. }
  556. }()
  557. // Activity monitoring is used to measure tunnel duration
  558. monitoredConn, err := common.NewActivityMonitoredConn(dialConn, 0, false, nil)
  559. if err != nil {
  560. return nil, nil, nil, nil, common.ContextError(err)
  561. }
  562. // Apply throttling (if configured)
  563. throttledConn := common.NewThrottledConn(monitoredConn, config.RateLimits)
  564. // Add obfuscated SSH layer
  565. var sshConn net.Conn = throttledConn
  566. if useObfuscatedSsh {
  567. sshConn, err = NewObfuscatedSshConn(
  568. OBFUSCATION_CONN_MODE_CLIENT, throttledConn, serverEntry.SshObfuscatedKey)
  569. if err != nil {
  570. return nil, nil, nil, nil, common.ContextError(err)
  571. }
  572. }
  573. // Now establish the SSH session over the conn transport
  574. expectedPublicKey, err := base64.StdEncoding.DecodeString(serverEntry.SshHostKey)
  575. if err != nil {
  576. return nil, nil, nil, nil, common.ContextError(err)
  577. }
  578. sshCertChecker := &ssh.CertChecker{
  579. HostKeyFallback: func(addr string, remote net.Addr, publicKey ssh.PublicKey) error {
  580. if !bytes.Equal(expectedPublicKey, publicKey.Marshal()) {
  581. return common.ContextError(errors.New("unexpected host public key"))
  582. }
  583. return nil
  584. },
  585. }
  586. sshPasswordPayload, err := json.Marshal(
  587. struct {
  588. SessionId string `json:"SessionId"`
  589. SshPassword string `json:"SshPassword"`
  590. }{sessionId, serverEntry.SshPassword})
  591. if err != nil {
  592. return nil, nil, nil, nil, common.ContextError(err)
  593. }
  594. sshClientConfig := &ssh.ClientConfig{
  595. User: serverEntry.SshUsername,
  596. Auth: []ssh.AuthMethod{
  597. ssh.Password(string(sshPasswordPayload)),
  598. },
  599. HostKeyCallback: sshCertChecker.CheckHostKey,
  600. }
  601. // The ssh session establishment (via ssh.NewClientConn) is wrapped
  602. // in a timeout to ensure it won't hang. We've encountered firewalls
  603. // that allow the TCP handshake to complete but then send a RST to the
  604. // server-side and nothing to the client-side, and if that happens
  605. // while ssh.NewClientConn is reading, it may wait forever. The timeout
  606. // closes the conn, which interrupts it.
  607. // Note: TCP handshake timeouts are provided by TCPConn, and session
  608. // timeouts *after* ssh establishment are provided by the ssh keep alive
  609. // in operate tunnel.
  610. // TODO: adjust the timeout to account for time-elapsed-from-start
  611. type sshNewClientResult struct {
  612. sshClient *ssh.Client
  613. err error
  614. }
  615. resultChannel := make(chan *sshNewClientResult, 2)
  616. if *config.TunnelConnectTimeoutSeconds > 0 {
  617. time.AfterFunc(time.Duration(*config.TunnelConnectTimeoutSeconds)*time.Second, func() {
  618. resultChannel <- &sshNewClientResult{nil, errors.New("ssh dial timeout")}
  619. })
  620. }
  621. go func() {
  622. // The following is adapted from ssh.Dial(), here using a custom conn
  623. // The sshAddress is passed through to host key verification callbacks; we don't use it.
  624. sshAddress := ""
  625. sshClientConn, sshChans, sshReqs, err := ssh.NewClientConn(sshConn, sshAddress, sshClientConfig)
  626. var sshClient *ssh.Client
  627. if err == nil {
  628. sshClient = ssh.NewClient(sshClientConn, sshChans, sshReqs)
  629. }
  630. resultChannel <- &sshNewClientResult{sshClient, err}
  631. }()
  632. result := <-resultChannel
  633. if result.err != nil {
  634. return nil, nil, nil, nil, common.ContextError(result.err)
  635. }
  636. var dialStats *TunnelDialStats
  637. if dialConfig.UpstreamProxyUrl != "" || meekConfig != nil {
  638. dialStats = &TunnelDialStats{}
  639. if dialConfig.UpstreamProxyUrl != "" {
  640. // Note: UpstreamProxyUrl should have parsed correctly in the dial
  641. proxyURL, err := url.Parse(dialConfig.UpstreamProxyUrl)
  642. if err == nil {
  643. dialStats.UpstreamProxyType = proxyURL.Scheme
  644. }
  645. dialStats.UpstreamProxyCustomHeaderNames = make([]string, 0)
  646. for name, _ := range dialConfig.UpstreamProxyCustomHeaders {
  647. dialStats.UpstreamProxyCustomHeaderNames = append(dialStats.UpstreamProxyCustomHeaderNames, name)
  648. }
  649. }
  650. if meekConfig != nil {
  651. dialStats.MeekDialAddress = meekConfig.DialAddress
  652. dialStats.MeekResolvedIPAddress = resolvedIPAddress.Load().(string)
  653. dialStats.MeekSNIServerName = meekConfig.SNIServerName
  654. dialStats.MeekHostHeader = meekConfig.HostHeader
  655. dialStats.MeekTransformedHostName = meekConfig.TransformedHostName
  656. }
  657. NoticeConnectedTunnelDialStats(serverEntry.IpAddress, dialStats)
  658. }
  659. cleanupConn = nil
  660. // Note: dialConn may be used to close the underlying network connection
  661. // but should not be used to perform I/O as that would interfere with SSH
  662. // (and also bypasses throttling).
  663. return dialConn, monitoredConn, result.sshClient, dialStats, nil
  664. }
  665. func makeRandomPeriod(min, max time.Duration) time.Duration {
  666. period, err := common.MakeRandomPeriod(min, max)
  667. if err != nil {
  668. NoticeAlert("MakeRandomPeriod failed: %s", err)
  669. // Proceed without random period
  670. period = max
  671. }
  672. return period
  673. }
  674. // operateTunnel monitors the health of the tunnel and performs
  675. // periodic work.
  676. //
  677. // BytesTransferred and TotalBytesTransferred notices are emitted
  678. // for live reporting and diagnostics reporting, respectively.
  679. //
  680. // Status requests are sent to the Psiphon API to report bytes
  681. // transferred.
  682. //
  683. // Periodic SSH keep alive packets are sent to ensure the underlying
  684. // TCP connection isn't terminated by NAT, or other network
  685. // interference -- or test if it has been terminated while the device
  686. // has been asleep. When a keep alive times out, the tunnel is
  687. // considered failed.
  688. //
  689. // An immediate SSH keep alive "probe" is sent to test the tunnel and
  690. // server responsiveness when a port forward failure is detected: a
  691. // failed dial or failed read/write. This keep alive has a shorter
  692. // timeout.
  693. //
  694. // Note that port foward failures may be due to non-failure conditions.
  695. // For example, when the user inputs an invalid domain name and
  696. // resolution is done by the ssh server; or trying to connect to a
  697. // non-white-listed port; and the error message in these cases is not
  698. // distinguishable from a a true server error (a common error message,
  699. // "ssh: rejected: administratively prohibited (open failed)", may be
  700. // returned for these cases but also if the server has run out of
  701. // ephemeral ports, for example).
  702. //
  703. // SSH keep alives are not sent when the tunnel has been recently
  704. // active (not only does tunnel activity obviate the necessity of a keep
  705. // alive, testing has shown that keep alives may time out for "busy"
  706. // tunnels, especially over meek protocol and other high latency
  707. // conditions).
  708. //
  709. // "Recently active" is defined has having received payload bytes. Sent
  710. // bytes are not considered as testing has shown bytes may appear to
  711. // send when certain NAT devices have interfered with the tunnel, while
  712. // no bytes are received. In a pathological case, with DNS implemented
  713. // as tunneled UDP, a browser may wait excessively for a domain name to
  714. // resolve, while no new port forward is attempted which would otherwise
  715. // result in a tunnel failure detection.
  716. //
  717. // TODO: change "recently active" to include having received any
  718. // SSH protocol messages from the server, not just user payload?
  719. //
  720. func (tunnel *Tunnel) operateTunnel(tunnelOwner TunnelOwner) {
  721. defer tunnel.operateWaitGroup.Done()
  722. lastBytesReceivedTime := monotime.Now()
  723. lastTotalBytesTransferedTime := monotime.Now()
  724. totalSent := int64(0)
  725. totalReceived := int64(0)
  726. noticeBytesTransferredTicker := time.NewTicker(1 * time.Second)
  727. defer noticeBytesTransferredTicker.Stop()
  728. // The next status request and ssh keep alive times are picked at random,
  729. // from a range, to make the resulting traffic less fingerprintable,
  730. // Note: not using Tickers since these are not fixed time periods.
  731. nextStatusRequestPeriod := func() time.Duration {
  732. return makeRandomPeriod(
  733. PSIPHON_API_STATUS_REQUEST_PERIOD_MIN,
  734. PSIPHON_API_STATUS_REQUEST_PERIOD_MAX)
  735. }
  736. statsTimer := time.NewTimer(nextStatusRequestPeriod())
  737. defer statsTimer.Stop()
  738. // Schedule an immediate status request to deliver any unreported
  739. // tunnel stats.
  740. // Note: this may not be effective when there's an outstanding
  741. // asynchronous untunneled final status request is holding the
  742. // tunnel stats records. It may also conflict with other
  743. // tunnel candidates which attempt to send an immediate request
  744. // before being discarded. For now, we mitigate this with a short,
  745. // random delay.
  746. unreported := CountUnreportedTunnelStats()
  747. if unreported > 0 {
  748. NoticeInfo("Unreported tunnel stats: %d", unreported)
  749. statsTimer.Reset(makeRandomPeriod(
  750. PSIPHON_API_STATUS_REQUEST_SHORT_PERIOD_MIN,
  751. PSIPHON_API_STATUS_REQUEST_SHORT_PERIOD_MAX))
  752. }
  753. nextSshKeepAlivePeriod := func() time.Duration {
  754. return makeRandomPeriod(
  755. TUNNEL_SSH_KEEP_ALIVE_PERIOD_MIN,
  756. TUNNEL_SSH_KEEP_ALIVE_PERIOD_MAX)
  757. }
  758. // TODO: don't initialize timer when config.DisablePeriodicSshKeepAlive is set
  759. sshKeepAliveTimer := time.NewTimer(nextSshKeepAlivePeriod())
  760. if tunnel.config.DisablePeriodicSshKeepAlive {
  761. sshKeepAliveTimer.Stop()
  762. } else {
  763. defer sshKeepAliveTimer.Stop()
  764. }
  765. // Perform network requests in separate goroutines so as not to block
  766. // other operations.
  767. requestsWaitGroup := new(sync.WaitGroup)
  768. requestsWaitGroup.Add(1)
  769. signalStatusRequest := make(chan struct{})
  770. go func() {
  771. defer requestsWaitGroup.Done()
  772. for _ = range signalStatusRequest {
  773. sendStats(tunnel)
  774. }
  775. }()
  776. requestsWaitGroup.Add(1)
  777. signalSshKeepAlive := make(chan time.Duration)
  778. sshKeepAliveError := make(chan error, 1)
  779. go func() {
  780. defer requestsWaitGroup.Done()
  781. for timeout := range signalSshKeepAlive {
  782. err := sendSshKeepAlive(tunnel.sshClient, tunnel.conn, timeout)
  783. if err != nil {
  784. select {
  785. case sshKeepAliveError <- err:
  786. default:
  787. }
  788. }
  789. }
  790. }()
  791. requestsWaitGroup.Add(1)
  792. signalStopClientVerificationRequests := make(chan struct{})
  793. go func() {
  794. defer requestsWaitGroup.Done()
  795. clientVerificationRequestSuccess := true
  796. clientVerificationPayload := ""
  797. failCount := 0
  798. for {
  799. // TODO: use reflect.SelectCase?
  800. if clientVerificationRequestSuccess == true {
  801. failCount = 0
  802. select {
  803. case clientVerificationPayload = <-tunnel.newClientVerificationPayload:
  804. case <-signalStopClientVerificationRequests:
  805. return
  806. }
  807. } else {
  808. // If sendClientVerification failed to send the payload we
  809. // will retry after a delay. Will use a new payload instead
  810. // if that arrives in the meantime.
  811. // If failures count is more than PSIPHON_API_CLIENT_VERIFICATION_REQUEST_MAX_RETRIES
  812. // stop retrying for this tunnel.
  813. failCount += 1
  814. if failCount > PSIPHON_API_CLIENT_VERIFICATION_REQUEST_MAX_RETRIES {
  815. return
  816. }
  817. timeout := time.After(PSIPHON_API_CLIENT_VERIFICATION_REQUEST_RETRY_PERIOD)
  818. select {
  819. case <-timeout:
  820. case clientVerificationPayload = <-tunnel.newClientVerificationPayload:
  821. case <-signalStopClientVerificationRequests:
  822. return
  823. }
  824. }
  825. clientVerificationRequestSuccess = sendClientVerification(tunnel, clientVerificationPayload)
  826. }
  827. }()
  828. shutdown := false
  829. var err error
  830. for !shutdown && err == nil {
  831. select {
  832. case <-noticeBytesTransferredTicker.C:
  833. sent, received := transferstats.ReportRecentBytesTransferredForServer(
  834. tunnel.serverEntry.IpAddress)
  835. if received > 0 {
  836. lastBytesReceivedTime = monotime.Now()
  837. }
  838. totalSent += sent
  839. totalReceived += received
  840. if lastTotalBytesTransferedTime.Add(TOTAL_BYTES_TRANSFERRED_NOTICE_PERIOD).Before(monotime.Now()) {
  841. NoticeTotalBytesTransferred(tunnel.serverEntry.IpAddress, totalSent, totalReceived)
  842. lastTotalBytesTransferedTime = monotime.Now()
  843. }
  844. // Only emit the frequent BytesTransferred notice when tunnel is not idle.
  845. if tunnel.config.EmitBytesTransferred && (sent > 0 || received > 0) {
  846. NoticeBytesTransferred(tunnel.serverEntry.IpAddress, sent, received)
  847. }
  848. case <-statsTimer.C:
  849. select {
  850. case signalStatusRequest <- *new(struct{}):
  851. default:
  852. }
  853. statsTimer.Reset(nextStatusRequestPeriod())
  854. case <-sshKeepAliveTimer.C:
  855. if lastBytesReceivedTime.Add(TUNNEL_SSH_KEEP_ALIVE_PERIODIC_INACTIVE_PERIOD).Before(monotime.Now()) {
  856. select {
  857. case signalSshKeepAlive <- time.Duration(*tunnel.config.TunnelSshKeepAlivePeriodicTimeoutSeconds) * time.Second:
  858. default:
  859. }
  860. }
  861. sshKeepAliveTimer.Reset(nextSshKeepAlivePeriod())
  862. case <-tunnel.signalPortForwardFailure:
  863. // Note: no mutex on portForwardFailureTotal; only referenced here
  864. tunnel.totalPortForwardFailures++
  865. NoticeInfo("port forward failures for %s: %d",
  866. tunnel.serverEntry.IpAddress, tunnel.totalPortForwardFailures)
  867. if lastBytesReceivedTime.Add(TUNNEL_SSH_KEEP_ALIVE_PROBE_INACTIVE_PERIOD).Before(monotime.Now()) {
  868. select {
  869. case signalSshKeepAlive <- time.Duration(*tunnel.config.TunnelSshKeepAliveProbeTimeoutSeconds) * time.Second:
  870. default:
  871. }
  872. }
  873. if !tunnel.config.DisablePeriodicSshKeepAlive {
  874. sshKeepAliveTimer.Reset(nextSshKeepAlivePeriod())
  875. }
  876. case err = <-sshKeepAliveError:
  877. case <-tunnel.shutdownOperateBroadcast:
  878. shutdown = true
  879. }
  880. }
  881. close(signalSshKeepAlive)
  882. close(signalStatusRequest)
  883. close(signalStopClientVerificationRequests)
  884. requestsWaitGroup.Wait()
  885. // Capture bytes transferred since the last noticeBytesTransferredTicker tick
  886. sent, received := transferstats.ReportRecentBytesTransferredForServer(tunnel.serverEntry.IpAddress)
  887. totalSent += sent
  888. totalReceived += received
  889. // Always emit a final NoticeTotalBytesTransferred
  890. NoticeTotalBytesTransferred(tunnel.serverEntry.IpAddress, totalSent, totalReceived)
  891. // Tunnel does not have a serverContext when DisableApi is set.
  892. if tunnel.serverContext != nil && !tunnel.IsDiscarded() {
  893. // The stats for this tunnel will be reported via the next successful
  894. // status request.
  895. // Since client clocks are unreliable, we report the server's timestamp from
  896. // the handshake response as the absolute tunnel start time. This time
  897. // will be slightly earlier than the actual tunnel activation time, as the
  898. // client has to receive and parse the response and activate the tunnel.
  899. tunnelStartTime := tunnel.serverContext.serverHandshakeTimestamp
  900. // For the tunnel duration calculation, we use the local clock. The start time
  901. // is tunnel.establishedTime as recorded when the tunnel was established. For the
  902. // end time, we do not use the current time as we may now be long past the
  903. // actual termination time of the tunnel. For example, the host or device may
  904. // have resumed after a long sleep (it's not clear that the monotonic clock service
  905. // used to measure elapsed time will or will not stop during device sleep). Instead,
  906. // we use the last data received time as the estimated tunnel end time.
  907. //
  908. // One potential issue with using the last received time is receiving data
  909. // after an extended sleep because the device sleep occured with data still in
  910. // the OS socket read buffer. This is not expected to happen on Android, as the
  911. // OS will wake a process when it has TCP data available to read. (For this reason,
  912. // the actual long sleep issue is only with an idle tunnel; in this case the client
  913. // is responsible for sending SSH keep alives but a device sleep will delay the
  914. // golang SSH keep alive timer.)
  915. //
  916. // Idle tunnels will only read data when a SSH keep alive is sent. As a result,
  917. // the last-received-time scheme can undercount tunnel durations by up to
  918. // TUNNEL_SSH_KEEP_ALIVE_PERIOD_MAX for idle tunnels.
  919. tunnelDuration := tunnel.conn.GetLastActivityMonotime().Sub(tunnel.establishedTime)
  920. err := RecordTunnelStats(
  921. tunnel.serverContext.sessionId,
  922. tunnel.serverContext.tunnelNumber,
  923. tunnel.serverEntry.IpAddress,
  924. fmt.Sprintf("%d", tunnel.establishDuration),
  925. tunnelStartTime,
  926. fmt.Sprintf("%d", tunnelDuration),
  927. totalSent,
  928. totalReceived)
  929. if err != nil {
  930. NoticeAlert("RecordTunnelStats failed: %s", common.ContextError(err))
  931. }
  932. }
  933. // Final status request notes:
  934. //
  935. // It's highly desirable to send a final status request in order to report
  936. // domain bytes transferred stats as well as to report tunnel stats as
  937. // soon as possible. For this reason, we attempt untunneled requests when
  938. // the tunneled request isn't possible or has failed.
  939. //
  940. // In an orderly shutdown (err == nil), the Controller is stopping and
  941. // everything must be wrapped up quickly. Also, we still have a working
  942. // tunnel. So we first attempt a tunneled status request (with a short
  943. // timeout) and then attempt, synchronously -- otherwise the Contoller's
  944. // runWaitGroup.Wait() will return while a request is still in progress
  945. // -- untunneled requests (also with short timeouts). Note that in this
  946. // case the untunneled request will opt out of untunneledPendingConns so
  947. // that it's not inadvertently canceled by the Controller shutdown
  948. // sequence (see doUntunneledStatusRequest).
  949. //
  950. // If the tunnel has failed, the Controller may continue working. We want
  951. // to re-establish as soon as possible (so don't want to block on status
  952. // requests, even for a second). We may have a long time to attempt
  953. // untunneled requests in the background. And there is no tunnel through
  954. // which to attempt tunneled requests. So we spawn a goroutine to run the
  955. // untunneled requests, which are allowed a longer timeout. These requests
  956. // will be interrupted by the Controller's untunneledPendingConns.CloseAll()
  957. // in the case of a shutdown.
  958. if err == nil {
  959. NoticeInfo("shutdown operate tunnel")
  960. if !sendStats(tunnel) {
  961. sendUntunneledStats(tunnel, true)
  962. }
  963. } else {
  964. NoticeAlert("operate tunnel error for %s: %s", tunnel.serverEntry.IpAddress, err)
  965. go sendUntunneledStats(tunnel, false)
  966. tunnelOwner.SignalTunnelFailure(tunnel)
  967. }
  968. }
  969. // sendSshKeepAlive is a helper which sends a keepalive@openssh.com request
  970. // on the specified SSH connections and returns true of the request succeeds
  971. // within a specified timeout. If the request fails, the associated conn is
  972. // closed, which will terminate the associated tunnel.
  973. func sendSshKeepAlive(
  974. sshClient *ssh.Client, conn net.Conn, timeout time.Duration) error {
  975. errChannel := make(chan error, 2)
  976. if timeout > 0 {
  977. time.AfterFunc(timeout, func() {
  978. errChannel <- TimeoutError{}
  979. })
  980. }
  981. go func() {
  982. // Random padding to frustrate fingerprinting
  983. randomPadding, err := common.MakeSecureRandomPadding(0, TUNNEL_SSH_KEEP_ALIVE_PAYLOAD_MAX_BYTES)
  984. if err != nil {
  985. NoticeAlert("MakeSecureRandomPadding failed: %s", err)
  986. // Proceed without random padding
  987. randomPadding = make([]byte, 0)
  988. }
  989. // Note: reading a reply is important for last-received-time tunnel
  990. // duration calculation.
  991. _, _, err = sshClient.SendRequest("keepalive@openssh.com", true, randomPadding)
  992. errChannel <- err
  993. }()
  994. err := <-errChannel
  995. if err != nil {
  996. sshClient.Close()
  997. conn.Close()
  998. }
  999. return common.ContextError(err)
  1000. }
  1001. // sendStats is a helper for sending session stats to the server.
  1002. func sendStats(tunnel *Tunnel) bool {
  1003. // Tunnel does not have a serverContext when DisableApi is set
  1004. if tunnel.serverContext == nil {
  1005. return true
  1006. }
  1007. // Skip when tunnel is discarded
  1008. if tunnel.IsDiscarded() {
  1009. return true
  1010. }
  1011. err := tunnel.serverContext.DoStatusRequest(tunnel)
  1012. if err != nil {
  1013. NoticeAlert("DoStatusRequest failed for %s: %s", tunnel.serverEntry.IpAddress, err)
  1014. }
  1015. return err == nil
  1016. }
  1017. // sendUntunnelStats sends final status requests directly to Psiphon
  1018. // servers after the tunnel has already failed. This is an attempt
  1019. // to retain useful bytes transferred stats.
  1020. func sendUntunneledStats(tunnel *Tunnel, isShutdown bool) {
  1021. // Tunnel does not have a serverContext when DisableApi is set
  1022. if tunnel.serverContext == nil {
  1023. return
  1024. }
  1025. // Skip when tunnel is discarded
  1026. if tunnel.IsDiscarded() {
  1027. return
  1028. }
  1029. err := tunnel.serverContext.TryUntunneledStatusRequest(isShutdown)
  1030. if err != nil {
  1031. NoticeAlert("TryUntunneledStatusRequest failed for %s: %s", tunnel.serverEntry.IpAddress, err)
  1032. }
  1033. }
  1034. // sendClientVerification is a helper for sending a client verification request
  1035. // to the server.
  1036. func sendClientVerification(tunnel *Tunnel, clientVerificationPayload string) bool {
  1037. // Tunnel does not have a serverContext when DisableApi is set
  1038. if tunnel.serverContext == nil {
  1039. return true
  1040. }
  1041. // Skip when tunnel is discarded
  1042. if tunnel.IsDiscarded() {
  1043. return true
  1044. }
  1045. err := tunnel.serverContext.DoClientVerificationRequest(clientVerificationPayload, tunnel.serverEntry.IpAddress)
  1046. if err != nil {
  1047. NoticeAlert("DoClientVerificationRequest failed for %s: %s", tunnel.serverEntry.IpAddress, err)
  1048. }
  1049. return err == nil
  1050. }