config.go 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106
  1. /*
  2. * Copyright (c) 2016, 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 server
  20. import (
  21. "crypto/rand"
  22. "crypto/rsa"
  23. "crypto/x509"
  24. "encoding/base64"
  25. "encoding/hex"
  26. "encoding/json"
  27. "encoding/pem"
  28. "fmt"
  29. "net"
  30. "os"
  31. "strconv"
  32. "strings"
  33. "sync/atomic"
  34. "time"
  35. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  36. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/accesscontrol"
  37. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/ssh"
  38. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  39. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/osl"
  40. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
  41. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/tactics"
  42. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/values"
  43. "golang.org/x/crypto/nacl/box"
  44. )
  45. const (
  46. SERVER_CONFIG_FILENAME = "psiphond.config"
  47. SERVER_TRAFFIC_RULES_CONFIG_FILENAME = "psiphond-traffic-rules.config"
  48. SERVER_OSL_CONFIG_FILENAME = "psiphond-osl.config"
  49. SERVER_TACTICS_CONFIG_FILENAME = "psiphond-tactics.config"
  50. SERVER_ENTRY_FILENAME = "server-entry.dat"
  51. DEFAULT_SERVER_IP_ADDRESS = "127.0.0.1"
  52. WEB_SERVER_SECRET_BYTE_LENGTH = 32
  53. DISCOVERY_VALUE_KEY_BYTE_LENGTH = 32
  54. SSH_USERNAME_SUFFIX_BYTE_LENGTH = 8
  55. SSH_PASSWORD_BYTE_LENGTH = 32
  56. SSH_RSA_HOST_KEY_BITS = 2048
  57. SSH_OBFUSCATED_KEY_BYTE_LENGTH = 32
  58. PEAK_UPSTREAM_FAILURE_RATE_MINIMUM_SAMPLE_SIZE = 10
  59. PERIODIC_GARBAGE_COLLECTION = 120 * time.Second
  60. STOP_ESTABLISH_TUNNELS_ESTABLISHED_CLIENT_THRESHOLD = 20
  61. DEFAULT_LOG_FILE_REOPEN_RETRIES = 25
  62. )
  63. // Config specifies the configuration and behavior of a Psiphon
  64. // server.
  65. type Config struct {
  66. // LogLevel specifies the log level. Valid values are:
  67. // panic, fatal, error, warn, info, debug
  68. LogLevel string
  69. // LogFilename specifies the path of the file to log
  70. // to. When blank, logs are written to stderr.
  71. LogFilename string
  72. // LogFileReopenRetries specifies how many retries, each with a 1ms delay,
  73. // will be attempted after reopening a rotated log file fails. Retries
  74. // mitigate any race conditions between writes/reopens and file operations
  75. // performed by external log managers, such as logrotate.
  76. //
  77. // When omitted, DEFAULT_LOG_FILE_REOPEN_RETRIES is used.
  78. LogFileReopenRetries *int
  79. // LogFileCreateMode specifies that the Psiphon server should create a new
  80. // log file when one is not found, such as after rotation with logrotate
  81. // configured with nocreate. The value is the os.FileMode value to use when
  82. // creating the file.
  83. //
  84. // When omitted, the Psiphon server does not create log files.
  85. LogFileCreateMode *int
  86. // SkipPanickingLogWriter disables panicking when
  87. // unable to write any logs.
  88. SkipPanickingLogWriter bool
  89. // DiscoveryValueHMACKey is the network-wide secret value
  90. // used to determine a unique discovery strategy.
  91. DiscoveryValueHMACKey string
  92. // GeoIPDatabaseFilenames are paths of GeoIP2/GeoLite2
  93. // MaxMind database files. When empty, no GeoIP lookups are
  94. // performed. Each file is queried, in order, for the
  95. // logged fields: country code, city, and ISP. Multiple
  96. // file support accommodates the MaxMind distribution where
  97. // ISP data in a separate file.
  98. GeoIPDatabaseFilenames []string
  99. // PsinetDatabaseFilename is the path of the file containing
  100. // psinet.Database data.
  101. PsinetDatabaseFilename string
  102. // HostID is the ID of the server host; this is used for API
  103. // event logging.
  104. HostID string
  105. // ServerIPAddress is the public IP address of the server.
  106. ServerIPAddress string
  107. // WebServerPort is the listening port of the web server.
  108. // When <= 0, no web server component is run.
  109. WebServerPort int
  110. // WebServerSecret is the unique secret value that the client
  111. // must supply to make requests to the web server.
  112. WebServerSecret string
  113. // WebServerCertificate is the certificate the client uses to
  114. // authenticate the web server.
  115. WebServerCertificate string
  116. // WebServerPrivateKey is the private key the web server uses to
  117. // authenticate itself to clients.
  118. WebServerPrivateKey string
  119. // WebServerPortForwardAddress specifies the expected network
  120. // address ("<host>:<port>") specified in a client's port forward
  121. // HostToConnect and PortToConnect when the client is making a
  122. // tunneled connection to the web server. This address is always
  123. // exempted from validation against SSH_DISALLOWED_PORT_FORWARD_HOSTS
  124. // and AllowTCPPorts.
  125. WebServerPortForwardAddress string
  126. // WebServerPortForwardRedirectAddress specifies an alternate
  127. // destination address to be substituted and dialed instead of
  128. // the original destination when the port forward destination is
  129. // WebServerPortForwardAddress.
  130. WebServerPortForwardRedirectAddress string
  131. // TunnelProtocolPorts specifies which tunnel protocols to run
  132. // and which ports to listen on for each protocol. Valid tunnel
  133. // protocols include:
  134. // "SSH", "OSSH", "UNFRONTED-MEEK-OSSH", "UNFRONTED-MEEK-HTTPS-OSSH",
  135. // "UNFRONTED-MEEK-SESSION-TICKET-OSSH", "FRONTED-MEEK-OSSH",
  136. // "FRONTED-MEEK-QUIC-OSSH", "FRONTED-MEEK-HTTP-OSSH", "QUIC-OSSH",
  137. // "TAPDANCE-OSSH", abd "CONJURE-OSSH".
  138. TunnelProtocolPorts map[string]int
  139. // TunnelProtocolPassthroughAddresses specifies passthrough addresses to be
  140. // used for tunnel protocols configured in TunnelProtocolPorts. Passthrough
  141. // is a probing defense which relays all network traffic between a client and
  142. // the passthrough target when the client fails anti-probing tests.
  143. //
  144. // TunnelProtocolPassthroughAddresses is supported for:
  145. // "UNFRONTED-MEEK-HTTPS-OSSH", "UNFRONTED-MEEK-SESSION-TICKET-OSSH".
  146. TunnelProtocolPassthroughAddresses map[string]string
  147. // LegacyPassthrough indicates whether to expect legacy passthrough messages
  148. // from clients attempting to connect. This should be set for existing/legacy
  149. // passthrough servers only.
  150. LegacyPassthrough bool
  151. // EnableGQUIC indicates whether to enable legacy gQUIC QUIC-OSSH
  152. // versions, for backwards compatibility with all versions used by older
  153. // clients. Enabling gQUIC degrades the anti-probing stance of QUIC-OSSH,
  154. // as the legacy gQUIC stack will respond to probing packets.
  155. EnableGQUIC bool
  156. // SSHPrivateKey is the SSH host key. The same key is used for
  157. // all protocols, run by this server instance, which use SSH.
  158. SSHPrivateKey string
  159. // SSHServerVersion is the server version presented in the
  160. // identification string. The same value is used for all
  161. // protocols, run by this server instance, which use SSH.
  162. SSHServerVersion string
  163. // SSHUserName is the SSH user name to be presented by the
  164. // the tunnel-core client. The same value is used for all
  165. // protocols, run by this server instance, which use SSH.
  166. SSHUserName string
  167. // SSHPassword is the SSH password to be presented by the
  168. // the tunnel-core client. The same value is used for all
  169. // protocols, run by this server instance, which use SSH.
  170. SSHPassword string
  171. // SSHBeginHandshakeTimeoutMilliseconds specifies the timeout
  172. // for clients queueing to begin an SSH handshake. The default
  173. // is SSH_BEGIN_HANDSHAKE_TIMEOUT.
  174. SSHBeginHandshakeTimeoutMilliseconds *int
  175. // SSHHandshakeTimeoutMilliseconds specifies the timeout
  176. // before which a client must complete its handshake. The default
  177. // is SSH_HANDSHAKE_TIMEOUT.
  178. SSHHandshakeTimeoutMilliseconds *int
  179. // ObfuscatedSSHKey is the secret key for use in the Obfuscated
  180. // SSH protocol. The same secret key is used for all protocols,
  181. // run by this server instance, which use Obfuscated SSH.
  182. ObfuscatedSSHKey string
  183. // MeekCookieEncryptionPrivateKey is the NaCl private key used
  184. // to decrypt meek cookie payload sent from clients. The same
  185. // key is used for all meek protocols run by this server instance.
  186. MeekCookieEncryptionPrivateKey string
  187. // MeekObfuscatedKey is the secret key used for obfuscating
  188. // meek cookies sent from clients. The same key is used for all
  189. // meek protocols run by this server instance.
  190. MeekObfuscatedKey string
  191. // MeekProhibitedHeaders is a list of HTTP headers to check for
  192. // in client requests. If one of these headers is found, the
  193. // request fails. This is used to defend against abuse.
  194. MeekProhibitedHeaders []string
  195. // MeekProxyForwardedForHeaders is a list of HTTP headers which
  196. // may be added by downstream HTTP proxies or CDNs in front
  197. // of clients. These headers supply the original client IP
  198. // address, which is geolocated for stats purposes. Headers
  199. // include, for example, X-Forwarded-For. The header's value
  200. // is assumed to be a comma delimted list of IP addresses where
  201. // the client IP is the first IP address in the list. Meek protocols
  202. // look for these headers and use the client IP address from
  203. // the header if any one is present and the value is a valid
  204. // IP address; otherwise the direct connection remote address is
  205. // used as the client IP.
  206. MeekProxyForwardedForHeaders []string
  207. // MeekTurnAroundTimeoutMilliseconds specifies the amount of time meek will
  208. // wait for downstream bytes before responding to a request. The default is
  209. // MEEK_DEFAULT_TURN_AROUND_TIMEOUT.
  210. MeekTurnAroundTimeoutMilliseconds *int
  211. // MeekExtendedTurnAroundTimeoutMilliseconds specifies the extended amount of
  212. // time meek will wait for downstream bytes, as long as bytes arrive every
  213. // MeekTurnAroundTimeoutMilliseconds, before responding to a request. The
  214. // default is MEEK_DEFAULT_EXTENDED_TURN_AROUND_TIMEOUT.
  215. MeekExtendedTurnAroundTimeoutMilliseconds *int
  216. // MeekSkipExtendedTurnAroundThresholdBytes specifies when to skip the
  217. // extended turn around. When the number of bytes received in the client
  218. // request meets the threshold, optimize for upstream flows with quicker
  219. // round trip turn arounds.
  220. MeekSkipExtendedTurnAroundThresholdBytes *int
  221. // MeekMaxSessionStalenessMilliseconds specifies the TTL for meek sessions.
  222. // The default is MEEK_DEFAULT_MAX_SESSION_STALENESS.
  223. MeekMaxSessionStalenessMilliseconds *int
  224. // MeekHTTPClientIOTimeoutMilliseconds specifies meek HTTP server I/O
  225. // timeouts. The default is MEEK_DEFAULT_HTTP_CLIENT_IO_TIMEOUT.
  226. MeekHTTPClientIOTimeoutMilliseconds *int
  227. // MeekCachedResponseBufferSize is the size of a private,
  228. // fixed-size buffer allocated for every meek client. The buffer
  229. // is used to cache response payload, allowing the client to retry
  230. // fetching when a network connection is interrupted. This retry
  231. // makes the OSSH tunnel within meek resilient to interruptions
  232. // at the HTTP TCP layer.
  233. // Larger buffers increase resiliency to interruption, but consume
  234. // more memory as buffers as never freed. The maximum size of a
  235. // response payload is a function of client activity, network
  236. // throughput and throttling.
  237. // A default of 64K is used when MeekCachedResponseBufferSize is 0.
  238. MeekCachedResponseBufferSize int
  239. // MeekCachedResponsePoolBufferSize is the size of a fixed-size,
  240. // shared buffer used to temporarily extend a private buffer when
  241. // MeekCachedResponseBufferSize is insufficient. Shared buffers
  242. // allow some clients to successfully retry longer response payloads
  243. // without allocating large buffers for all clients.
  244. // A default of 64K is used when MeekCachedResponsePoolBufferSize
  245. // is 0.
  246. MeekCachedResponsePoolBufferSize int
  247. // MeekCachedResponsePoolBufferCount is the number of shared
  248. // buffers. Shared buffers are allocated on first use and remain
  249. // allocated, so shared buffer count * size is roughly the memory
  250. // overhead of this facility.
  251. // A default of 2048 is used when MeekCachedResponsePoolBufferCount
  252. // is 0.
  253. MeekCachedResponsePoolBufferCount int
  254. // UDPInterceptUdpgwServerAddress specifies the network address of
  255. // a udpgw server which clients may be port forwarding to. When
  256. // specified, these TCP port forwards are intercepted and handled
  257. // directly by this server, which parses the SSH channel using the
  258. // udpgw protocol. Handling includes udpgw transparent DNS: tunneled
  259. // UDP DNS packets are rerouted to the host's DNS server.
  260. //
  261. // The intercept is applied before the port forward destination is
  262. // validated against SSH_DISALLOWED_PORT_FORWARD_HOSTS and
  263. // AllowTCPPorts. So the intercept address may be any otherwise
  264. // prohibited destination.
  265. UDPInterceptUdpgwServerAddress string
  266. // DNSResolverIPAddress specifies the IP address of a DNS server
  267. // to be used when "/etc/resolv.conf" doesn't exist or fails to
  268. // parse. When blank, "/etc/resolv.conf" must contain a usable
  269. // "nameserver" entry.
  270. DNSResolverIPAddress string
  271. // LoadMonitorPeriodSeconds indicates how frequently to log server
  272. // load information (number of connected clients per tunnel protocol,
  273. // number of running goroutines, amount of memory allocated, etc.)
  274. // The default, 0, disables load logging.
  275. LoadMonitorPeriodSeconds int
  276. // PeakUpstreamFailureRateMinimumSampleSize specifies the minimum number
  277. // of samples (e.g., upstream port forward attempts) that are required
  278. // before taking a failure rate snapshot which may be recorded as
  279. // peak_dns_failure_rate/peak_tcp_port_forward_failure_rate. The default
  280. // is PEAK_UPSTREAM_FAILURE_RATE_SAMPLE_SIZE.
  281. PeakUpstreamFailureRateMinimumSampleSize *int
  282. // ProcessProfileOutputDirectory is the path of a directory to which
  283. // process profiles will be written when signaled with SIGUSR2. The
  284. // files are overwritten on each invocation. When set to the default
  285. // value, blank, no profiles are written on SIGUSR2. Profiles include
  286. // the default profiles here: https://golang.org/pkg/runtime/pprof/#Profile.
  287. ProcessProfileOutputDirectory string
  288. // ProcessBlockProfileDurationSeconds specifies the sample duration for
  289. // "block" profiling. For the default, 0, no "block" profile is taken.
  290. ProcessBlockProfileDurationSeconds int
  291. // ProcessCPUProfileDurationSeconds specifies the sample duration for
  292. // CPU profiling. For the default, 0, no CPU profile is taken.
  293. ProcessCPUProfileDurationSeconds int
  294. // TrafficRulesFilename is the path of a file containing a JSON-encoded
  295. // TrafficRulesSet, the traffic rules to apply to Psiphon client tunnels.
  296. TrafficRulesFilename string
  297. // OSLConfigFilename is the path of a file containing a JSON-encoded
  298. // OSL Config, the OSL schemes to apply to Psiphon client tunnels.
  299. OSLConfigFilename string
  300. // RunPacketTunnel specifies whether to run a packet tunnel.
  301. RunPacketTunnel bool
  302. // PacketTunnelEgressInterface specifies tun.ServerConfig.EgressInterface.
  303. PacketTunnelEgressInterface string
  304. // PacketTunnelEnableDNSFlowTracking sets
  305. // tun.ServerConfig.EnableDNSFlowTracking.
  306. PacketTunnelEnableDNSFlowTracking bool
  307. // PacketTunnelDownstreamPacketQueueSize specifies
  308. // tun.ServerConfig.DownStreamPacketQueueSize.
  309. PacketTunnelDownstreamPacketQueueSize int
  310. // PacketTunnelSessionIdleExpirySeconds specifies
  311. // tun.ServerConfig.SessionIdleExpirySeconds.
  312. PacketTunnelSessionIdleExpirySeconds int
  313. // PacketTunnelSudoNetworkConfigCommands sets
  314. // tun.ServerConfig.SudoNetworkConfigCommands.
  315. PacketTunnelSudoNetworkConfigCommands bool
  316. // RunPacketManipulator specifies whether to run a packet manipulator.
  317. RunPacketManipulator bool
  318. // MaxConcurrentSSHHandshakes specifies a limit on the number of concurrent
  319. // SSH handshake negotiations. This is set to mitigate spikes in memory
  320. // allocations and CPU usage associated with SSH handshakes when many clients
  321. // attempt to connect concurrently. When a maximum limit is specified and
  322. // reached, additional clients that establish TCP or meek connections will
  323. // be disconnected after a short wait for the number of concurrent handshakes
  324. // to drop below the limit.
  325. // The default, 0 is no limit.
  326. MaxConcurrentSSHHandshakes int
  327. // PeriodicGarbageCollectionSeconds turns on periodic calls to
  328. // debug.FreeOSMemory, every specified number of seconds, to force garbage
  329. // collection and memory scavenging. Specify 0 to disable. The default is
  330. // PERIODIC_GARBAGE_COLLECTION.
  331. PeriodicGarbageCollectionSeconds *int
  332. // StopEstablishTunnelsEstablishedClientThreshold sets the established client
  333. // threshold for dumping profiles when SIGTSTP is signaled. When there are
  334. // less than or equal to the threshold number of established clients,
  335. // profiles are dumped to aid investigating unusual load limited states that
  336. // occur when few clients are connected and load should be relatively low. A
  337. // profile dump is attempted at most once per process lifetime, the first
  338. // time the threshold is met. Disabled when < 0.
  339. StopEstablishTunnelsEstablishedClientThreshold *int
  340. // AccessControlVerificationKeyRing is the access control authorization
  341. // verification key ring used to verify signed authorizations presented
  342. // by clients. Verified, active (unexpired) access control types will be
  343. // available for matching in the TrafficRulesFilter for the client via
  344. // AuthorizedAccessTypes. All other authorizations are ignored.
  345. AccessControlVerificationKeyRing accesscontrol.VerificationKeyRing
  346. // TacticsConfigFilename is the path of a file containing a JSON-encoded
  347. // tactics server configuration.
  348. TacticsConfigFilename string
  349. // BlocklistFilename is the path of a file containing a CSV-encoded
  350. // blocklist configuration. See NewBlocklist for more file format
  351. // documentation.
  352. BlocklistFilename string
  353. // BlocklistActive indicates whether to actively prevent blocklist hits in
  354. // addition to logging events.
  355. BlocklistActive bool
  356. // AllowBogons disables port forward bogon checks. This should be used only
  357. // for testing.
  358. AllowBogons bool
  359. // OwnEncodedServerEntries is a list of the server's own encoded server
  360. // entries, idenfified by server entry tag. These values are used in the
  361. // handshake API to update clients that don't yet have a signed copy of these
  362. // server entries.
  363. //
  364. // For purposes of compartmentalization, each server receives only its own
  365. // server entries here; and, besides the discovery server entries, in
  366. // psinet.Database, necessary for the discovery feature, no other server
  367. // entries are stored on a Psiphon server.
  368. OwnEncodedServerEntries map[string]string
  369. sshBeginHandshakeTimeout time.Duration
  370. sshHandshakeTimeout time.Duration
  371. peakUpstreamFailureRateMinimumSampleSize int
  372. periodicGarbageCollection time.Duration
  373. stopEstablishTunnelsEstablishedClientThreshold int
  374. dumpProfilesOnStopEstablishTunnelsDone int32
  375. frontingProviderID string
  376. runningProtocols []string
  377. }
  378. // GetLogFileReopenConfig gets the reopen retries, and create/mode inputs for
  379. // rotate.NewRotatableFileWriter, which is used when writing to log files.
  380. //
  381. // By default, we expect the log files to be managed by logrotate, with
  382. // logrotate configured to re-create the next log file after rotation. As
  383. // described in the documentation for rotate.NewRotatableFileWriter, and as
  384. // observed in production, we occasionally need retries when attempting to
  385. // reopen the log file post-rotation; and we avoid conflicts, and spurious
  386. // re-rotations, by disabling file create in rotate.NewRotatableFileWriter. In
  387. // large scale production, incidents requiring retry are very rare, so the
  388. // retry delay is not expected to have a significant impact on performance.
  389. //
  390. // The defaults may be overriden in the Config.
  391. func (config *Config) GetLogFileReopenConfig() (int, bool, os.FileMode) {
  392. retries := DEFAULT_LOG_FILE_REOPEN_RETRIES
  393. if config.LogFileReopenRetries != nil {
  394. retries = *config.LogFileReopenRetries
  395. }
  396. create := false
  397. mode := os.FileMode(0)
  398. if config.LogFileCreateMode != nil {
  399. create = true
  400. mode = os.FileMode(*config.LogFileCreateMode)
  401. }
  402. return retries, create, mode
  403. }
  404. // RunWebServer indicates whether to run a web server component.
  405. func (config *Config) RunWebServer() bool {
  406. return config.WebServerPort > 0
  407. }
  408. // RunLoadMonitor indicates whether to monitor and log server load.
  409. func (config *Config) RunLoadMonitor() bool {
  410. return config.LoadMonitorPeriodSeconds > 0
  411. }
  412. // RunPeriodicGarbageCollection indicates whether to run periodic garbage collection.
  413. func (config *Config) RunPeriodicGarbageCollection() bool {
  414. return config.periodicGarbageCollection > 0
  415. }
  416. // DumpProfilesOnStopEstablishTunnels indicates whether dump profiles due to
  417. // an unexpectedly low number of established clients during high load.
  418. func (config *Config) DumpProfilesOnStopEstablishTunnels(establishedClientsCount int) bool {
  419. if config.stopEstablishTunnelsEstablishedClientThreshold < 0 {
  420. return false
  421. }
  422. if atomic.LoadInt32(&config.dumpProfilesOnStopEstablishTunnelsDone) != 0 {
  423. return false
  424. }
  425. dump := (establishedClientsCount <= config.stopEstablishTunnelsEstablishedClientThreshold)
  426. atomic.StoreInt32(&config.dumpProfilesOnStopEstablishTunnelsDone, 1)
  427. return dump
  428. }
  429. // GetOwnEncodedServerEntry returns one of the server's own server entries, as
  430. // identified by the server entry tag.
  431. func (config *Config) GetOwnEncodedServerEntry(serverEntryTag string) (string, bool) {
  432. serverEntry, ok := config.OwnEncodedServerEntries[serverEntryTag]
  433. return serverEntry, ok
  434. }
  435. // GetFrontingProviderID returns the fronting provider ID associated with the
  436. // server's fronted protocol(s).
  437. func (config *Config) GetFrontingProviderID() string {
  438. return config.frontingProviderID
  439. }
  440. // GetRunningProtocols returns the list of protcols this server is running.
  441. // The caller must not mutate the return value.
  442. func (config *Config) GetRunningProtocols() []string {
  443. return config.runningProtocols
  444. }
  445. // LoadConfig loads and validates a JSON encoded server config.
  446. func LoadConfig(configJSON []byte) (*Config, error) {
  447. var config Config
  448. err := json.Unmarshal(configJSON, &config)
  449. if err != nil {
  450. return nil, errors.Trace(err)
  451. }
  452. if config.ServerIPAddress == "" {
  453. return nil, errors.TraceNew("ServerIPAddress is required")
  454. }
  455. if config.WebServerPort > 0 && (config.WebServerSecret == "" || config.WebServerCertificate == "" ||
  456. config.WebServerPrivateKey == "") {
  457. return nil, errors.TraceNew(
  458. "Web server requires WebServerSecret, WebServerCertificate, WebServerPrivateKey")
  459. }
  460. if config.WebServerPortForwardAddress != "" {
  461. if err := validateNetworkAddress(config.WebServerPortForwardAddress, false); err != nil {
  462. return nil, errors.TraceNew("WebServerPortForwardAddress is invalid")
  463. }
  464. }
  465. if config.WebServerPortForwardRedirectAddress != "" {
  466. if config.WebServerPortForwardAddress == "" {
  467. return nil, errors.TraceNew(
  468. "WebServerPortForwardRedirectAddress requires WebServerPortForwardAddress")
  469. }
  470. if err := validateNetworkAddress(config.WebServerPortForwardRedirectAddress, false); err != nil {
  471. return nil, errors.TraceNew("WebServerPortForwardRedirectAddress is invalid")
  472. }
  473. }
  474. for tunnelProtocol, _ := range config.TunnelProtocolPorts {
  475. if !common.Contains(protocol.SupportedTunnelProtocols, tunnelProtocol) {
  476. return nil, errors.Tracef("Unsupported tunnel protocol: %s", tunnelProtocol)
  477. }
  478. if protocol.TunnelProtocolUsesSSH(tunnelProtocol) ||
  479. protocol.TunnelProtocolUsesObfuscatedSSH(tunnelProtocol) {
  480. if config.SSHPrivateKey == "" || config.SSHServerVersion == "" ||
  481. config.SSHUserName == "" || config.SSHPassword == "" {
  482. return nil, errors.Tracef(
  483. "Tunnel protocol %s requires SSHPrivateKey, SSHServerVersion, SSHUserName, SSHPassword",
  484. tunnelProtocol)
  485. }
  486. }
  487. if protocol.TunnelProtocolUsesObfuscatedSSH(tunnelProtocol) {
  488. if config.ObfuscatedSSHKey == "" {
  489. return nil, errors.Tracef(
  490. "Tunnel protocol %s requires ObfuscatedSSHKey",
  491. tunnelProtocol)
  492. }
  493. }
  494. if protocol.TunnelProtocolUsesMeekHTTP(tunnelProtocol) ||
  495. protocol.TunnelProtocolUsesMeekHTTPS(tunnelProtocol) {
  496. if config.MeekCookieEncryptionPrivateKey == "" || config.MeekObfuscatedKey == "" {
  497. return nil, errors.Tracef(
  498. "Tunnel protocol %s requires MeekCookieEncryptionPrivateKey, MeekObfuscatedKey",
  499. tunnelProtocol)
  500. }
  501. }
  502. }
  503. for tunnelProtocol, address := range config.TunnelProtocolPassthroughAddresses {
  504. if !protocol.TunnelProtocolSupportsPassthrough(tunnelProtocol) {
  505. return nil, errors.Tracef("Passthrough unsupported tunnel protocol: %s", tunnelProtocol)
  506. }
  507. if _, _, err := net.SplitHostPort(address); err != nil {
  508. if err != nil {
  509. return nil, errors.Tracef(
  510. "Tunnel protocol %s passthrough address %s invalid: %s",
  511. tunnelProtocol, address, err)
  512. }
  513. }
  514. }
  515. config.sshBeginHandshakeTimeout = SSH_BEGIN_HANDSHAKE_TIMEOUT
  516. if config.SSHBeginHandshakeTimeoutMilliseconds != nil {
  517. config.sshBeginHandshakeTimeout = time.Duration(*config.SSHBeginHandshakeTimeoutMilliseconds) * time.Millisecond
  518. }
  519. config.sshHandshakeTimeout = SSH_HANDSHAKE_TIMEOUT
  520. if config.SSHHandshakeTimeoutMilliseconds != nil {
  521. config.sshHandshakeTimeout = time.Duration(*config.SSHHandshakeTimeoutMilliseconds) * time.Millisecond
  522. }
  523. if config.ObfuscatedSSHKey != "" {
  524. seed, err := protocol.DeriveSSHServerVersionPRNGSeed(config.ObfuscatedSSHKey)
  525. if err != nil {
  526. return nil, errors.Tracef(
  527. "DeriveSSHServerVersionPRNGSeed failed: %s", err)
  528. }
  529. serverVersion := values.GetSSHServerVersion(seed)
  530. if serverVersion != "" {
  531. config.SSHServerVersion = serverVersion
  532. }
  533. }
  534. if config.UDPInterceptUdpgwServerAddress != "" {
  535. if err := validateNetworkAddress(config.UDPInterceptUdpgwServerAddress, true); err != nil {
  536. return nil, errors.Tracef("UDPInterceptUdpgwServerAddress is invalid: %s", err)
  537. }
  538. }
  539. if config.DNSResolverIPAddress != "" {
  540. if net.ParseIP(config.DNSResolverIPAddress) == nil {
  541. return nil, errors.Tracef("DNSResolverIPAddress is invalid")
  542. }
  543. }
  544. config.peakUpstreamFailureRateMinimumSampleSize = PEAK_UPSTREAM_FAILURE_RATE_MINIMUM_SAMPLE_SIZE
  545. if config.PeakUpstreamFailureRateMinimumSampleSize != nil {
  546. config.peakUpstreamFailureRateMinimumSampleSize = *config.PeakUpstreamFailureRateMinimumSampleSize
  547. }
  548. config.periodicGarbageCollection = PERIODIC_GARBAGE_COLLECTION
  549. if config.PeriodicGarbageCollectionSeconds != nil {
  550. config.periodicGarbageCollection = time.Duration(*config.PeriodicGarbageCollectionSeconds) * time.Second
  551. }
  552. config.stopEstablishTunnelsEstablishedClientThreshold = STOP_ESTABLISH_TUNNELS_ESTABLISHED_CLIENT_THRESHOLD
  553. if config.StopEstablishTunnelsEstablishedClientThreshold != nil {
  554. config.stopEstablishTunnelsEstablishedClientThreshold = *config.StopEstablishTunnelsEstablishedClientThreshold
  555. }
  556. err = accesscontrol.ValidateVerificationKeyRing(&config.AccessControlVerificationKeyRing)
  557. if err != nil {
  558. return nil, errors.Tracef(
  559. "AccessControlVerificationKeyRing is invalid: %s", err)
  560. }
  561. // Limitation: the following is a shortcut which extracts the server's
  562. // fronting provider ID from the server's OwnEncodedServerEntries. This logic
  563. // assumes a server has only one fronting provider. In principle, it's
  564. // possible for server with multiple server entries to run multiple fronted
  565. // protocols, each with a different fronting provider ID.
  566. //
  567. // TODO: add an explicit parameter mapping tunnel protocol ports to fronting
  568. // provider IDs.
  569. for _, encodedServerEntry := range config.OwnEncodedServerEntries {
  570. serverEntry, err := protocol.DecodeServerEntry(encodedServerEntry, "", "")
  571. if err != nil {
  572. return nil, errors.Tracef(
  573. "protocol.DecodeServerEntry failed: %s", err)
  574. }
  575. if config.frontingProviderID == "" {
  576. config.frontingProviderID = serverEntry.FrontingProviderID
  577. } else if config.frontingProviderID != serverEntry.FrontingProviderID {
  578. return nil, errors.Tracef("unsupported multiple FrontingProviderID values")
  579. }
  580. }
  581. config.runningProtocols = []string{}
  582. for tunnelProtocol := range config.TunnelProtocolPorts {
  583. config.runningProtocols = append(config.runningProtocols, tunnelProtocol)
  584. }
  585. return &config, nil
  586. }
  587. func validateNetworkAddress(address string, requireIPaddress bool) error {
  588. host, portStr, err := net.SplitHostPort(address)
  589. if err != nil {
  590. return err
  591. }
  592. if requireIPaddress && net.ParseIP(host) == nil {
  593. return errors.TraceNew("host must be an IP address")
  594. }
  595. port, err := strconv.Atoi(portStr)
  596. if err != nil {
  597. return err
  598. }
  599. if port < 0 || port > 65535 {
  600. return errors.TraceNew("invalid port")
  601. }
  602. return nil
  603. }
  604. // GenerateConfigParams specifies customizations to be applied to
  605. // a generated server config.
  606. type GenerateConfigParams struct {
  607. LogFilename string
  608. SkipPanickingLogWriter bool
  609. LogLevel string
  610. ServerIPAddress string
  611. WebServerPort int
  612. EnableSSHAPIRequests bool
  613. TunnelProtocolPorts map[string]int
  614. TrafficRulesConfigFilename string
  615. OSLConfigFilename string
  616. TacticsConfigFilename string
  617. TacticsRequestPublicKey string
  618. TacticsRequestObfuscatedKey string
  619. Passthrough bool
  620. LegacyPassthrough bool
  621. LimitQUICVersions protocol.QUICVersions
  622. EnableGQUIC bool
  623. }
  624. // GenerateConfig creates a new Psiphon server config. It returns JSON encoded
  625. // configs and a client-compatible "server entry" for the server. It generates
  626. // all necessary secrets and key material, which are emitted in the config
  627. // file and server entry as necessary.
  628. //
  629. // GenerateConfig uses sample values for many fields. The intention is for
  630. // generated configs to be used for testing or as examples for production
  631. // setup, not to generate production-ready configurations.
  632. //
  633. // When tactics key material is provided in GenerateConfigParams, tactics
  634. // capabilities are added for all meek protocols in TunnelProtocolPorts.
  635. func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, []byte, []byte, error) {
  636. // Input validation
  637. if net.ParseIP(params.ServerIPAddress) == nil {
  638. return nil, nil, nil, nil, nil, errors.TraceNew("invalid IP address")
  639. }
  640. if len(params.TunnelProtocolPorts) == 0 {
  641. return nil, nil, nil, nil, nil, errors.TraceNew("no tunnel protocols")
  642. }
  643. usedPort := make(map[int]bool)
  644. if params.WebServerPort != 0 {
  645. usedPort[params.WebServerPort] = true
  646. }
  647. usingMeek := false
  648. for tunnelProtocol, port := range params.TunnelProtocolPorts {
  649. if !common.Contains(protocol.SupportedTunnelProtocols, tunnelProtocol) {
  650. return nil, nil, nil, nil, nil, errors.TraceNew("invalid tunnel protocol")
  651. }
  652. if usedPort[port] {
  653. return nil, nil, nil, nil, nil, errors.TraceNew("duplicate listening port")
  654. }
  655. usedPort[port] = true
  656. if protocol.TunnelProtocolUsesMeekHTTP(tunnelProtocol) ||
  657. protocol.TunnelProtocolUsesMeekHTTPS(tunnelProtocol) {
  658. usingMeek = true
  659. }
  660. }
  661. // One test mode populates the tactics config file; this will generate
  662. // keys. Another test mode passes in existing keys to be used in the
  663. // server entry. Both the filename and existing keys cannot be passed in.
  664. if (params.TacticsConfigFilename != "") &&
  665. (params.TacticsRequestPublicKey != "" || params.TacticsRequestObfuscatedKey != "") {
  666. return nil, nil, nil, nil, nil, errors.TraceNew("invalid tactics parameters")
  667. }
  668. // Web server config
  669. var webServerSecret, webServerCertificate,
  670. webServerPrivateKey, webServerPortForwardAddress string
  671. if params.WebServerPort != 0 {
  672. webServerSecretBytes, err := common.MakeSecureRandomBytes(WEB_SERVER_SECRET_BYTE_LENGTH)
  673. if err != nil {
  674. return nil, nil, nil, nil, nil, errors.Trace(err)
  675. }
  676. webServerSecret = hex.EncodeToString(webServerSecretBytes)
  677. webServerCertificate, webServerPrivateKey, err = common.GenerateWebServerCertificate("")
  678. if err != nil {
  679. return nil, nil, nil, nil, nil, errors.Trace(err)
  680. }
  681. webServerPortForwardAddress = net.JoinHostPort(
  682. params.ServerIPAddress, strconv.Itoa(params.WebServerPort))
  683. }
  684. // SSH config
  685. rsaKey, err := rsa.GenerateKey(rand.Reader, SSH_RSA_HOST_KEY_BITS)
  686. if err != nil {
  687. return nil, nil, nil, nil, nil, errors.Trace(err)
  688. }
  689. sshPrivateKey := pem.EncodeToMemory(
  690. &pem.Block{
  691. Type: "RSA PRIVATE KEY",
  692. Bytes: x509.MarshalPKCS1PrivateKey(rsaKey),
  693. },
  694. )
  695. signer, err := ssh.NewSignerFromKey(rsaKey)
  696. if err != nil {
  697. return nil, nil, nil, nil, nil, errors.Trace(err)
  698. }
  699. sshPublicKey := signer.PublicKey()
  700. sshUserNameSuffixBytes, err := common.MakeSecureRandomBytes(SSH_USERNAME_SUFFIX_BYTE_LENGTH)
  701. if err != nil {
  702. return nil, nil, nil, nil, nil, errors.Trace(err)
  703. }
  704. sshUserNameSuffix := hex.EncodeToString(sshUserNameSuffixBytes)
  705. sshUserName := "psiphon_" + sshUserNameSuffix
  706. sshPasswordBytes, err := common.MakeSecureRandomBytes(SSH_PASSWORD_BYTE_LENGTH)
  707. if err != nil {
  708. return nil, nil, nil, nil, nil, errors.Trace(err)
  709. }
  710. sshPassword := hex.EncodeToString(sshPasswordBytes)
  711. sshServerVersion := "SSH-2.0-Psiphon"
  712. // Obfuscated SSH config
  713. obfuscatedSSHKeyBytes, err := common.MakeSecureRandomBytes(SSH_OBFUSCATED_KEY_BYTE_LENGTH)
  714. if err != nil {
  715. return nil, nil, nil, nil, nil, errors.Trace(err)
  716. }
  717. obfuscatedSSHKey := hex.EncodeToString(obfuscatedSSHKeyBytes)
  718. // Meek config
  719. var meekCookieEncryptionPublicKey, meekCookieEncryptionPrivateKey, meekObfuscatedKey string
  720. if usingMeek {
  721. rawMeekCookieEncryptionPublicKey, rawMeekCookieEncryptionPrivateKey, err :=
  722. box.GenerateKey(rand.Reader)
  723. if err != nil {
  724. return nil, nil, nil, nil, nil, errors.Trace(err)
  725. }
  726. meekCookieEncryptionPublicKey = base64.StdEncoding.EncodeToString(rawMeekCookieEncryptionPublicKey[:])
  727. meekCookieEncryptionPrivateKey = base64.StdEncoding.EncodeToString(rawMeekCookieEncryptionPrivateKey[:])
  728. meekObfuscatedKeyBytes, err := common.MakeSecureRandomBytes(SSH_OBFUSCATED_KEY_BYTE_LENGTH)
  729. if err != nil {
  730. return nil, nil, nil, nil, nil, errors.Trace(err)
  731. }
  732. meekObfuscatedKey = hex.EncodeToString(meekObfuscatedKeyBytes)
  733. }
  734. // Other config
  735. discoveryValueHMACKeyBytes, err := common.MakeSecureRandomBytes(DISCOVERY_VALUE_KEY_BYTE_LENGTH)
  736. if err != nil {
  737. return nil, nil, nil, nil, nil, errors.Trace(err)
  738. }
  739. discoveryValueHMACKey := base64.StdEncoding.EncodeToString(discoveryValueHMACKeyBytes)
  740. // Assemble configs and server entry
  741. // Note: this config is intended for either testing or as an illustrative
  742. // example or template and is not intended for production deployment.
  743. logLevel := params.LogLevel
  744. if logLevel == "" {
  745. logLevel = "info"
  746. }
  747. // For testing, set the Psiphon server to create its log files; we do not
  748. // expect tests to necessarily run under log managers, such as logrotate.
  749. createMode := 0666
  750. config := &Config{
  751. LogLevel: logLevel,
  752. LogFilename: params.LogFilename,
  753. LogFileCreateMode: &createMode,
  754. SkipPanickingLogWriter: params.SkipPanickingLogWriter,
  755. GeoIPDatabaseFilenames: nil,
  756. HostID: "example-host-id",
  757. ServerIPAddress: params.ServerIPAddress,
  758. DiscoveryValueHMACKey: discoveryValueHMACKey,
  759. WebServerPort: params.WebServerPort,
  760. WebServerSecret: webServerSecret,
  761. WebServerCertificate: webServerCertificate,
  762. WebServerPrivateKey: webServerPrivateKey,
  763. WebServerPortForwardAddress: webServerPortForwardAddress,
  764. SSHPrivateKey: string(sshPrivateKey),
  765. SSHServerVersion: sshServerVersion,
  766. SSHUserName: sshUserName,
  767. SSHPassword: sshPassword,
  768. ObfuscatedSSHKey: obfuscatedSSHKey,
  769. TunnelProtocolPorts: params.TunnelProtocolPorts,
  770. DNSResolverIPAddress: "8.8.8.8",
  771. UDPInterceptUdpgwServerAddress: "127.0.0.1:7300",
  772. MeekCookieEncryptionPrivateKey: meekCookieEncryptionPrivateKey,
  773. MeekObfuscatedKey: meekObfuscatedKey,
  774. MeekProhibitedHeaders: nil,
  775. MeekProxyForwardedForHeaders: []string{"X-Forwarded-For"},
  776. LoadMonitorPeriodSeconds: 300,
  777. TrafficRulesFilename: params.TrafficRulesConfigFilename,
  778. OSLConfigFilename: params.OSLConfigFilename,
  779. TacticsConfigFilename: params.TacticsConfigFilename,
  780. LegacyPassthrough: params.LegacyPassthrough,
  781. EnableGQUIC: params.EnableGQUIC,
  782. }
  783. encodedConfig, err := json.MarshalIndent(config, "\n", " ")
  784. if err != nil {
  785. return nil, nil, nil, nil, nil, errors.Trace(err)
  786. }
  787. intPtr := func(i int) *int {
  788. return &i
  789. }
  790. trafficRulesSet := &TrafficRulesSet{
  791. DefaultRules: TrafficRules{
  792. RateLimits: RateLimits{
  793. ReadUnthrottledBytes: new(int64),
  794. ReadBytesPerSecond: new(int64),
  795. WriteUnthrottledBytes: new(int64),
  796. WriteBytesPerSecond: new(int64),
  797. },
  798. IdleTCPPortForwardTimeoutMilliseconds: intPtr(DEFAULT_IDLE_TCP_PORT_FORWARD_TIMEOUT_MILLISECONDS),
  799. IdleUDPPortForwardTimeoutMilliseconds: intPtr(DEFAULT_IDLE_UDP_PORT_FORWARD_TIMEOUT_MILLISECONDS),
  800. MaxTCPPortForwardCount: intPtr(DEFAULT_MAX_TCP_PORT_FORWARD_COUNT),
  801. MaxUDPPortForwardCount: intPtr(DEFAULT_MAX_UDP_PORT_FORWARD_COUNT),
  802. AllowTCPPorts: nil,
  803. AllowUDPPorts: nil,
  804. },
  805. }
  806. encodedTrafficRulesSet, err := json.MarshalIndent(trafficRulesSet, "\n", " ")
  807. if err != nil {
  808. return nil, nil, nil, nil, nil, errors.Trace(err)
  809. }
  810. encodedOSLConfig, err := json.MarshalIndent(&osl.Config{}, "\n", " ")
  811. if err != nil {
  812. return nil, nil, nil, nil, nil, errors.Trace(err)
  813. }
  814. tacticsRequestPublicKey := params.TacticsRequestPublicKey
  815. tacticsRequestObfuscatedKey := params.TacticsRequestObfuscatedKey
  816. var tacticsRequestPrivateKey string
  817. var encodedTacticsConfig []byte
  818. if params.TacticsConfigFilename != "" {
  819. tacticsRequestPublicKey, tacticsRequestPrivateKey, tacticsRequestObfuscatedKey, err =
  820. tactics.GenerateKeys()
  821. if err != nil {
  822. return nil, nil, nil, nil, nil, errors.Trace(err)
  823. }
  824. decodedTacticsRequestPublicKey, err := base64.StdEncoding.DecodeString(tacticsRequestPublicKey)
  825. if err != nil {
  826. return nil, nil, nil, nil, nil, errors.Trace(err)
  827. }
  828. decodedTacticsRequestPrivateKey, err := base64.StdEncoding.DecodeString(tacticsRequestPrivateKey)
  829. if err != nil {
  830. return nil, nil, nil, nil, nil, errors.Trace(err)
  831. }
  832. decodedTacticsRequestObfuscatedKey, err := base64.StdEncoding.DecodeString(tacticsRequestObfuscatedKey)
  833. if err != nil {
  834. return nil, nil, nil, nil, nil, errors.Trace(err)
  835. }
  836. tacticsConfig := &tactics.Server{
  837. RequestPublicKey: decodedTacticsRequestPublicKey,
  838. RequestPrivateKey: decodedTacticsRequestPrivateKey,
  839. RequestObfuscatedKey: decodedTacticsRequestObfuscatedKey,
  840. DefaultTactics: tactics.Tactics{
  841. TTL: "1m",
  842. Probability: 1.0,
  843. },
  844. }
  845. encodedTacticsConfig, err = json.MarshalIndent(tacticsConfig, "\n", " ")
  846. if err != nil {
  847. return nil, nil, nil, nil, nil, errors.Trace(err)
  848. }
  849. }
  850. capabilities := []string{}
  851. if params.EnableSSHAPIRequests {
  852. capabilities = append(capabilities, protocol.CAPABILITY_SSH_API_REQUESTS)
  853. }
  854. if params.WebServerPort != 0 {
  855. capabilities = append(capabilities, protocol.CAPABILITY_UNTUNNELED_WEB_API_REQUESTS)
  856. }
  857. for tunnelProtocol := range params.TunnelProtocolPorts {
  858. capability := protocol.GetCapability(tunnelProtocol)
  859. if params.Passthrough && protocol.TunnelProtocolSupportsPassthrough(tunnelProtocol) {
  860. if !params.LegacyPassthrough {
  861. capability += "-PASSTHROUGH-v2"
  862. } else {
  863. capability += "-PASSTHROUGH"
  864. }
  865. }
  866. if tunnelProtocol == protocol.TUNNEL_PROTOCOL_QUIC_OBFUSCATED_SSH && !params.EnableGQUIC {
  867. capability += "v1"
  868. }
  869. capabilities = append(capabilities, capability)
  870. if params.TacticsRequestPublicKey != "" && params.TacticsRequestObfuscatedKey != "" &&
  871. protocol.TunnelProtocolUsesMeek(tunnelProtocol) {
  872. capabilities = append(capabilities, protocol.GetTacticsCapability(tunnelProtocol))
  873. }
  874. }
  875. sshPort := params.TunnelProtocolPorts[protocol.TUNNEL_PROTOCOL_SSH]
  876. obfuscatedSSHPort := params.TunnelProtocolPorts[protocol.TUNNEL_PROTOCOL_OBFUSCATED_SSH]
  877. obfuscatedSSHQUICPort := params.TunnelProtocolPorts[protocol.TUNNEL_PROTOCOL_QUIC_OBFUSCATED_SSH]
  878. // Meek port limitations
  879. // - fronted meek protocols are hard-wired in the client to be port 443 or 80.
  880. // - only one other meek port may be specified.
  881. meekPort := params.TunnelProtocolPorts[protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK]
  882. if meekPort == 0 {
  883. meekPort = params.TunnelProtocolPorts[protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_HTTPS]
  884. }
  885. if meekPort == 0 {
  886. meekPort = params.TunnelProtocolPorts[protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_SESSION_TICKET]
  887. }
  888. // Note: fronting params are a stub; this server entry will exercise
  889. // client and server fronting code paths, but not actually traverse
  890. // a fronting hop.
  891. serverEntryWebServerPort := ""
  892. strippedWebServerCertificate := ""
  893. if params.WebServerPort != 0 {
  894. serverEntryWebServerPort = fmt.Sprintf("%d", params.WebServerPort)
  895. // Server entry format omits the BEGIN/END lines and newlines
  896. lines := strings.Split(webServerCertificate, "\n")
  897. strippedWebServerCertificate = strings.Join(lines[1:len(lines)-2], "")
  898. }
  899. serverEntry := &protocol.ServerEntry{
  900. IpAddress: params.ServerIPAddress,
  901. WebServerPort: serverEntryWebServerPort,
  902. WebServerSecret: webServerSecret,
  903. WebServerCertificate: strippedWebServerCertificate,
  904. SshPort: sshPort,
  905. SshUsername: sshUserName,
  906. SshPassword: sshPassword,
  907. SshHostKey: base64.RawStdEncoding.EncodeToString(sshPublicKey.Marshal()),
  908. SshObfuscatedPort: obfuscatedSSHPort,
  909. SshObfuscatedQUICPort: obfuscatedSSHQUICPort,
  910. LimitQUICVersions: params.LimitQUICVersions,
  911. SshObfuscatedKey: obfuscatedSSHKey,
  912. Capabilities: capabilities,
  913. Region: "US",
  914. MeekServerPort: meekPort,
  915. MeekCookieEncryptionPublicKey: meekCookieEncryptionPublicKey,
  916. MeekObfuscatedKey: meekObfuscatedKey,
  917. MeekFrontingHosts: []string{params.ServerIPAddress},
  918. MeekFrontingAddresses: []string{params.ServerIPAddress},
  919. MeekFrontingDisableSNI: false,
  920. TacticsRequestPublicKey: tacticsRequestPublicKey,
  921. TacticsRequestObfuscatedKey: tacticsRequestObfuscatedKey,
  922. ConfigurationVersion: 1,
  923. }
  924. encodedServerEntry, err := protocol.EncodeServerEntry(serverEntry)
  925. if err != nil {
  926. return nil, nil, nil, nil, nil, errors.Trace(err)
  927. }
  928. return encodedConfig, encodedTrafficRulesSet, encodedOSLConfig, encodedTacticsConfig, []byte(encodedServerEntry), nil
  929. }