config.go 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382
  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. "net"
  29. "os"
  30. "strconv"
  31. "strings"
  32. "sync/atomic"
  33. "time"
  34. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  35. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/accesscontrol"
  36. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/ssh"
  37. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  38. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/inproxy"
  39. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/osl"
  40. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
  41. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
  42. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/tactics"
  43. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/values"
  44. "golang.org/x/crypto/nacl/box"
  45. )
  46. const (
  47. SERVER_CONFIG_FILENAME = "psiphond.config"
  48. SERVER_TRAFFIC_RULES_CONFIG_FILENAME = "psiphond-traffic-rules.config"
  49. SERVER_OSL_CONFIG_FILENAME = "psiphond-osl.config"
  50. SERVER_TACTICS_CONFIG_FILENAME = "psiphond-tactics.config"
  51. SERVER_ENTRY_FILENAME = "server-entry.dat"
  52. DEFAULT_SERVER_IP_ADDRESS = "127.0.0.1"
  53. WEB_SERVER_SECRET_BYTE_LENGTH = 32
  54. DISCOVERY_VALUE_KEY_BYTE_LENGTH = 32
  55. SSH_USERNAME_SUFFIX_BYTE_LENGTH = 8
  56. SSH_PASSWORD_BYTE_LENGTH = 32
  57. SSH_RSA_HOST_KEY_BITS = 2048
  58. SSH_OBFUSCATED_KEY_BYTE_LENGTH = 32
  59. SHADOWSOCKS_KEY_BYTE_LENGTH = 32
  60. PEAK_UPSTREAM_FAILURE_RATE_MINIMUM_SAMPLE_SIZE = 10
  61. PERIODIC_GARBAGE_COLLECTION = 120 * time.Second
  62. STOP_ESTABLISH_TUNNELS_ESTABLISHED_CLIENT_THRESHOLD = 20
  63. DEFAULT_LOG_FILE_REOPEN_RETRIES = 25
  64. )
  65. // Config specifies the configuration and behavior of a Psiphon
  66. // server.
  67. type Config struct {
  68. // LogLevel specifies the log level. Valid values are:
  69. // panic, fatal, error, warn, info, debug
  70. //
  71. // Some debug logs can contain user traffic destination address information.
  72. LogLevel string `json:",omitempty"`
  73. // LogFilename specifies the path of the file to log
  74. // to. When blank, logs are written to stderr.
  75. LogFilename string `json:",omitempty"`
  76. // LogFileReopenRetries specifies how many retries, each with a 1ms delay,
  77. // will be attempted after reopening a rotated log file fails. Retries
  78. // mitigate any race conditions between writes/reopens and file operations
  79. // performed by external log managers, such as logrotate.
  80. //
  81. // When omitted, DEFAULT_LOG_FILE_REOPEN_RETRIES is used.
  82. LogFileReopenRetries *int `json:",omitempty"`
  83. // LogFileCreateMode specifies that the Psiphon server should create a new
  84. // log file when one is not found, such as after rotation with logrotate
  85. // configured with nocreate. The value is the os.FileMode value to use when
  86. // creating the file.
  87. //
  88. // When omitted, the Psiphon server does not create log files.
  89. LogFileCreateMode *int `json:",omitempty"`
  90. // When LogDNSServerLoadMetrics is true, server_load logs will include a
  91. // break down of DNS request counts, failure rates, etc. per DNS server.
  92. // Otherwise, only the overall DNS metrics are logged.
  93. LogDNSServerLoadMetrics bool `json:",omitempty"`
  94. // SkipPanickingLogWriter disables panicking when
  95. // unable to write any logs.
  96. SkipPanickingLogWriter bool `json:",omitempty"`
  97. // DiscoveryValueHMACKey is the network-wide secret value
  98. // used to determine a unique discovery strategy.
  99. DiscoveryValueHMACKey string `json:",omitempty"`
  100. // GeoIPDatabaseFilenames are paths of GeoIP2/GeoLite2
  101. // MaxMind database files. When empty, no GeoIP lookups are
  102. // performed. Each file is queried, in order, for the
  103. // logged fields: country code, city, and ISP. Multiple
  104. // file support accommodates the MaxMind distribution where
  105. // ISP data in a separate file.
  106. GeoIPDatabaseFilenames []string `json:",omitempty"`
  107. // PsinetDatabaseFilename is the path of the file containing
  108. // psinet.Database data.
  109. PsinetDatabaseFilename string `json:",omitempty"`
  110. // HostID identifies the server host; this value is included with all logs.
  111. HostID string `json:",omitempty"`
  112. // HostProvider identifies the server host provider; this value is
  113. // included with all logs and logged only when not blank.
  114. HostProvider string `json:",omitempty"`
  115. // ServerIPAddress is the public IP address of the server.
  116. ServerIPAddress string `json:",omitempty"`
  117. // TunnelProtocolPorts specifies which tunnel protocols to run
  118. // and which ports to listen on for each protocol. Valid tunnel
  119. // protocols include:
  120. // "SSH", "OSSH", "TLS-OSSH", "UNFRONTED-MEEK-OSSH", "UNFRONTED-MEEK-HTTPS-OSSH",
  121. // "UNFRONTED-MEEK-SESSION-TICKET-OSSH", "FRONTED-MEEK-OSSH",
  122. // "FRONTED-MEEK-QUIC-OSSH", "FRONTED-MEEK-HTTP-OSSH", "QUIC-OSSH",
  123. // "TAPDANCE-OSSH", "CONJURE-OSSH", and "SHADOWSOCKS-OSSH".
  124. TunnelProtocolPorts map[string]int `json:",omitempty"`
  125. // TunnelProtocolPassthroughAddresses specifies passthrough addresses to be
  126. // used for tunnel protocols configured in TunnelProtocolPorts. Passthrough
  127. // is a probing defense which relays all network traffic between a client and
  128. // the passthrough target when the client fails anti-probing tests.
  129. //
  130. // TunnelProtocolPassthroughAddresses is supported for:
  131. // "TLS-OSSH", "UNFRONTED-MEEK-HTTPS-OSSH",
  132. // "UNFRONTED-MEEK-SESSION-TICKET-OSSH", "UNFRONTED-MEEK-OSSH".
  133. TunnelProtocolPassthroughAddresses map[string]string `json:",omitempty"`
  134. // LegacyPassthrough indicates whether to expect legacy passthrough messages
  135. // from clients attempting to connect. This should be set for existing/legacy
  136. // passthrough servers only.
  137. LegacyPassthrough bool `json:",omitempty"`
  138. // EnableGQUIC indicates whether to enable legacy gQUIC QUIC-OSSH
  139. // versions, for backwards compatibility with all versions used by older
  140. // clients. Enabling gQUIC degrades the anti-probing stance of QUIC-OSSH,
  141. // as the legacy gQUIC stack will respond to probing packets.
  142. EnableGQUIC bool `json:",omitempty"`
  143. // SSHPrivateKey is the SSH host key. The same key is used for
  144. // all protocols, run by this server instance, which use SSH.
  145. SSHPrivateKey string `json:",omitempty"`
  146. // SSHServerVersion is the server version presented in the
  147. // identification string. The same value is used for all
  148. // protocols, run by this server instance, which use SSH.
  149. SSHServerVersion string `json:",omitempty"`
  150. // SSHUserName is the SSH user name to be presented by the
  151. // the tunnel-core client. The same value is used for all
  152. // protocols, run by this server instance, which use SSH.
  153. SSHUserName string `json:",omitempty"`
  154. // SSHPassword is the SSH password to be presented by the
  155. // the tunnel-core client. The same value is used for all
  156. // protocols, run by this server instance, which use SSH.
  157. SSHPassword string `json:",omitempty"`
  158. // SSHBeginHandshakeTimeoutMilliseconds specifies the timeout
  159. // for clients queueing to begin an SSH handshake. The default
  160. // is SSH_BEGIN_HANDSHAKE_TIMEOUT.
  161. SSHBeginHandshakeTimeoutMilliseconds *int `json:",omitempty"`
  162. // SSHHandshakeTimeoutMilliseconds specifies the timeout
  163. // before which a client must complete its handshake. The default
  164. // is SSH_HANDSHAKE_TIMEOUT.
  165. SSHHandshakeTimeoutMilliseconds *int `json:",omitempty"`
  166. // ObfuscatedSSHKey is the secret key for use in the Obfuscated
  167. // SSH protocol. The same secret key is used for all protocols,
  168. // run by this server instance, which use Obfuscated SSH.
  169. ObfuscatedSSHKey string `json:",omitempty"`
  170. // ShadowsocksKey is the secret key for use in the Shadowsocks
  171. // protocol.
  172. ShadowsocksKey string `json:",omitempty"`
  173. // MeekCookieEncryptionPrivateKey is the NaCl private key used
  174. // to decrypt meek cookie payload sent from clients. The same
  175. // key is used for all meek protocols run by this server instance.
  176. MeekCookieEncryptionPrivateKey string `json:",omitempty"`
  177. // MeekObfuscatedKey is the secret key used for obfuscating
  178. // meek cookies sent from clients. The same key is used for all
  179. // meek protocols run by this server instance.
  180. //
  181. // NOTE: this key is also used by the TLS-OSSH protocol, which allows
  182. // clients with legacy unfronted meek-https server entries, that have the
  183. // passthrough capability, to connect with TLS-OSSH to the servers
  184. // corresponding to those server entries, which now support TLS-OSSH by
  185. // demultiplexing meek-https and TLS-OSSH over the meek-https port.
  186. MeekObfuscatedKey string `json:",omitempty"`
  187. // MeekProhibitedHeaders is a list of HTTP headers to check for
  188. // in client requests. If one of these headers is found, the
  189. // request fails. This is used to defend against abuse.
  190. MeekProhibitedHeaders []string `json:",omitempty"`
  191. // MeekRequiredHeaders is a list of HTTP header names and values that must
  192. // appear in requests. This is used to defend against abuse.
  193. MeekRequiredHeaders map[string]string `json:",omitempty"`
  194. // MeekServerCertificate specifies an optional certificate to use for meek
  195. // servers, in place of the default, randomly generate certificate. When
  196. // specified, the corresponding private key must be supplied in
  197. // MeekServerPrivateKey. Any specified certificate is used for all meek
  198. // listeners.
  199. MeekServerCertificate string `json:",omitempty"`
  200. // MeekServerPrivateKey is the private key corresponding to the optional
  201. // MeekServerCertificate parameter.
  202. MeekServerPrivateKey string `json:",omitempty"`
  203. // MeekProxyForwardedForHeaders is a list of HTTP headers which
  204. // may be added by downstream HTTP proxies or CDNs in front
  205. // of clients. These headers supply the original client IP
  206. // address, which is geolocated for stats purposes. Headers
  207. // include, for example, X-Forwarded-For. The header's value
  208. // is assumed to be a comma delimted list of IP addresses where
  209. // the client IP is the first IP address in the list. Meek protocols
  210. // look for these headers and use the client IP address from
  211. // the header if any one is present and the value is a valid
  212. // IP address; otherwise the direct connection remote address is
  213. // used as the client IP.
  214. MeekProxyForwardedForHeaders []string `json:",omitempty"`
  215. // MeekTurnAroundTimeoutMilliseconds specifies the amount of time meek will
  216. // wait for downstream bytes before responding to a request. The default is
  217. // MEEK_DEFAULT_TURN_AROUND_TIMEOUT.
  218. MeekTurnAroundTimeoutMilliseconds *int `json:",omitempty"`
  219. // MeekExtendedTurnAroundTimeoutMilliseconds specifies the extended amount of
  220. // time meek will wait for downstream bytes, as long as bytes arrive every
  221. // MeekTurnAroundTimeoutMilliseconds, before responding to a request. The
  222. // default is MEEK_DEFAULT_EXTENDED_TURN_AROUND_TIMEOUT.
  223. MeekExtendedTurnAroundTimeoutMilliseconds *int `json:",omitempty"`
  224. // MeekSkipExtendedTurnAroundThresholdBytes specifies when to skip the
  225. // extended turn around. When the number of bytes received in the client
  226. // request meets the threshold, optimize for upstream flows with quicker
  227. // round trip turn arounds.
  228. MeekSkipExtendedTurnAroundThresholdBytes *int `json:",omitempty"`
  229. // MeekMaxSessionStalenessMilliseconds specifies the TTL for meek sessions.
  230. // The default is MEEK_DEFAULT_MAX_SESSION_STALENESS.
  231. MeekMaxSessionStalenessMilliseconds *int `json:",omitempty"`
  232. // MeekHTTPClientIOTimeoutMilliseconds specifies meek HTTP server I/O
  233. // timeouts. The default is MEEK_DEFAULT_HTTP_CLIENT_IO_TIMEOUT.
  234. MeekHTTPClientIOTimeoutMilliseconds *int `json:",omitempty"`
  235. // MeekFrontedHTTPClientIOTimeoutMilliseconds specifies meek HTTP server
  236. // I/O timeouts for fronted protocols. The default is
  237. // MEEK_DEFAULT_FRONTED_HTTP_CLIENT_IO_TIMEOUT.
  238. MeekFrontedHTTPClientIOTimeoutMilliseconds *int `json:",omitempty"`
  239. // MeekCachedResponseBufferSize is the size of a private,
  240. // fixed-size buffer allocated for every meek client. The buffer
  241. // is used to cache response payload, allowing the client to retry
  242. // fetching when a network connection is interrupted. This retry
  243. // makes the OSSH tunnel within meek resilient to interruptions
  244. // at the HTTP TCP layer.
  245. // Larger buffers increase resiliency to interruption, but consume
  246. // more memory as buffers as never freed. The maximum size of a
  247. // response payload is a function of client activity, network
  248. // throughput and throttling.
  249. // A default of 64K is used when MeekCachedResponseBufferSize is 0.
  250. MeekCachedResponseBufferSize int `json:",omitempty"`
  251. // MeekCachedResponsePoolBufferSize is the size of a fixed-size,
  252. // shared buffer used to temporarily extend a private buffer when
  253. // MeekCachedResponseBufferSize is insufficient. Shared buffers
  254. // allow some clients to successfully retry longer response payloads
  255. // without allocating large buffers for all clients.
  256. // A default of 64K is used when MeekCachedResponsePoolBufferSize
  257. // is 0.
  258. MeekCachedResponsePoolBufferSize int `json:",omitempty"`
  259. // MeekCachedResponsePoolBufferCount is the number of shared
  260. // buffers. Shared buffers are allocated on first use and remain
  261. // allocated, so shared buffer count * size is roughly the memory
  262. // overhead of this facility.
  263. // A default of 2048 is used when MeekCachedResponsePoolBufferCount
  264. // is 0.
  265. MeekCachedResponsePoolBufferCount int `json:",omitempty"`
  266. // MeekCachedResponsePoolBufferClientLimit is the maximum number of of
  267. // shared buffers a single client may consume at once. A default of 32 is
  268. // used when MeekCachedResponsePoolBufferClientLimit is 0.
  269. MeekCachedResponsePoolBufferClientLimit int `json:",omitempty"`
  270. // UDPInterceptUdpgwServerAddress specifies the network address of
  271. // a udpgw server which clients may be port forwarding to. When
  272. // specified, these TCP port forwards are intercepted and handled
  273. // directly by this server, which parses the SSH channel using the
  274. // udpgw protocol. Handling includes udpgw transparent DNS: tunneled
  275. // UDP DNS packets are rerouted to the host's DNS server.
  276. //
  277. // The intercept is applied before the port forward destination is
  278. // validated against SSH_DISALLOWED_PORT_FORWARD_HOSTS and
  279. // AllowTCPPorts. So the intercept address may be any otherwise
  280. // prohibited destination.
  281. UDPInterceptUdpgwServerAddress string `json:",omitempty"`
  282. // DNSResolverIPAddress specifies the IP address of a DNS server
  283. // to be used when "/etc/resolv.conf" doesn't exist or fails to
  284. // parse. When blank, "/etc/resolv.conf" must contain a usable
  285. // "nameserver" entry.
  286. DNSResolverIPAddress string `json:",omitempty"`
  287. // LoadMonitorPeriodSeconds indicates how frequently to log server
  288. // load information (number of connected clients per tunnel protocol,
  289. // number of running goroutines, amount of memory allocated, etc.)
  290. // The default, 0, disables load logging.
  291. LoadMonitorPeriodSeconds int `json:",omitempty"`
  292. // PeakUpstreamFailureRateMinimumSampleSize specifies the minimum number
  293. // of samples (e.g., upstream port forward attempts) that are required
  294. // before taking a failure rate snapshot which may be recorded as
  295. // peak_dns_failure_rate/peak_tcp_port_forward_failure_rate. The default
  296. // is PEAK_UPSTREAM_FAILURE_RATE_SAMPLE_SIZE.
  297. PeakUpstreamFailureRateMinimumSampleSize *int `json:",omitempty"`
  298. // ProcessProfileOutputDirectory is the path of a directory to which
  299. // process profiles will be written when signaled with SIGUSR2. The
  300. // files are overwritten on each invocation. When set to the default
  301. // value, blank, no profiles are written on SIGUSR2. Profiles include
  302. // the default profiles here: https://golang.org/pkg/runtime/pprof/#Profile.
  303. ProcessProfileOutputDirectory string `json:",omitempty"`
  304. // ProcessBlockProfileDurationSeconds specifies the sample duration for
  305. // "block" profiling. For the default, 0, no "block" profile is taken.
  306. ProcessBlockProfileDurationSeconds int `json:",omitempty"`
  307. // ProcessCPUProfileDurationSeconds specifies the sample duration for
  308. // CPU profiling. For the default, 0, no CPU profile is taken.
  309. ProcessCPUProfileDurationSeconds int `json:",omitempty"`
  310. // TrafficRulesFilename is the path of a file containing a JSON-encoded
  311. // TrafficRulesSet, the traffic rules to apply to Psiphon client tunnels.
  312. TrafficRulesFilename string `json:",omitempty"`
  313. // OSLConfigFilename is the path of a file containing a JSON-encoded
  314. // OSL Config, the OSL schemes to apply to Psiphon client tunnels.
  315. OSLConfigFilename string `json:",omitempty"`
  316. // RunPacketTunnel specifies whether to run a packet tunnel.
  317. RunPacketTunnel bool `json:",omitempty"`
  318. // PacketTunnelEgressInterface specifies tun.ServerConfig.EgressInterface.
  319. PacketTunnelEgressInterface string `json:",omitempty"`
  320. // PacketTunnelEnableDNSFlowTracking sets
  321. // tun.ServerConfig.EnableDNSFlowTracking.
  322. PacketTunnelEnableDNSFlowTracking bool `json:",omitempty"`
  323. // PacketTunnelDownstreamPacketQueueSize specifies
  324. // tun.ServerConfig.DownStreamPacketQueueSize.
  325. PacketTunnelDownstreamPacketQueueSize int `json:",omitempty"`
  326. // PacketTunnelSessionIdleExpirySeconds specifies
  327. // tun.ServerConfig.SessionIdleExpirySeconds.
  328. PacketTunnelSessionIdleExpirySeconds int `json:",omitempty"`
  329. // PacketTunnelSudoNetworkConfigCommands sets
  330. // tun.ServerConfig.SudoNetworkConfigCommands,
  331. // packetman.Config.SudoNetworkConfigCommands, and
  332. // SudoNetworkConfigCommands for configureIptablesAcceptRateLimitChain.
  333. PacketTunnelSudoNetworkConfigCommands bool `json:",omitempty"`
  334. // RunPacketManipulator specifies whether to run a packet manipulator.
  335. RunPacketManipulator bool `json:",omitempty"`
  336. // MaxConcurrentSSHHandshakes specifies a limit on the number of concurrent
  337. // SSH handshake negotiations. This is set to mitigate spikes in memory
  338. // allocations and CPU usage associated with SSH handshakes when many clients
  339. // attempt to connect concurrently. When a maximum limit is specified and
  340. // reached, additional clients that establish TCP or meek connections will
  341. // be disconnected after a short wait for the number of concurrent handshakes
  342. // to drop below the limit.
  343. // The default, 0 is no limit.
  344. MaxConcurrentSSHHandshakes int `json:",omitempty"`
  345. // PeriodicGarbageCollectionSeconds turns on periodic calls to
  346. // debug.FreeOSMemory, every specified number of seconds, to force garbage
  347. // collection and memory scavenging. Specify 0 to disable. The default is
  348. // PERIODIC_GARBAGE_COLLECTION.
  349. PeriodicGarbageCollectionSeconds *int `json:",omitempty"`
  350. // StopEstablishTunnelsEstablishedClientThreshold sets the established client
  351. // threshold for dumping profiles when SIGTSTP is signaled. When there are
  352. // less than or equal to the threshold number of established clients,
  353. // profiles are dumped to aid investigating unusual load limited states that
  354. // occur when few clients are connected and load should be relatively low. A
  355. // profile dump is attempted at most once per process lifetime, the first
  356. // time the threshold is met. Disabled when < 0.
  357. StopEstablishTunnelsEstablishedClientThreshold *int `json:",omitempty"`
  358. // AccessControlVerificationKeyRing is the access control authorization
  359. // verification key ring used to verify signed authorizations presented
  360. // by clients. Verified, active (unexpired) access control types will be
  361. // available for matching in the TrafficRulesFilter for the client via
  362. // AuthorizedAccessTypes. All other authorizations are ignored.
  363. AccessControlVerificationKeyRing *accesscontrol.VerificationKeyRing `json:",omitempty"`
  364. // TacticsConfigFilename is the path of a file containing a JSON-encoded
  365. // tactics server configuration.
  366. TacticsConfigFilename string `json:",omitempty"`
  367. // TacticsRequestPublicKey is an optional, base64 encoded
  368. // tactics.Server.RequestPublicKey which overrides the value in the
  369. // tactics configuration file.
  370. TacticsRequestPublicKey string `json:",omitempty"`
  371. // TacticsRequestPrivateKey is an optional, base64 encoded
  372. // tactics.Server.RequestPrivateKey which overrides the value in the
  373. // tactics configuration file.
  374. TacticsRequestPrivateKey string `json:",omitempty"`
  375. // TacticsRequestObfuscatedKey is an optional, base64 encoded
  376. // tactics.Server.RequestObfuscatedKey which overrides the value in the
  377. // tactics configuration file.
  378. TacticsRequestObfuscatedKey string `json:",omitempty"`
  379. // BlocklistFilename is the path of a file containing a CSV-encoded
  380. // blocklist configuration. See NewBlocklist for more file format
  381. // documentation.
  382. BlocklistFilename string `json:",omitempty"`
  383. // BlocklistActive indicates whether to actively prevent blocklist hits in
  384. // addition to logging events.
  385. BlocklistActive bool `json:",omitempty"`
  386. // AllowBogons disables port forward bogon checks. This should be used only
  387. // for testing.
  388. AllowBogons bool `json:",omitempty"`
  389. // EnableSteeringIPs enables meek server steering IP support.
  390. EnableSteeringIPs bool `json:",omitempty"`
  391. // OwnEncodedServerEntries is a list of the server's own encoded server
  392. // entries, idenfified by server entry tag. These values are used in the
  393. // handshake API to update clients that don't yet have a signed copy of these
  394. // server entries.
  395. //
  396. // For purposes of compartmentalization, each server receives only its own
  397. // server entries here; and, besides the discovery server entries, in
  398. // psinet.Database, necessary for the discovery feature, no other server
  399. // entries are stored on a Psiphon server.
  400. OwnEncodedServerEntries map[string]string `json:",omitempty"`
  401. // MeekServerRunInproxyBroker indicates whether to run an in-proxy broker
  402. // endpoint and service under the meek server.
  403. MeekServerRunInproxyBroker bool `json:",omitempty"`
  404. // MeekServerInproxyBrokerOnly indicates whether to run only an in-proxy
  405. // broker under the meek server, and not run any meek tunnel protocol. To
  406. // run the meek listener, a meek server protocol and port must still be
  407. // specified in TunnelProtocolPorts, but no other tunnel protocol
  408. // parameters are required.
  409. MeekServerInproxyBrokerOnly bool `json:",omitempty"`
  410. // InproxyBrokerSessionPrivateKey specifies the broker's in-proxy session
  411. // private key and derived public key used by in-proxy clients and
  412. // proxies. This value is required when running an in-proxy broker.
  413. InproxyBrokerSessionPrivateKey string `json:",omitempty"`
  414. // InproxyBrokerObfuscationRootSecret specifies the broker's in-proxy
  415. // session root obfuscation secret used by in-proxy clients and proxies.
  416. // This value is required when running an in-proxy broker.
  417. InproxyBrokerObfuscationRootSecret string `json:",omitempty"`
  418. // InproxyBrokerServerEntrySignaturePublicKey specifies the public key
  419. // used to verify Psiphon server entry signature. This value is required
  420. // when running an in-proxy broker.
  421. InproxyBrokerServerEntrySignaturePublicKey string `json:",omitempty"`
  422. // InproxyBrokerAllowCommonASNMatching overrides the default broker
  423. // matching behavior which doesn't match non-personal in-proxy clients
  424. // and proxies from the same ASN. This parameter is for testing only.
  425. InproxyBrokerAllowCommonASNMatching bool `json:",omitempty"`
  426. // InproxyBrokerAllowBogonWebRTCConnections overrides the default broker
  427. // SDP validation behavior, which doesn't allow private network WebRTC
  428. // candidates. This parameter is for testing only.
  429. InproxyBrokerAllowBogonWebRTCConnections bool `json:",omitempty"`
  430. // InproxyServerSessionPrivateKey specifies the server's in-proxy session
  431. // private key and derived public key used by brokers. This value is
  432. // required when running in-proxy tunnel protocols.
  433. InproxyServerSessionPrivateKey string `json:",omitempty"`
  434. // InproxyServerObfuscationRootSecret specifies the server's in-proxy
  435. // session root obfuscation secret used by brokers. This value is
  436. // required when running in-proxy tunnel protocols.
  437. InproxyServerObfuscationRootSecret string `json:",omitempty"`
  438. // IptablesAcceptRateLimitChainName, when set, enables programmatic
  439. // configuration of iptables rules to allow and apply rate limits to
  440. // tunnel protocol network ports. The configuration is applied to the
  441. // specified chain.
  442. //
  443. // For details, see configureIptablesAcceptRateLimitChain.
  444. IptablesAcceptRateLimitChainName string `json:",omitempty"`
  445. // IptablesAcceptRateLimitTunnelProtocolRateLimits specifies custom
  446. // iptables rate limits by tunnel protocol name. See
  447. // configureIptablesAcceptRateLimitChain details about the rate limit
  448. // values.
  449. IptablesAcceptRateLimitTunnelProtocolRateLimits map[string][2]int `json:",omitempty"`
  450. sshBeginHandshakeTimeout time.Duration
  451. sshHandshakeTimeout time.Duration
  452. peakUpstreamFailureRateMinimumSampleSize int
  453. periodicGarbageCollection time.Duration
  454. stopEstablishTunnelsEstablishedClientThreshold int
  455. dumpProfilesOnStopEstablishTunnelsDoneOnce int32
  456. providerID string
  457. frontingProviderID string
  458. region string
  459. runningProtocols []string
  460. runningOnlyInproxyBroker bool
  461. }
  462. // GetLogFileReopenConfig gets the reopen retries, and create/mode inputs for
  463. // rotate.NewRotatableFileWriter, which is used when writing to log files.
  464. //
  465. // By default, we expect the log files to be managed by logrotate, with
  466. // logrotate configured to re-create the next log file after rotation. As
  467. // described in the documentation for rotate.NewRotatableFileWriter, and as
  468. // observed in production, we occasionally need retries when attempting to
  469. // reopen the log file post-rotation; and we avoid conflicts, and spurious
  470. // re-rotations, by disabling file create in rotate.NewRotatableFileWriter. In
  471. // large scale production, incidents requiring retry are very rare, so the
  472. // retry delay is not expected to have a significant impact on performance.
  473. //
  474. // The defaults may be overriden in the Config.
  475. func (config *Config) GetLogFileReopenConfig() (int, bool, os.FileMode) {
  476. retries := DEFAULT_LOG_FILE_REOPEN_RETRIES
  477. if config.LogFileReopenRetries != nil {
  478. retries = *config.LogFileReopenRetries
  479. }
  480. create := false
  481. mode := os.FileMode(0)
  482. if config.LogFileCreateMode != nil {
  483. create = true
  484. mode = os.FileMode(*config.LogFileCreateMode)
  485. }
  486. return retries, create, mode
  487. }
  488. // RunLoadMonitor indicates whether to monitor and log server load.
  489. func (config *Config) RunLoadMonitor() bool {
  490. return config.LoadMonitorPeriodSeconds > 0
  491. }
  492. // RunPeriodicGarbageCollection indicates whether to run periodic garbage collection.
  493. func (config *Config) RunPeriodicGarbageCollection() bool {
  494. return config.periodicGarbageCollection > 0
  495. }
  496. // DumpProfilesOnStopEstablishTunnels indicates whether dump profiles due to
  497. // an unexpectedly low number of established clients during high load.
  498. func (config *Config) DumpProfilesOnStopEstablishTunnels(establishedClientsCount int) bool {
  499. if config.stopEstablishTunnelsEstablishedClientThreshold < 0 {
  500. return false
  501. }
  502. if config.runningOnlyInproxyBroker {
  503. // There will always be zero established clients when running only the
  504. // in-proxy broker and no tunnel protocols.
  505. return false
  506. }
  507. if atomic.LoadInt32(&config.dumpProfilesOnStopEstablishTunnelsDoneOnce) != 0 {
  508. return false
  509. }
  510. dump := (establishedClientsCount <= config.stopEstablishTunnelsEstablishedClientThreshold)
  511. if dump {
  512. atomic.StoreInt32(&config.dumpProfilesOnStopEstablishTunnelsDoneOnce, 1)
  513. }
  514. return dump
  515. }
  516. // GetOwnEncodedServerEntry returns one of the server's own server entries, as
  517. // identified by the server entry tag.
  518. func (config *Config) GetOwnEncodedServerEntry(serverEntryTag string) (string, bool) {
  519. serverEntry, ok := config.OwnEncodedServerEntries[serverEntryTag]
  520. return serverEntry, ok
  521. }
  522. // GetProviderID returns the provider ID associated with the server.
  523. func (config *Config) GetProviderID() string {
  524. return config.providerID
  525. }
  526. // GetFrontingProviderID returns the fronting provider ID associated with the
  527. // server's fronted protocol(s).
  528. func (config *Config) GetFrontingProviderID() string {
  529. return config.frontingProviderID
  530. }
  531. // GetRegion returns the region associated with the server.
  532. func (config *Config) GetRegion() string {
  533. return config.region
  534. }
  535. // GetRunningProtocols returns the list of protcols this server is running.
  536. // The caller must not mutate the return value.
  537. func (config *Config) GetRunningProtocols() []string {
  538. return config.runningProtocols
  539. }
  540. // GetRunningOnlyInproxyBroker indicates if the server is running only the
  541. // in-proxy broker and no tunnel protocols.
  542. func (config *Config) GetRunningOnlyInproxyBroker() bool {
  543. return config.runningOnlyInproxyBroker
  544. }
  545. // LoadConfig loads and validates a JSON encoded server config.
  546. func LoadConfig(configJSON []byte) (*Config, error) {
  547. var config Config
  548. err := json.Unmarshal(configJSON, &config)
  549. if err != nil {
  550. return nil, errors.Trace(err)
  551. }
  552. if config.ServerIPAddress == "" {
  553. return nil, errors.TraceNew("ServerIPAddress is required")
  554. }
  555. if config.MeekServerRunInproxyBroker {
  556. if config.InproxyBrokerSessionPrivateKey == "" {
  557. return nil, errors.TraceNew("Inproxy Broker requires InproxyBrokerSessionPrivateKey")
  558. }
  559. if config.InproxyBrokerObfuscationRootSecret == "" {
  560. return nil, errors.TraceNew("Inproxy Broker requires InproxyBrokerObfuscationRootSecret")
  561. }
  562. // There must be at least one meek tunnel protocol configured for
  563. // MeekServer to run and host an in-proxy broker. Since each
  564. // MeekServer instance runs its own in-proxy Broker instance, allow
  565. // at most one meek tunnel protocol to be configured so all
  566. // connections to the broker use the same, unambiguous instance.
  567. meekServerCount := 0
  568. for tunnelProtocol := range config.TunnelProtocolPorts {
  569. if protocol.TunnelProtocolUsesMeek(tunnelProtocol) {
  570. meekServerCount += 1
  571. }
  572. }
  573. if meekServerCount != 1 {
  574. return nil, errors.TraceNew("Inproxy Broker requires one MeekServer instance")
  575. }
  576. }
  577. if config.MeekServerInproxyBrokerOnly {
  578. if !config.MeekServerRunInproxyBroker {
  579. return nil, errors.TraceNew("Inproxy Broker-only mode requires MeekServerRunInproxyBroker")
  580. }
  581. }
  582. if config.ObfuscatedSSHKey != "" {
  583. // Any SSHServerVersion selected here will take precedence over a
  584. // value specified in the JSON config. Furthermore, the JSON config
  585. // may omit SSHServerVersion as long as ObfuscatedSSHKey is specified
  586. // and a value is selected.
  587. seed, err := protocol.DeriveSSHServerVersionPRNGSeed(config.ObfuscatedSSHKey)
  588. if err != nil {
  589. return nil, errors.Tracef(
  590. "DeriveSSHServerVersionPRNGSeed failed: %s", err)
  591. }
  592. serverVersion := values.GetSSHServerVersion(seed)
  593. if serverVersion != "" {
  594. config.SSHServerVersion = serverVersion
  595. }
  596. }
  597. config.runningProtocols = []string{}
  598. config.runningOnlyInproxyBroker = config.MeekServerRunInproxyBroker
  599. for tunnelProtocol := range config.TunnelProtocolPorts {
  600. if !common.Contains(protocol.SupportedTunnelProtocols, tunnelProtocol) {
  601. return nil, errors.Tracef("Unsupported tunnel protocol: %s", tunnelProtocol)
  602. }
  603. if config.MeekServerInproxyBrokerOnly && protocol.TunnelProtocolUsesMeek(tunnelProtocol) {
  604. // In in-proxy broker-only mode, the TunnelProtocolPorts must be
  605. // specified in order to run the MeekServer, but none of the
  606. // following meek tunnel parameters are required.
  607. continue
  608. }
  609. if protocol.TunnelProtocolUsesInproxy(tunnelProtocol) && !inproxy.Enabled() {
  610. // Note that, technically, it may be possible to allow this case,
  611. // since PSIPHON_ENABLE_INPROXY is currently required only for
  612. // client/proxy-side WebRTC functionality, although that could change.
  613. return nil, errors.TraceNew("inproxy implementation is not enabled")
  614. }
  615. if protocol.TunnelProtocolUsesSSH(tunnelProtocol) ||
  616. protocol.TunnelProtocolUsesObfuscatedSSH(tunnelProtocol) {
  617. if config.SSHPrivateKey == "" || config.SSHServerVersion == "" ||
  618. config.SSHUserName == "" || config.SSHPassword == "" {
  619. return nil, errors.Tracef(
  620. "Tunnel protocol %s requires SSHPrivateKey, SSHServerVersion, SSHUserName, SSHPassword",
  621. tunnelProtocol)
  622. }
  623. }
  624. if protocol.TunnelProtocolUsesObfuscatedSSH(tunnelProtocol) {
  625. if config.ObfuscatedSSHKey == "" {
  626. return nil, errors.Tracef(
  627. "Tunnel protocol %s requires ObfuscatedSSHKey",
  628. tunnelProtocol)
  629. }
  630. }
  631. if protocol.TunnelProtocolUsesTLSOSSH(tunnelProtocol) {
  632. // Meek obfuscated key used for legacy reasons. See comment for
  633. // MeekObfuscatedKey.
  634. if config.MeekObfuscatedKey == "" {
  635. return nil, errors.Tracef(
  636. "Tunnel protocol %s requires MeekObfuscatedKey",
  637. tunnelProtocol)
  638. }
  639. }
  640. if protocol.TunnelProtocolUsesMeekHTTP(tunnelProtocol) ||
  641. protocol.TunnelProtocolUsesMeekHTTPS(tunnelProtocol) {
  642. if config.MeekCookieEncryptionPrivateKey == "" || config.MeekObfuscatedKey == "" {
  643. return nil, errors.Tracef(
  644. "Tunnel protocol %s requires MeekCookieEncryptionPrivateKey, MeekObfuscatedKey",
  645. tunnelProtocol)
  646. }
  647. }
  648. // For FRONTED QUIC and HTTP, HTTPS is always used on the
  649. // edge-to-server hop, so it must be enabled or else this
  650. // configuration will not work. There is no FRONTED QUIC listener at
  651. // all; see TunnelServer.Run.
  652. if protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) {
  653. _, ok := config.TunnelProtocolPorts[protocol.TUNNEL_PROTOCOL_FRONTED_MEEK]
  654. if !ok {
  655. return nil, errors.Tracef(
  656. "Tunnel protocol %s requires %s to be enabled",
  657. tunnelProtocol,
  658. protocol.TUNNEL_PROTOCOL_FRONTED_MEEK)
  659. }
  660. }
  661. config.runningProtocols = append(config.runningProtocols, tunnelProtocol)
  662. config.runningOnlyInproxyBroker = false
  663. }
  664. for tunnelProtocol, address := range config.TunnelProtocolPassthroughAddresses {
  665. if !protocol.TunnelProtocolSupportsPassthrough(tunnelProtocol) {
  666. return nil, errors.Tracef("Passthrough unsupported tunnel protocol: %s", tunnelProtocol)
  667. }
  668. if _, _, err := net.SplitHostPort(address); err != nil {
  669. if err != nil {
  670. return nil, errors.Tracef(
  671. "Tunnel protocol %s passthrough address %s invalid: %s",
  672. tunnelProtocol, address, err)
  673. }
  674. }
  675. }
  676. config.sshBeginHandshakeTimeout = SSH_BEGIN_HANDSHAKE_TIMEOUT
  677. if config.SSHBeginHandshakeTimeoutMilliseconds != nil {
  678. config.sshBeginHandshakeTimeout = time.Duration(*config.SSHBeginHandshakeTimeoutMilliseconds) * time.Millisecond
  679. }
  680. config.sshHandshakeTimeout = SSH_HANDSHAKE_TIMEOUT
  681. if config.SSHHandshakeTimeoutMilliseconds != nil {
  682. config.sshHandshakeTimeout = time.Duration(*config.SSHHandshakeTimeoutMilliseconds) * time.Millisecond
  683. }
  684. if config.UDPInterceptUdpgwServerAddress != "" {
  685. if err := validateNetworkAddress(config.UDPInterceptUdpgwServerAddress, true); err != nil {
  686. return nil, errors.Tracef("UDPInterceptUdpgwServerAddress is invalid: %s", err)
  687. }
  688. }
  689. if config.DNSResolverIPAddress != "" {
  690. if net.ParseIP(config.DNSResolverIPAddress) == nil {
  691. return nil, errors.Tracef("DNSResolverIPAddress is invalid")
  692. }
  693. }
  694. config.peakUpstreamFailureRateMinimumSampleSize = PEAK_UPSTREAM_FAILURE_RATE_MINIMUM_SAMPLE_SIZE
  695. if config.PeakUpstreamFailureRateMinimumSampleSize != nil {
  696. config.peakUpstreamFailureRateMinimumSampleSize = *config.PeakUpstreamFailureRateMinimumSampleSize
  697. }
  698. config.periodicGarbageCollection = PERIODIC_GARBAGE_COLLECTION
  699. if config.PeriodicGarbageCollectionSeconds != nil {
  700. config.periodicGarbageCollection = time.Duration(*config.PeriodicGarbageCollectionSeconds) * time.Second
  701. }
  702. config.stopEstablishTunnelsEstablishedClientThreshold = STOP_ESTABLISH_TUNNELS_ESTABLISHED_CLIENT_THRESHOLD
  703. if config.StopEstablishTunnelsEstablishedClientThreshold != nil {
  704. config.stopEstablishTunnelsEstablishedClientThreshold = *config.StopEstablishTunnelsEstablishedClientThreshold
  705. }
  706. if config.AccessControlVerificationKeyRing != nil {
  707. err = accesscontrol.ValidateVerificationKeyRing(config.AccessControlVerificationKeyRing)
  708. if err != nil {
  709. return nil, errors.Tracef(
  710. "AccessControlVerificationKeyRing is invalid: %s", err)
  711. }
  712. }
  713. // Limitation: the following is a shortcut which extracts the server's
  714. // fronting provider ID from the server's OwnEncodedServerEntries. This logic
  715. // assumes a server has only one fronting provider. In principle, it's
  716. // possible for server with multiple server entries to run multiple fronted
  717. // protocols, each with a different fronting provider ID.
  718. //
  719. // TODO: add an explicit parameter mapping tunnel protocol ports to fronting
  720. // provider IDs.
  721. for _, encodedServerEntry := range config.OwnEncodedServerEntries {
  722. serverEntry, err := protocol.DecodeServerEntry(encodedServerEntry, "", "")
  723. if err != nil {
  724. return nil, errors.Tracef(
  725. "protocol.DecodeServerEntry failed: %s", err)
  726. }
  727. if config.providerID == "" {
  728. config.providerID = serverEntry.ProviderID
  729. } else if config.providerID != serverEntry.ProviderID {
  730. return nil, errors.Tracef("unsupported multiple ProviderID values")
  731. }
  732. if config.frontingProviderID == "" {
  733. config.frontingProviderID = serverEntry.FrontingProviderID
  734. } else if config.frontingProviderID != serverEntry.FrontingProviderID {
  735. return nil, errors.Tracef("unsupported multiple FrontingProviderID values")
  736. }
  737. if config.region == "" {
  738. config.region = serverEntry.Region
  739. } else if config.region != serverEntry.Region {
  740. return nil, errors.Tracef("unsupported multiple Region values")
  741. }
  742. }
  743. return &config, nil
  744. }
  745. func validateNetworkAddress(address string, requireIPaddress bool) error {
  746. host, portStr, err := net.SplitHostPort(address)
  747. if err != nil {
  748. return err
  749. }
  750. if requireIPaddress && net.ParseIP(host) == nil {
  751. return errors.TraceNew("host must be an IP address")
  752. }
  753. port, err := strconv.Atoi(portStr)
  754. if err != nil {
  755. return err
  756. }
  757. if port < 0 || port > 65535 {
  758. return errors.TraceNew("invalid port")
  759. }
  760. return nil
  761. }
  762. // GenerateConfigParams specifies customizations to be applied to
  763. // a generated server config.
  764. type GenerateConfigParams struct {
  765. LogFilename string
  766. SkipPanickingLogWriter bool
  767. LogLevel string
  768. ServerEntrySignaturePublicKey string
  769. ServerEntrySignaturePrivateKey string
  770. ServerIPAddress string
  771. TunnelProtocolPorts map[string]int
  772. TunnelProtocolPassthroughAddresses map[string]string
  773. TrafficRulesConfigFilename string
  774. OSLConfigFilename string
  775. TacticsConfigFilename string
  776. TacticsRequestPublicKey string
  777. TacticsRequestObfuscatedKey string
  778. Passthrough bool
  779. LegacyPassthrough bool
  780. LimitQUICVersions protocol.QUICVersions
  781. EnableGQUIC bool
  782. FrontingProviderID string
  783. }
  784. // GenerateConfig creates a new Psiphon server config. It returns JSON encoded
  785. // configs and a client-compatible "server entry" for the server. It generates
  786. // all necessary secrets and key material, which are emitted in the config
  787. // file and server entry as necessary.
  788. //
  789. // GenerateConfig uses sample values for many fields. The intention is for
  790. // generated configs to be used for testing or as examples for production
  791. // setup, not to generate production-ready configurations.
  792. //
  793. // When tactics key material is provided in GenerateConfigParams, tactics
  794. // capabilities are added for all meek protocols in TunnelProtocolPorts.
  795. func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, []byte, []byte, []byte, error) {
  796. // Input validation
  797. if net.ParseIP(params.ServerIPAddress) == nil {
  798. return nil, nil, nil, nil, nil, errors.TraceNew("invalid IP address")
  799. }
  800. if len(params.TunnelProtocolPorts) == 0 {
  801. return nil, nil, nil, nil, nil, errors.TraceNew("no tunnel protocols")
  802. }
  803. usedPort := make(map[int]bool)
  804. usingMeek := false
  805. usingTLSOSSH := false
  806. usingInproxy := false
  807. for tunnelProtocol, port := range params.TunnelProtocolPorts {
  808. if !common.Contains(protocol.SupportedTunnelProtocols, tunnelProtocol) {
  809. return nil, nil, nil, nil, nil, errors.TraceNew("invalid tunnel protocol")
  810. }
  811. if usedPort[port] {
  812. return nil, nil, nil, nil, nil, errors.TraceNew("duplicate listening port")
  813. }
  814. usedPort[port] = true
  815. if protocol.TunnelProtocolUsesTLSOSSH(tunnelProtocol) {
  816. usingTLSOSSH = true
  817. }
  818. if protocol.TunnelProtocolUsesMeekHTTP(tunnelProtocol) ||
  819. protocol.TunnelProtocolUsesMeekHTTPS(tunnelProtocol) {
  820. usingMeek = true
  821. }
  822. if protocol.TunnelProtocolUsesInproxy(tunnelProtocol) {
  823. usingInproxy = true
  824. }
  825. }
  826. // One test mode populates the tactics config file; this will generate
  827. // keys. Another test mode passes in existing keys to be used in the
  828. // server entry. Both the filename and existing keys cannot be passed in.
  829. if (params.TacticsConfigFilename != "") &&
  830. (params.TacticsRequestPublicKey != "" || params.TacticsRequestObfuscatedKey != "") {
  831. return nil, nil, nil, nil, nil, errors.TraceNew("invalid tactics parameters")
  832. }
  833. // SSH config
  834. rsaKey, err := rsa.GenerateKey(rand.Reader, SSH_RSA_HOST_KEY_BITS)
  835. if err != nil {
  836. return nil, nil, nil, nil, nil, errors.Trace(err)
  837. }
  838. sshPrivateKey := pem.EncodeToMemory(
  839. &pem.Block{
  840. Type: "RSA PRIVATE KEY",
  841. Bytes: x509.MarshalPKCS1PrivateKey(rsaKey),
  842. },
  843. )
  844. signer, err := ssh.NewSignerFromKey(rsaKey)
  845. if err != nil {
  846. return nil, nil, nil, nil, nil, errors.Trace(err)
  847. }
  848. sshPublicKey := signer.PublicKey()
  849. sshUserNameSuffixBytes, err := common.MakeSecureRandomBytes(SSH_USERNAME_SUFFIX_BYTE_LENGTH)
  850. if err != nil {
  851. return nil, nil, nil, nil, nil, errors.Trace(err)
  852. }
  853. sshUserNameSuffix := hex.EncodeToString(sshUserNameSuffixBytes)
  854. sshUserName := "psiphon_" + sshUserNameSuffix
  855. sshPasswordBytes, err := common.MakeSecureRandomBytes(SSH_PASSWORD_BYTE_LENGTH)
  856. if err != nil {
  857. return nil, nil, nil, nil, nil, errors.Trace(err)
  858. }
  859. sshPassword := hex.EncodeToString(sshPasswordBytes)
  860. sshServerVersion := "SSH-2.0-Psiphon"
  861. // Obfuscated SSH config
  862. obfuscatedSSHKeyBytes, err := common.MakeSecureRandomBytes(SSH_OBFUSCATED_KEY_BYTE_LENGTH)
  863. if err != nil {
  864. return nil, nil, nil, nil, nil, errors.Trace(err)
  865. }
  866. obfuscatedSSHKey := hex.EncodeToString(obfuscatedSSHKeyBytes)
  867. // Shadowsocks config
  868. shadowsocksKeyBytes, err := common.MakeSecureRandomBytes(SHADOWSOCKS_KEY_BYTE_LENGTH)
  869. if err != nil {
  870. return nil, nil, nil, nil, nil, errors.Trace(err)
  871. }
  872. shadowsocksKey := hex.EncodeToString(shadowsocksKeyBytes)
  873. // Meek config
  874. var meekCookieEncryptionPublicKey, meekCookieEncryptionPrivateKey, meekObfuscatedKey string
  875. if usingMeek {
  876. rawMeekCookieEncryptionPublicKey, rawMeekCookieEncryptionPrivateKey, err :=
  877. box.GenerateKey(rand.Reader)
  878. if err != nil {
  879. return nil, nil, nil, nil, nil, errors.Trace(err)
  880. }
  881. meekCookieEncryptionPublicKey = base64.StdEncoding.EncodeToString(rawMeekCookieEncryptionPublicKey[:])
  882. meekCookieEncryptionPrivateKey = base64.StdEncoding.EncodeToString(rawMeekCookieEncryptionPrivateKey[:])
  883. }
  884. if usingMeek || usingTLSOSSH {
  885. meekObfuscatedKeyBytes, err := common.MakeSecureRandomBytes(SSH_OBFUSCATED_KEY_BYTE_LENGTH)
  886. if err != nil {
  887. return nil, nil, nil, nil, nil, errors.Trace(err)
  888. }
  889. meekObfuscatedKey = hex.EncodeToString(meekObfuscatedKeyBytes)
  890. }
  891. // Inproxy config
  892. var inproxyServerSessionPublicKey,
  893. inproxyServerSessionPrivateKey,
  894. inproxyServerObfuscationRootSecret string
  895. if usingInproxy {
  896. privateKey, err := inproxy.GenerateSessionPrivateKey()
  897. if err != nil {
  898. return nil, nil, nil, nil, nil, errors.Trace(err)
  899. }
  900. inproxyServerSessionPrivateKey = privateKey.String()
  901. publicKey, err := privateKey.GetPublicKey()
  902. if err != nil {
  903. return nil, nil, nil, nil, nil, errors.Trace(err)
  904. }
  905. inproxyServerSessionPublicKey = publicKey.String()
  906. obfuscationRootSecret, err := inproxy.GenerateRootObfuscationSecret()
  907. if err != nil {
  908. return nil, nil, nil, nil, nil, errors.Trace(err)
  909. }
  910. inproxyServerObfuscationRootSecret = obfuscationRootSecret.String()
  911. }
  912. // Other config
  913. discoveryValueHMACKeyBytes, err := common.MakeSecureRandomBytes(DISCOVERY_VALUE_KEY_BYTE_LENGTH)
  914. if err != nil {
  915. return nil, nil, nil, nil, nil, errors.Trace(err)
  916. }
  917. discoveryValueHMACKey := base64.StdEncoding.EncodeToString(discoveryValueHMACKeyBytes)
  918. // Generate a legacy web server secret, to accomodate test cases, such as deriving
  919. // a server entry tag when no tag is present.
  920. webServerSecretBytes, err := common.MakeSecureRandomBytes(WEB_SERVER_SECRET_BYTE_LENGTH)
  921. if err != nil {
  922. return nil, nil, nil, nil, nil, errors.Trace(err)
  923. }
  924. webServerSecret := hex.EncodeToString(webServerSecretBytes)
  925. // Assemble configs and server entry
  926. // Note: this config is intended for either testing or as an illustrative
  927. // example or template and is not intended for production deployment.
  928. logLevel := params.LogLevel
  929. if logLevel == "" {
  930. logLevel = "info"
  931. }
  932. // For testing, set the Psiphon server to create its log files; we do not
  933. // expect tests to necessarily run under log managers, such as logrotate.
  934. createMode := 0666
  935. config := &Config{
  936. LogLevel: logLevel,
  937. LogFilename: params.LogFilename,
  938. LogFileCreateMode: &createMode,
  939. SkipPanickingLogWriter: params.SkipPanickingLogWriter,
  940. GeoIPDatabaseFilenames: nil,
  941. HostID: "example-host-id",
  942. ServerIPAddress: params.ServerIPAddress,
  943. DiscoveryValueHMACKey: discoveryValueHMACKey,
  944. SSHPrivateKey: string(sshPrivateKey),
  945. SSHServerVersion: sshServerVersion,
  946. SSHUserName: sshUserName,
  947. SSHPassword: sshPassword,
  948. ShadowsocksKey: shadowsocksKey,
  949. ObfuscatedSSHKey: obfuscatedSSHKey,
  950. TunnelProtocolPorts: params.TunnelProtocolPorts,
  951. TunnelProtocolPassthroughAddresses: params.TunnelProtocolPassthroughAddresses,
  952. DNSResolverIPAddress: "8.8.8.8",
  953. UDPInterceptUdpgwServerAddress: "127.0.0.1:7300",
  954. MeekCookieEncryptionPrivateKey: meekCookieEncryptionPrivateKey,
  955. MeekObfuscatedKey: meekObfuscatedKey,
  956. MeekProhibitedHeaders: nil,
  957. MeekProxyForwardedForHeaders: []string{"X-Forwarded-For"},
  958. LoadMonitorPeriodSeconds: 300,
  959. TrafficRulesFilename: params.TrafficRulesConfigFilename,
  960. OSLConfigFilename: params.OSLConfigFilename,
  961. TacticsConfigFilename: params.TacticsConfigFilename,
  962. LegacyPassthrough: params.LegacyPassthrough,
  963. EnableGQUIC: params.EnableGQUIC,
  964. InproxyServerSessionPrivateKey: inproxyServerSessionPrivateKey,
  965. InproxyServerObfuscationRootSecret: inproxyServerObfuscationRootSecret,
  966. }
  967. encodedConfig, err := json.MarshalIndent(config, "\n", " ")
  968. if err != nil {
  969. return nil, nil, nil, nil, nil, errors.Trace(err)
  970. }
  971. intPtr := func(i int) *int {
  972. return &i
  973. }
  974. trafficRulesSet := &TrafficRulesSet{
  975. DefaultRules: TrafficRules{
  976. RateLimits: RateLimits{
  977. ReadUnthrottledBytes: new(int64),
  978. ReadBytesPerSecond: new(int64),
  979. WriteUnthrottledBytes: new(int64),
  980. WriteBytesPerSecond: new(int64),
  981. },
  982. IdleTCPPortForwardTimeoutMilliseconds: intPtr(DEFAULT_IDLE_TCP_PORT_FORWARD_TIMEOUT_MILLISECONDS),
  983. IdleUDPPortForwardTimeoutMilliseconds: intPtr(DEFAULT_IDLE_UDP_PORT_FORWARD_TIMEOUT_MILLISECONDS),
  984. MaxTCPPortForwardCount: intPtr(DEFAULT_MAX_TCP_PORT_FORWARD_COUNT),
  985. MaxUDPPortForwardCount: intPtr(DEFAULT_MAX_UDP_PORT_FORWARD_COUNT),
  986. AllowTCPPorts: nil,
  987. AllowUDPPorts: nil,
  988. },
  989. }
  990. encodedTrafficRulesSet, err := json.MarshalIndent(trafficRulesSet, "\n", " ")
  991. if err != nil {
  992. return nil, nil, nil, nil, nil, errors.Trace(err)
  993. }
  994. encodedOSLConfig, err := json.MarshalIndent(&osl.Config{}, "\n", " ")
  995. if err != nil {
  996. return nil, nil, nil, nil, nil, errors.Trace(err)
  997. }
  998. tacticsRequestPublicKey := params.TacticsRequestPublicKey
  999. tacticsRequestObfuscatedKey := params.TacticsRequestObfuscatedKey
  1000. var tacticsRequestPrivateKey string
  1001. var encodedTacticsConfig []byte
  1002. if params.TacticsConfigFilename != "" {
  1003. tacticsRequestPublicKey, tacticsRequestPrivateKey, tacticsRequestObfuscatedKey, err =
  1004. tactics.GenerateKeys()
  1005. if err != nil {
  1006. return nil, nil, nil, nil, nil, errors.Trace(err)
  1007. }
  1008. decodedTacticsRequestPublicKey, err := base64.StdEncoding.DecodeString(tacticsRequestPublicKey)
  1009. if err != nil {
  1010. return nil, nil, nil, nil, nil, errors.Trace(err)
  1011. }
  1012. decodedTacticsRequestPrivateKey, err := base64.StdEncoding.DecodeString(tacticsRequestPrivateKey)
  1013. if err != nil {
  1014. return nil, nil, nil, nil, nil, errors.Trace(err)
  1015. }
  1016. decodedTacticsRequestObfuscatedKey, err := base64.StdEncoding.DecodeString(tacticsRequestObfuscatedKey)
  1017. if err != nil {
  1018. return nil, nil, nil, nil, nil, errors.Trace(err)
  1019. }
  1020. tacticsConfig := &tactics.Server{
  1021. RequestPublicKey: decodedTacticsRequestPublicKey,
  1022. RequestPrivateKey: decodedTacticsRequestPrivateKey,
  1023. RequestObfuscatedKey: decodedTacticsRequestObfuscatedKey,
  1024. DefaultTactics: tactics.Tactics{
  1025. TTL: "1m",
  1026. },
  1027. }
  1028. encodedTacticsConfig, err = json.MarshalIndent(tacticsConfig, "\n", " ")
  1029. if err != nil {
  1030. return nil, nil, nil, nil, nil, errors.Trace(err)
  1031. }
  1032. }
  1033. // Capabilities
  1034. capabilities := []string{protocol.CAPABILITY_SSH_API_REQUESTS}
  1035. var frontingProviderID string
  1036. for tunnelProtocol := range params.TunnelProtocolPorts {
  1037. capability := protocol.GetCapability(tunnelProtocol)
  1038. // In-proxy tunnel protocol capabilities don't include
  1039. // v1/-PASSTHROUGHv2 suffixes; see comments in ServerEntry.hasCapability.
  1040. if !protocol.TunnelProtocolUsesInproxy(tunnelProtocol) {
  1041. // Note: do not add passthrough annotation if HTTP unfronted meek
  1042. // because it would result in an invalid capability.
  1043. if params.Passthrough &&
  1044. protocol.TunnelProtocolSupportsPassthrough(tunnelProtocol) &&
  1045. tunnelProtocol != protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK {
  1046. if !params.LegacyPassthrough {
  1047. capability += "-PASSTHROUGH-v2"
  1048. } else {
  1049. capability += "-PASSTHROUGH"
  1050. }
  1051. }
  1052. if tunnelProtocol == protocol.TUNNEL_PROTOCOL_QUIC_OBFUSCATED_SSH &&
  1053. !params.EnableGQUIC {
  1054. capability += "v1"
  1055. }
  1056. }
  1057. capabilities = append(capabilities, capability)
  1058. if params.TacticsRequestPublicKey != "" && params.TacticsRequestObfuscatedKey != "" &&
  1059. protocol.TunnelProtocolSupportsTactics(tunnelProtocol) {
  1060. capabilities = append(capabilities, protocol.GetTacticsCapability(tunnelProtocol))
  1061. }
  1062. if protocol.TunnelProtocolUsesFrontedMeek(tunnelProtocol) {
  1063. frontingProviderID = params.FrontingProviderID
  1064. }
  1065. }
  1066. // Tunnel protocol ports
  1067. // Limitations:
  1068. // - Only one meek port may be specified per server entry.
  1069. // - Neither fronted meek nor Conjuure protocols are supported here.
  1070. var sshPort, obfuscatedSSHPort, meekPort, obfuscatedSSHQUICPort, tlsOSSHPort, shadowsocksPort int
  1071. var inproxySSHPort, inproxyOSSHPort, inproxyQUICPort, inproxyMeekPort, inproxyTlsOSSHPort, inproxyShadowsocksPort int
  1072. for tunnelProtocol, port := range params.TunnelProtocolPorts {
  1073. if !protocol.TunnelProtocolUsesInproxy(tunnelProtocol) {
  1074. switch tunnelProtocol {
  1075. case protocol.TUNNEL_PROTOCOL_TLS_OBFUSCATED_SSH:
  1076. tlsOSSHPort = port
  1077. case protocol.TUNNEL_PROTOCOL_SSH:
  1078. sshPort = port
  1079. case protocol.TUNNEL_PROTOCOL_OBFUSCATED_SSH:
  1080. obfuscatedSSHPort = port
  1081. case protocol.TUNNEL_PROTOCOL_QUIC_OBFUSCATED_SSH:
  1082. obfuscatedSSHQUICPort = port
  1083. case protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_HTTPS,
  1084. protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_SESSION_TICKET,
  1085. protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK:
  1086. meekPort = port
  1087. case protocol.TUNNEL_PROTOCOL_SHADOWSOCKS_OSSH:
  1088. shadowsocksPort = port
  1089. }
  1090. } else {
  1091. switch protocol.TunnelProtocolMinusInproxy(tunnelProtocol) {
  1092. case protocol.TUNNEL_PROTOCOL_TLS_OBFUSCATED_SSH:
  1093. inproxyTlsOSSHPort = port
  1094. case protocol.TUNNEL_PROTOCOL_SSH:
  1095. inproxySSHPort = port
  1096. case protocol.TUNNEL_PROTOCOL_OBFUSCATED_SSH:
  1097. inproxyOSSHPort = port
  1098. case protocol.TUNNEL_PROTOCOL_QUIC_OBFUSCATED_SSH:
  1099. inproxyQUICPort = port
  1100. case protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_HTTPS,
  1101. protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK_SESSION_TICKET,
  1102. protocol.TUNNEL_PROTOCOL_UNFRONTED_MEEK:
  1103. inproxyMeekPort = port
  1104. case protocol.TUNNEL_PROTOCOL_SHADOWSOCKS_OSSH:
  1105. inproxyShadowsocksPort = port
  1106. }
  1107. }
  1108. }
  1109. // Note: fronting params are a stub; this server entry will exercise
  1110. // client and server fronting code paths, but not actually traverse
  1111. // a fronting hop.
  1112. serverEntry := &protocol.ServerEntry{
  1113. Tag: prng.Base64String(32),
  1114. IpAddress: params.ServerIPAddress,
  1115. WebServerSecret: webServerSecret,
  1116. TlsOSSHPort: tlsOSSHPort,
  1117. SshPort: sshPort,
  1118. SshUsername: sshUserName,
  1119. SshPassword: sshPassword,
  1120. SshHostKey: base64.StdEncoding.EncodeToString(sshPublicKey.Marshal()),
  1121. SshObfuscatedPort: obfuscatedSSHPort,
  1122. SshObfuscatedQUICPort: obfuscatedSSHQUICPort,
  1123. SshShadowsocksKey: shadowsocksKey,
  1124. SshShadowsocksPort: shadowsocksPort,
  1125. LimitQUICVersions: params.LimitQUICVersions,
  1126. SshObfuscatedKey: obfuscatedSSHKey,
  1127. Capabilities: capabilities,
  1128. Region: "US",
  1129. ProviderID: strings.ToUpper(prng.HexString(8)),
  1130. FrontingProviderID: frontingProviderID,
  1131. MeekServerPort: meekPort,
  1132. MeekCookieEncryptionPublicKey: meekCookieEncryptionPublicKey,
  1133. MeekObfuscatedKey: meekObfuscatedKey,
  1134. MeekFrontingHosts: []string{params.ServerIPAddress},
  1135. MeekFrontingAddresses: []string{params.ServerIPAddress},
  1136. MeekFrontingDisableSNI: false,
  1137. TacticsRequestPublicKey: tacticsRequestPublicKey,
  1138. TacticsRequestObfuscatedKey: tacticsRequestObfuscatedKey,
  1139. ConfigurationVersion: 1,
  1140. InproxySessionPublicKey: inproxyServerSessionPublicKey,
  1141. InproxySessionRootObfuscationSecret: inproxyServerObfuscationRootSecret,
  1142. InproxySSHPort: inproxySSHPort,
  1143. InproxyOSSHPort: inproxyOSSHPort,
  1144. InproxyQUICPort: inproxyQUICPort,
  1145. InproxyMeekPort: inproxyMeekPort,
  1146. InproxyTlsOSSHPort: inproxyTlsOSSHPort,
  1147. InproxyShadowsocksPort: inproxyShadowsocksPort,
  1148. }
  1149. if params.ServerEntrySignaturePublicKey != "" {
  1150. serverEntryJSON, err := json.Marshal(serverEntry)
  1151. if err != nil {
  1152. return nil, nil, nil, nil, nil, errors.Trace(err)
  1153. }
  1154. var serverEntryFields protocol.ServerEntryFields
  1155. err = json.Unmarshal(serverEntryJSON, &serverEntryFields)
  1156. if err != nil {
  1157. return nil, nil, nil, nil, nil, errors.Trace(err)
  1158. }
  1159. err = serverEntryFields.AddSignature(
  1160. params.ServerEntrySignaturePublicKey, params.ServerEntrySignaturePrivateKey)
  1161. if err != nil {
  1162. return nil, nil, nil, nil, nil, errors.Trace(err)
  1163. }
  1164. serverEntry, err = serverEntryFields.GetServerEntry()
  1165. if err != nil {
  1166. return nil, nil, nil, nil, nil, errors.Trace(err)
  1167. }
  1168. }
  1169. encodedServerEntry, err := protocol.EncodeServerEntry(serverEntry)
  1170. if err != nil {
  1171. return nil, nil, nil, nil, nil, errors.Trace(err)
  1172. }
  1173. return encodedConfig, encodedTrafficRulesSet, encodedOSLConfig, encodedTacticsConfig, []byte(encodedServerEntry), nil
  1174. }