server.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /*
  2. * Copyright (c) 2023, 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 inproxy
  20. import (
  21. "time"
  22. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  23. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  24. )
  25. // MaxRelayRoundTrips is a sanity/anti-DoS check against clients that attempt
  26. // to relay more packets than are required for both a session handshake and
  27. // application-level request round trip.
  28. const MaxRelayRoundTrips = 10
  29. // ServerBrokerSessions manages the secure sessions that handle
  30. // BrokerServerReports from brokers. Each in-proxy-capable Psiphon server
  31. // maintains a ServerBrokerSessions, with a set of established sessions for
  32. // each broker. Session messages are relayed between the broker and the
  33. // server by the client.
  34. //
  35. // ServerBrokerSessions runs a ProxyQualityReporter which sends proxy quality
  36. // reports back to the same brokers.
  37. type ServerBrokerSessions struct {
  38. config *ServerBrokerSessionsConfig
  39. sessions *ResponderSessions
  40. proxyQualityReporter *ProxyQualityReporter
  41. }
  42. // ServerBrokerSessionsConfig specifies the configuration for a
  43. // ServerBrokerSessions instance.
  44. type ServerBrokerSessionsConfig struct {
  45. // Logger provides a logging facility.
  46. Logger common.Logger
  47. // ServerPrivateKey is the server's session private key. It must
  48. // correspond to the server session public key that a broker finds in a
  49. // signed Psiphon server entry.
  50. ServerPrivateKey SessionPrivateKey
  51. // ServerRootObfuscationSecret is the server's root obfuscation secret, as
  52. // found in the server's signed Psiphon server entry.
  53. ServerRootObfuscationSecret ObfuscationSecret
  54. // BrokerPublicKeys specifies the public keys corresponding to known
  55. // brokers that are trusted to connect to the server; which are also the
  56. // brokers to which the server will send its proxy quality reports.
  57. BrokerPublicKeys []SessionPublicKey
  58. // BrokerRootObfuscationSecrets are the obfuscation secrets corresponding
  59. // to the entries in BrokerPublicKeys.
  60. BrokerRootObfuscationSecrets []ObfuscationSecret
  61. // BrokerRoundTripperMaker constructs round trip transports used to send
  62. // proxy quality requests to the specified broker.
  63. BrokerRoundTripperMaker ProxyQualityBrokerRoundTripperMaker
  64. // ProxyMetricsValidator is used to further validate the proxy metrics
  65. // fields relayed by the broker in broker server reports.
  66. ProxyMetricsValidator common.APIParameterValidator
  67. // ProxyMetricsValidator is used to log-format the proxy metrics fields
  68. // relayed by the broker in broker server reports.
  69. ProxyMetricsFormatter common.APIParameterLogFieldFormatter
  70. // ProxyMetricsPrefix specifies an optional prefix to be prepended to
  71. // proxy metric fields when logging.
  72. ProxyMetricsPrefix string
  73. }
  74. // NewServerBrokerSessions create a new ServerBrokerSessions, with the
  75. // specified key material. The expected brokers are authenticated with
  76. // brokerPublicKeys, an allow list.
  77. func NewServerBrokerSessions(
  78. config *ServerBrokerSessionsConfig) (*ServerBrokerSessions, error) {
  79. sessions, err := NewResponderSessionsForKnownInitiators(
  80. config.ServerPrivateKey,
  81. config.ServerRootObfuscationSecret,
  82. config.BrokerPublicKeys)
  83. if err != nil {
  84. return nil, errors.Trace(err)
  85. }
  86. s := &ServerBrokerSessions{
  87. config: config,
  88. sessions: sessions,
  89. }
  90. s.proxyQualityReporter, err = NewProxyQualityReporter(
  91. config.Logger,
  92. s,
  93. config.ServerPrivateKey,
  94. config.BrokerPublicKeys,
  95. config.BrokerRootObfuscationSecrets,
  96. config.BrokerRoundTripperMaker)
  97. if err != nil {
  98. return nil, errors.Trace(err)
  99. }
  100. return s, nil
  101. }
  102. // Start launches the proxy quality reporter.
  103. func (s *ServerBrokerSessions) Start() error {
  104. err := s.proxyQualityReporter.Start()
  105. if err != nil {
  106. return errors.Trace(err)
  107. }
  108. return nil
  109. }
  110. // Stop terminates the proxy quality reporter.
  111. func (s *ServerBrokerSessions) Stop() {
  112. s.proxyQualityReporter.Stop()
  113. }
  114. // SetKnownBrokers updates the set of broker public keys which are
  115. // allowed to establish sessions with the server. Any existing sessions with
  116. // keys not in the new list are deleted. Existing sessions with keys which
  117. // remain in the list are retained.
  118. //
  119. // The broker public keys also identify those brokers to which the proxy
  120. // quality reporter will send quality requests. The broker obfuscation
  121. // secrets are used by the reporter.
  122. func (s *ServerBrokerSessions) SetKnownBrokers(
  123. brokerPublicKeys []SessionPublicKey,
  124. brokerRootObfuscationSecrets []ObfuscationSecret) error {
  125. err := s.sessions.SetKnownInitiatorPublicKeys(
  126. brokerPublicKeys)
  127. if err != nil {
  128. return errors.Trace(err)
  129. }
  130. err = s.proxyQualityReporter.SetKnownBrokers(
  131. brokerPublicKeys, brokerRootObfuscationSecrets)
  132. if err != nil {
  133. return errors.Trace(err)
  134. }
  135. return nil
  136. }
  137. // SetProxyQualityRequestParameters overrides default values for proxy quality
  138. // reporter parameters.
  139. func (s *ServerBrokerSessions) SetProxyQualityRequestParameters(
  140. maxRequestEntries int,
  141. requestDelay time.Duration,
  142. requestTimeout time.Duration,
  143. requestRetries int) {
  144. s.proxyQualityReporter.SetRequestParameters(
  145. maxRequestEntries,
  146. requestDelay,
  147. requestTimeout,
  148. requestRetries)
  149. }
  150. // ReportQuality enqueues a proxy quality event in the proxy quality reporter.
  151. // See ProxyQualityReporter.ReportQuality for details.
  152. func (s *ServerBrokerSessions) ReportQuality(
  153. proxyID ID, proxyASN string, clientASN string) {
  154. s.proxyQualityReporter.ReportQuality(proxyID, proxyASN, clientASN)
  155. }
  156. // ProxiedConnectionHandler is a callback, provided by the Psiphon server,
  157. // that receives information from a BrokerServerReport for the client
  158. // associated with the callback.
  159. //
  160. // The server must use the brokerVerifiedOriginalClientIP for all GeoIP
  161. // operations associated with the client, including traffic rule selection
  162. // and client-side tactics selection.
  163. //
  164. // Since the BrokerServerReport may be delivered later than the Psiphon
  165. // handshake request -- in the case where the broker/server session needs to
  166. // be established there will be additional round trips -- the server should
  167. // delay traffic rule application, tactics responses, and allowing tunneled
  168. // traffic until after the ProxiedConnectionHandler callback is invoked for
  169. // the client. As a consequence, Psiphon Servers should be configured to
  170. // require Proxies to be used for designated protocols. It's expected that
  171. // server-side tactics such as packet manipulation will be applied based on
  172. // the proxy's IP address.
  173. //
  174. // The fields in logFields should be added to server_tunnel logs.
  175. type ProxiedConnectionHandler func(
  176. brokerVerifiedOriginalClientIP string,
  177. brokerReportedProxyID ID,
  178. brokerMatchedPersonalCompartments bool,
  179. logFields common.LogFields)
  180. // HandlePacket handles a broker/server session packet, which are relayed by
  181. // clients. In Psiphon, the packets may be exchanged in the Psiphon
  182. // handshake, or in subsequent SSH requests and responses. When the
  183. // broker/server session is already established, it's expected that the
  184. // BrokerServerReport arrives in the packet that accompanies the Psiphon
  185. // handshake, and so no additional round trip is required.
  186. //
  187. // Once the session is established and a verified BrokerServerReport arrives,
  188. // the information from that report is sent to the ProxiedConnectionHandler
  189. // callback. The callback should be associated with the client that is
  190. // relaying the packets.
  191. //
  192. // clientConnectionID is the in-proxy connection ID specified by the client in
  193. // its Psiphon handshake.
  194. //
  195. // When the retOut return value is not nil, it should be relayed back to the
  196. // client in the handshake response or other tunneled response. When retOut
  197. // is nil, the relay is complete.
  198. //
  199. // In the session reset token case, HandlePacket will return a non-nil retOut
  200. // along with a retErr; the server should both log retErr and also relay the
  201. // packet to the broker.
  202. func (s *ServerBrokerSessions) HandlePacket(
  203. logger common.Logger,
  204. in []byte,
  205. clientConnectionID ID,
  206. handler ProxiedConnectionHandler) (retOut []byte, retErr error) {
  207. handleUnwrappedReport := func(initiatorID ID, unwrappedReportPayload []byte) ([]byte, error) {
  208. brokerReport, err := UnmarshalBrokerServerReport(unwrappedReportPayload)
  209. if err != nil {
  210. return nil, errors.Trace(err)
  211. }
  212. logFields, err := brokerReport.ValidateAndGetLogFields(
  213. s.config.ProxyMetricsValidator,
  214. s.config.ProxyMetricsFormatter,
  215. s.config.ProxyMetricsPrefix)
  216. if err != nil {
  217. return nil, errors.Trace(err)
  218. }
  219. // The initiatorID is the broker's public key.
  220. logFields["inproxy_broker_id"] = initiatorID
  221. ok := true
  222. // The client must supply same connection ID to server that the broker
  223. // sends to the server.
  224. if brokerReport.ConnectionID != clientConnectionID {
  225. // Limitation: as the BrokerServerReport is a one-way message with
  226. // no response, the broker will not be notified of tunnel failure
  227. // errors including "connection ID mismatch", and cannot log this
  228. // connection attempt outcome.
  229. logger.WithTraceFields(common.LogFields{
  230. "client_inproxy_connection_id": clientConnectionID,
  231. "broker_inproxy_connection_id": brokerReport.ConnectionID,
  232. }).Error("connection ID mismatch")
  233. ok = false
  234. }
  235. if ok {
  236. handler(
  237. brokerReport.ClientIP,
  238. brokerReport.ProxyID,
  239. brokerReport.MatchedPersonalCompartments,
  240. logFields)
  241. }
  242. // Returns nil, as there is no response to the report, and so no
  243. // additional packet to relay.
  244. return nil, nil
  245. }
  246. out, err := s.sessions.HandlePacket(in, handleUnwrappedReport)
  247. return out, errors.Trace(err)
  248. }