config.go 60 KB

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