PsiphonTunnel.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. //
  2. // PsiphonTunnel.h
  3. // PsiphonTunnel
  4. //
  5. /*
  6. * Copyright (c) 2016, Psiphon Inc.
  7. * All rights reserved.
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. #import <UIKit/UIKit.h>
  24. #import "Reachability.h"
  25. #import "JailbreakCheck.h"
  26. //! Project version number for PsiphonTunnel.
  27. FOUNDATION_EXPORT double PsiphonTunnelVersionNumber;
  28. //! Project version string for PsiphonTunnel.
  29. FOUNDATION_EXPORT const unsigned char PsiphonTunnelVersionString[];
  30. /*!
  31. The set of possible connection states the tunnel can be in.
  32. */
  33. typedef NS_ENUM(NSInteger, PsiphonConnectionState)
  34. {
  35. PsiphonConnectionStateDisconnected = 0,
  36. PsiphonConnectionStateConnecting,
  37. PsiphonConnectionStateConnected,
  38. PsiphonConnectionStateWaitingForNetwork
  39. };
  40. /*!
  41. @protocol PsiphonTunnelLoggerDelegate
  42. Used to communicate diagnostic logs to the application that is using the PsiphonTunnel framework.
  43. */
  44. @protocol PsiphonTunnelLoggerDelegate <NSObject>
  45. @optional
  46. /*!
  47. Gets runtime errors info that may be useful for debugging.
  48. @param message The diagnostic message string.
  49. @param timestamp RFC3339 encoded timestamp.
  50. */
  51. - (void)onDiagnosticMessage:(NSString * _Nonnull)message withTimestamp:(NSString * _Nonnull)timestamp;
  52. @end
  53. /*!
  54. @protocol TunneledAppDelegate
  55. Used to communicate with the application that is using the PsiphonTunnel framework,
  56. and retrieve config info from it.
  57. All delegate methods will be called on a single serial dispatch queue. They will be made asynchronously unless otherwise noted (specifically when calling getPsiphonConfig and getEmbeddedServerEntries).
  58. */
  59. @protocol TunneledAppDelegate <NSObject, PsiphonTunnelLoggerDelegate>
  60. //
  61. // Required delegate methods
  62. //
  63. @required
  64. /*!
  65. Called when tunnel is starting to get the library consumer's desired configuration.
  66. @code
  67. Required fields:
  68. - `PropagationChannelId`
  69. - `SponsorId`
  70. - Remote server list functionality is not strictly required, but absence greatly undermines circumvention ability.
  71. - `RemoteServerListURLs`
  72. - `RemoteServerListSignaturePublicKey`
  73. - Obfuscated server list functionality is also not strictly required, but aids circumvention ability.
  74. - `ObfuscatedServerListRootURLs`
  75. - `RemoteServerListSignaturePublicKey`: This is the same field as above. It is required if either `RemoteServerListURLs` or `ObfuscatedServerListRootURLs` is supplied.
  76. Optional fields (if you don't need them, don't set them):
  77. - `DataStoreDirectory`: If not set, the library will use a sane location. Override if the client wants to restrict where operational data is kept. If overridden, the directory must already exist and be writable.
  78. - `RemoteServerListDownloadFilename`: If not set, the library will use a sane location. Override if the client wants to restrict where operational data is kept.
  79. - `ObfuscatedServerListDownloadDirectory`: If not set, the library will use a sane location. Override if the client wants to restrict where operational data is kept. If overridden, the directory must already exist and be writable.
  80. - `UpstreamProxyUrl`
  81. - `EmitDiagnosticNotices`
  82. - `EgressRegion`
  83. - `EstablishTunnelTimeoutSeconds`
  84. - Only set if disabling timeouts (for very slow network connections):
  85. - `TunnelConnectTimeoutSeconds`
  86. - `TunnelPortForwardDialTimeoutSeconds`
  87. - `TunnelSshKeepAliveProbeTimeoutSeconds`
  88. - `TunnelSshKeepAlivePeriodicTimeoutSeconds`
  89. - `FetchRemoteServerListTimeoutSeconds`
  90. - `PsiphonApiServerTimeoutSeconds`
  91. - `FetchRoutesTimeoutSeconds`
  92. - `HttpProxyOriginServerTimeoutSeconds`
  93. - Fields which should only be set by Psiphon proper:
  94. - `TunnelWholeDevice`
  95. - `LocalHttpProxyPort`
  96. - `LocalSocksProxyPort`
  97. @endcode
  98. @note All other config fields must not be set.
  99. See the tunnel-core config code for details about the fields.
  100. https://github.com/Psiphon-Labs/psiphon-tunnel-core/blob/master/psiphon/config.go
  101. @return Either JSON NSString with config that should be used to run the Psiphon tunnel,
  102. or return already parsed JSON as NSDictionary,
  103. or nil on error.
  104. */
  105. - (id _Nullable)getPsiphonConfig;
  106. //
  107. // Optional delegate methods. Note that some of these are probably necessary for
  108. // for a functioning app to implement, for example `onConnected`.
  109. //
  110. @optional
  111. /*!
  112. Called when the tunnel is starting to get the initial server entries (typically embedded in the app) that will be used to bootstrap the Psiphon tunnel connection. This value is in a particular format and will be supplied by Psiphon Inc.
  113. If getEmbeddedServerEntriesPath is also implemented, it will take precedence over this method, unless getEmbeddedServerEntriesPath returns NULL or an empty string.
  114. @return Pre-existing server entries to use when attempting to connect to a server. Must return an empty string if there are no embedded server entries. Must return NULL if there is an error and the tunnel starting should abort.
  115. */
  116. - (NSString * _Nullable)getEmbeddedServerEntries;
  117. /*!
  118. Called when the tunnel is starting to get the initial server entries (typically embedded in the app) that will be used to bootstrap the Psiphon tunnel connection. This value is in a particular format and will be supplied by Psiphon Inc.
  119. If this method is implemented, it takes precedence over getEmbeddedServerEntries, and getEmbeddedServerEntries will not be called unless this method returns NULL or an empty string.
  120. @return Optional path where embedded server entries file is located. This file should be readable by the library.
  121. */
  122. - (NSString * _Nullable)getEmbeddedServerEntriesPath;
  123. /*!
  124. Called when the tunnel is in the process of connecting.
  125. */
  126. - (void)onConnecting;
  127. /*!
  128. Called when the tunnel has successfully connected.
  129. */
  130. - (void)onConnected;
  131. /*!
  132. Called when the tunnel notices that the device has no network connectivity and
  133. begins waiting to regain it. When connecitvity is regained, `onConnecting`
  134. will be called.
  135. */
  136. - (void)onStartedWaitingForNetworkConnectivity;
  137. /*!
  138. Called when the tunnel's connection state changes.
  139. Note that this will be called _in addition to, but before_ `onConnecting`, etc.
  140. Also note that this will not be called for the initial disconnected state
  141. (since it didn't change from anything).
  142. @param oldState The previous connection state.
  143. @param newState The new connection state.
  144. */
  145. - (void)onConnectionStateChangedFrom:(PsiphonConnectionState)oldState to:(PsiphonConnectionState)newState;
  146. /*!
  147. Called to indicate that tunnel-core is exiting imminently (usually due to
  148. a `stop()` call, but could be due to an unexpected error).
  149. onExiting may be called before or after `stop()` returns.
  150. */
  151. - (void)onExiting;
  152. /*!
  153. Called when the device's Internet connection state has changed.
  154. This may mean that it had connectivity and now doesn't, or went from Wi-Fi to
  155. WWAN or vice versa or VPN state changed
  156. */
  157. - (void)onInternetReachabilityChanged:(Reachability * _Nonnull)currentReachability;
  158. /*!
  159. Called when tunnel-core determines which server egress regions are available
  160. for use. This can be used for updating the UI which provides the options to
  161. the user.
  162. @param regions A string array containing the available egress region country codes.
  163. */
  164. - (void)onAvailableEgressRegions:(NSArray * _Nonnull)regions;
  165. /*!
  166. If the tunnel is started with a fixed SOCKS proxy port, and that port is
  167. already in use, this will be called.
  168. @param port The port number.
  169. */
  170. - (void)onSocksProxyPortInUse:(NSInteger)port;
  171. /*!
  172. If the tunnel is started with a fixed HTTP proxy port, and that port is
  173. already in use, this will be called.
  174. @param port The port number.
  175. */
  176. - (void)onHttpProxyPortInUse:(NSInteger)port;
  177. /*!
  178. Called when tunnel-core determines what port will be used for the local SOCKS proxy.
  179. @param port The port number.
  180. */
  181. - (void)onListeningSocksProxyPort:(NSInteger)port;
  182. /*!
  183. Called when tunnel-core determines what port will be used for the local HTTP proxy.
  184. @param port The port number.
  185. */
  186. - (void)onListeningHttpProxyPort:(NSInteger)port;
  187. /*!
  188. Called when a error occurs when trying to utilize a configured upstream proxy.
  189. @param message A message giving additional info about the error.
  190. */
  191. - (void)onUpstreamProxyError:(NSString * _Nonnull)message;
  192. /*!
  193. Called after the handshake with the Psiphon server, with the client region as determined by the server.
  194. @param region The country code of the client, as determined by the server.
  195. */
  196. - (void)onClientRegion:(NSString * _Nonnull)region;
  197. /*!
  198. Called to report that split tunnel is on for the given region.
  199. @param region The region split tunnel is on for.
  200. */
  201. - (void)onSplitTunnelRegion:(NSString * _Nonnull)region;
  202. /*!
  203. Called to indicate that an address has been classified as being within the
  204. split tunnel region and therefore is being access directly rather than tunneled.
  205. Note: `address` should remain private; this notice should be used for alerting
  206. users, not for diagnotics logs.
  207. @param address The IP or hostname that is not being tunneled.
  208. */
  209. - (void)onUntunneledAddress:(NSString * _Nonnull)address;
  210. /*!
  211. Called to report how many bytes have been transferred since the last time
  212. this function was called.
  213. By default onBytesTransferred is disabled. Enable it by setting
  214. EmitBytesTransferred to true in the Psiphon config.
  215. @param sent The number of bytes sent.
  216. @param received The number of bytes received.
  217. */
  218. - (void)onBytesTransferred:(int64_t)sent :(int64_t)received;
  219. /*!
  220. Called when tunnel-core discovers a home page associated with this client.
  221. If there are no home pages, it will not be called. May be called more than
  222. once, for multiple home pages.
  223. Note: This is probably only applicable to Psiphon Inc.'s apps.
  224. @param url The URL of the home page.
  225. */
  226. - (void)onHomepage:(NSString * _Nonnull)url;
  227. /*!
  228. Called when tunnel-core receives server timetamp in the handshake
  229. @param timestamp The server timestamp in RFC3339 format.
  230. */
  231. - (void)onServerTimestamp:(NSString * _Nonnull)timestamp;
  232. /*!
  233. Called when tunnel-core receives an array of active authorization IDs in the handshake
  234. @param authorizations A string array containing active authorization IDs.
  235. */
  236. - (void)onActiveAuthorizationIDs:(NSArray * _Nonnull)authorizations;
  237. /*!
  238. Called when tunnel-core receives traffic rate limit information in the handshake
  239. @param upstreamBytesPerSecond upstream rate limit; 0 for no limit
  240. @param downstreamBytesPerSecond downstream rate limit; 0 for no limit
  241. */
  242. - (void)onTrafficRateLimits:(int64_t)upstreamBytesPerSecond :(int64_t)downstreamBytesPerSecond;
  243. /*!
  244. Called when tunnel-core receives an alert from the server.
  245. @param reason The reason for the alert.
  246. @param subject Additional context or classification of the reason; blank for none.
  247. */
  248. - (void)onServerAlert:(NSString * _Nonnull)reason :(NSString * _Nonnull)subject;
  249. @end
  250. /*!
  251. The interface for managing the Psiphon tunnel -- set up, tear down, receive info about.
  252. */
  253. @interface PsiphonTunnel : NSObject
  254. /*!
  255. Returns an instance of PsiphonTunnel. This is either a new instance or the pre-existing singleton. If an instance already exists, it will be stopped when this function is called.
  256. @param tunneledAppDelegate The delegate implementation to use for callbacks.
  257. @return The PsiphonTunnel instance.
  258. */
  259. + (PsiphonTunnel * _Nonnull)newPsiphonTunnel:(id<TunneledAppDelegate> _Nonnull)tunneledAppDelegate;
  260. /*!
  261. Returns the default data root directory that is used by PsiphonTunnel if DataRootDirectory is not specified in the config returned by
  262. getPsiphonConfig.
  263. @param err Any error encountered while obtaining the default data root directory. If set, the return value should be ignored.
  264. @return The default data root directory used by PsiphonTunnel.
  265. */
  266. + (NSURL * _Nullable)defaultDataRootDirectoryWithError:(NSError * _Nullable * _Nonnull)err;
  267. /*!
  268. Returns the path where the homepage notices file will be created.
  269. @note This file will only be created if UseNoticeFiles is set in the config returned by `getPsiphonConfig`.
  270. @param dataRootDirectory the configured data root directory. If DataRootDirectory is not specified in the config returned by
  271. getPsiphonConfig, then use `defaultDataRootDirectory`.
  272. @return The file path at which the homepage file will be created.
  273. */
  274. + (NSURL * _Nullable)homepageFilePath:(NSURL * _Nonnull)dataRootDirectory;
  275. /*!
  276. Returns the path where the notices file will be created. When the file is rotated it will be moved to `oldNoticesFilePath`.
  277. @note This file will only be created if UseNoticeFiles is set in the config returned by `getPsiphonConfig`.
  278. @param dataRootDirectory the configured data root directory. If DataRootDirectory is not specified in the config returned by
  279. `getPsiphonConfig`, then use `defaultDataRootDirectory`.
  280. @return The file path at which the notices file will be created.
  281. */
  282. + (NSURL * _Nullable)noticesFilePath:(NSURL * _Nonnull)dataRootDirectory;
  283. /*!
  284. Returns the path where the rotated notices file will be created.
  285. @note This file will only be created if UseNoticeFiles is set in the config returned by `getPsiphonConfig`.
  286. @param dataRootDirectory the configured data root directory. If DataRootDirectory is not specified in the config returned by
  287. `getPsiphonConfig`, then use `defaultDataRootDirectory`.
  288. @return The file path at which the rotated notices file can be found once rotated.
  289. */
  290. + (NSURL * _Nullable)olderNoticesFilePath:(NSURL * _Nonnull)dataRootDirectory;
  291. /*!
  292. Start connecting the PsiphonTunnel. Returns before connection is complete -- delegate callbacks (such as `onConnected` and `onConnectionStateChanged`) are used to indicate progress and state.
  293. @param ifNeeded If TRUE, the tunnel will only be started if it's not already connected and healthy. If FALSE, the tunnel will be forced to stop and reconnect.
  294. @return TRUE if the connection start was successful, FALSE otherwise.
  295. */
  296. - (BOOL)start:(BOOL)ifNeeded;
  297. /*!
  298. Reconnect a previously started PsiphonTunnel with the specified config changes.
  299. reconnectWithConfig has no effect if there is no running PsiphonTunnel.
  300. */
  301. - (void)reconnectWithConfig:(NSString * _Nullable) newSponsorID :(NSArray<NSString *> *_Nullable)newAuthorizations;
  302. /*!
  303. Force stops the tunnel and reconnects with the current session ID.
  304. Retuns with FALSE immediately if no session ID has already been generated.
  305. @note On the first connection `start:` method should always be used to generate a
  306. session ID.
  307. @return TRUE if the connection start was successful, FALSE otherwise.
  308. */
  309. - (BOOL)stopAndReconnectWithCurrentSessionID;
  310. /*!
  311. Stop the tunnel (regardless of its current connection state).
  312. */
  313. - (void)stop;
  314. /*!
  315. Indicate if the device is sleeping. This logs a diagnostic message and forces hasNetworkConnectivity to false when sleeping.
  316. */
  317. - (void)setSleeping:(BOOL)isSleeping;
  318. /*!
  319. Returns the current tunnel connection state.
  320. @return The current connection state.
  321. */
  322. - (PsiphonConnectionState)getConnectionState;
  323. /*!
  324. Returns the current network reachability status, if Psiphon tunnel is not in a
  325. disconnected state.
  326. @return The current reachability status.
  327. */
  328. - (BOOL)getNetworkReachabilityStatus:(NetworkStatus * _Nonnull)status;
  329. /*!
  330. Provides the port number of the local SOCKS proxy. Only valid when currently connected (will return 0 otherwise).
  331. @return The current local SOCKS proxy port number.
  332. */
  333. - (NSInteger)getLocalSocksProxyPort;
  334. /*!
  335. Provides the port number of the local HTTP proxy. Only valid when currently connected (will return 0 otherwise).
  336. @return The current local HTTP proxy port number.
  337. */
  338. - (NSInteger)getLocalHttpProxyPort;
  339. /*!
  340. Only valid in whole device mode. Provides the MTU the packet tunnel requires the device to use.
  341. @return The MTU size.
  342. */
  343. - (long)getPacketTunnelMTU;
  344. /*!
  345. Only valid in whole device mode. Provides the DNS resolver IP address that is provided by the packet tunnel to the device.
  346. @return The IP address of the DNS resolver as a string.
  347. */
  348. - (NSString * _Nonnull)getPacketTunnelDNSResolverIPv4Address;
  349. /*!
  350. Only valid in whole device mode. Provides the DNS resolver IP address that is provided by the packet tunnel to the device.
  351. @return The IP address of the DNS resolver as a string.
  352. */
  353. - (NSString * _Nonnull)getPacketTunnelDNSResolverIPv6Address;
  354. /*!
  355. Provides the tunnel-core build info json as a string. See the tunnel-core build info code for details https://github.com/Psiphon-Labs/psiphon-tunnel-core/blob/master/psiphon/common/buildinfo.go.
  356. @return The build info json as a string.
  357. */
  358. + (NSString * _Nonnull)getBuildInfo;
  359. #pragma mark - Profiling utitlities
  360. /*!
  361. Writes Go runtime profile information to a set of files in the specifiec output directory.
  362. @param cpuSampleDurationSeconds determines how to long to wait and sample profiles that require active sampling. When set to 0, these profiles are skipped.
  363. @param blockSampleDurationSeconds determines how to long to wait and sample profiles that require active sampling. When set to 0, these profiles are skipped.
  364. */
  365. - (void)writeRuntimeProfilesTo:(NSString * _Nonnull)outputDirectory withCPUSampleDurationSeconds:(int)cpuSampleDurationSeconds withBlockSampleDurationSeconds:(int)blockSampleDurationSeconds;
  366. @end
  367. /*!
  368. @protocol PsiphonTunnelFeedbackDelegate
  369. Used to communicate the outcome of feedback upload operations to the application using the PsiphonTunnel framework.
  370. */
  371. @protocol PsiphonTunnelFeedbackDelegate <NSObject>
  372. /// Called once the feedback upload has completed.
  373. /// @param err If non-nil, then the upload failed.
  374. - (void)sendFeedbackCompleted:(NSError * _Nullable)err;
  375. @end
  376. /*!
  377. The interface for managing the Psiphon tunnel feedback upload operations.
  378. @warning Should not be used in the same process as PsiphonTunnel.
  379. @warning Only a single instance of PsiphonTunnelFeedback should be used at a time. Using multiple instances in parallel, or
  380. concurrently, will result in undefined behavior.
  381. */
  382. @interface PsiphonTunnelFeedback : NSObject
  383. /*!
  384. Upload a feedback package to Psiphon Inc. The app collects feedback and diagnostics information in a particular format and then calls this
  385. function to upload it for later investigation. This call is asynchronous and returns before the upload completes. The operation has
  386. completed when `sendFeedbackCompleted:` is called on the provided `PsiphonTunnelFeedbackDelegate`.
  387. @param feedbackJson The feedback data to upload.
  388. @param feedbackConfigJson The feedback compatible config. Must be an NSDictionary or NSString. Config must be provided by
  389. Psiphon Inc.
  390. @param uploadPath The path at which to upload the diagnostic data. Must be provided by Psiphon Inc.
  391. @param loggerDelegate Optional delegate which will be called to log informational notices, including warnings. Stored as a weak
  392. reference; the caller is responsible for holding a strong reference.
  393. @param feedbackDelegate Delegate which `sendFeedbackCompleted(error)` is called on once when the operation completes; if
  394. error is non-nil, then the operation failed. Stored as a weak reference; the caller is responsible for holding a strong reference.
  395. @warning Only one active upload is supported at a time. An ongoing upload will be cancelled if this function is called again before it
  396. completes.
  397. @warning An ongoing feedback upload started with `startSendFeedback:` should be stopped with `stopSendFeedback` before the
  398. process exits. This ensures that any underlying resources are cleaned up; failing to do so may result in data store corruption or other
  399. undefined behavior.
  400. */
  401. - (void)startSendFeedback:(NSString * _Nonnull)feedbackJson
  402. feedbackConfigJson:(id _Nonnull)feedbackConfigJson
  403. uploadPath:(NSString * _Nonnull)uploadPath
  404. loggerDelegate:(id<PsiphonTunnelLoggerDelegate> _Nullable)loggerDelegate
  405. feedbackDelegate:(id<PsiphonTunnelFeedbackDelegate> _Nonnull)feedbackDelegate;
  406. /*!
  407. Interrupt an in-progress feedback upload operation started with `startSendFeedback:`. This call is synchronous and returns once the
  408. upload has been cancelled.
  409. */
  410. - (void)stopSendFeedback;
  411. @end