server.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  22. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  23. )
  24. // MaxRelayRoundTrips is a sanity/anti-DoS check against clients that attempt
  25. // to relay more packets than are required for both a session handshake and
  26. // application-level request round trip.
  27. const MaxRelayRoundTrips = 10
  28. // ServerBrokerSessions manages the secure sessions that handle
  29. // BrokerServerReports from brokers. Each in-proxy-capable Psiphon server
  30. // maintains a ServerBrokerSessions, with a set of established sessions for
  31. // each broker. Session messages are relayed between the broker and the
  32. // server by the client.
  33. type ServerBrokerSessions struct {
  34. sessions *ResponderSessions
  35. }
  36. // NewServerBrokerSessions create a new ServerBrokerSessions, with the
  37. // specified key material. The expected brokers are authenticated with
  38. // brokerPublicKeys, an allow list.
  39. func NewServerBrokerSessions(
  40. serverPrivateKey SessionPrivateKey,
  41. serverRootObfuscationSecret ObfuscationSecret,
  42. brokerPublicKeys []SessionPublicKey) (*ServerBrokerSessions, error) {
  43. sessions, err := NewResponderSessionsForKnownInitiators(
  44. serverPrivateKey, serverRootObfuscationSecret, brokerPublicKeys)
  45. if err != nil {
  46. return nil, errors.Trace(err)
  47. }
  48. return &ServerBrokerSessions{
  49. sessions: sessions,
  50. }, nil
  51. }
  52. // SetKnownBrokerPublicKeys updates the set of broker public keys which are
  53. // allowed to establish sessions with the server. Any existing sessions with
  54. // keys not in the new list are deleted. Existing sessions with keys which
  55. // remain in the list are retained.
  56. func (s *ServerBrokerSessions) SetKnownBrokerPublicKeys(
  57. brokerPublicKeys []SessionPublicKey) error {
  58. return errors.Trace(s.sessions.SetKnownInitiatorPublicKeys(brokerPublicKeys))
  59. }
  60. // ProxiedConnectionHandler is a callback, provided by the Psiphon server,
  61. // that receives information from a BrokerServerReport for the client
  62. // associated with the callback.
  63. //
  64. // The server must use the brokerVerifiedOriginalClientIP for all GeoIP
  65. // operations associated with the client, including traffic rule selection
  66. // and client-side tactics selection.
  67. //
  68. // Since the BrokerServerReport may be delivered later than the Psiphon
  69. // handshake request -- in the case where the broker/server session needs to
  70. // be established there will be additional round trips -- the server should
  71. // delay traffic rule application, tactics responses, and allowing tunneled
  72. // traffic until after the ProxiedConnectionHandler callback is invoked for
  73. // the client. As a consequence, Psiphon Servers should be configured to
  74. // require Proxies to be used for designated protocols. It's expected that
  75. // server-side tactics such as packet manipulation will be applied based on
  76. // the proxy's IP address.
  77. //
  78. // The fields in logFields should be added to server_tunnel logs.
  79. type ProxiedConnectionHandler func(
  80. brokerVerifiedOriginalClientIP string,
  81. logFields common.LogFields)
  82. // HandlePacket handles a broker/server session packet, which are relayed by
  83. // clients. In Psiphon, the packets may be exchanged in the Psiphon
  84. // handshake, or in subsequent SSH requests and responses. When the
  85. // broker/server session is already established, it's expected that the
  86. // BrokerServerReport arrives in the packet that accompanies the Psiphon
  87. // handshake, and so no additional round trip is required.
  88. //
  89. // Once the session is established and a verified BrokerServerReport arrives,
  90. // the information from that report is sent to the ProxiedConnectionHandler
  91. // callback. The callback should be associated with the client that is
  92. // relaying the packets.
  93. //
  94. // clientConnectionID is the in-proxy connection ID specified by the client in
  95. // its Psiphon handshake.
  96. //
  97. // When the retOut return value is not nil, it should be relayed back to the
  98. // client in the handshake response or other tunneled response. When retOut
  99. // is nil, the relay is complete.
  100. //
  101. // In the session reset token case, HandlePacket will return a non-nil retOut
  102. // along with a retErr; the server should both log retErr and also relay the
  103. // packet to the broker.
  104. func (s *ServerBrokerSessions) HandlePacket(
  105. logger common.Logger,
  106. in []byte,
  107. clientConnectionID ID,
  108. handler ProxiedConnectionHandler) (retOut []byte, retErr error) {
  109. handleUnwrappedReport := func(initiatorID ID, unwrappedReportPayload []byte) ([]byte, error) {
  110. brokerReport, err := UnmarshalBrokerServerReport(unwrappedReportPayload)
  111. if err != nil {
  112. return nil, errors.Trace(err)
  113. }
  114. logFields, err := brokerReport.ValidateAndGetLogFields()
  115. if err != nil {
  116. return nil, errors.Trace(err)
  117. }
  118. // The initiatorID is the broker's public key.
  119. logFields["inproxy_broker_id"] = initiatorID
  120. logFields["inproxy_connection_id"] = brokerReport.ConnectionID
  121. logFields["inproxy_proxy_id"] = brokerReport.ProxyID
  122. // !matched_common_compartments implies a personal compartment ID match
  123. logFields["inproxy_matched_common_compartments"] = brokerReport.MatchedCommonCompartments
  124. logFields["inproxy_proxy_nat_type"] = brokerReport.ProxyNATType
  125. logFields["inproxy_proxy_port_mapping_types"] = brokerReport.ProxyPortMappingTypes
  126. logFields["inproxy_client_nat_type"] = brokerReport.ClientNATType
  127. logFields["inproxy_client_port_mapping_types"] = brokerReport.ClientPortMappingTypes
  128. // TODO:
  129. // - log IPv4 vs. IPv6 information
  130. // - relay and log broker transport stats, such as meek HTTP version
  131. ok := true
  132. // The client must supply same connection ID to server that the broker
  133. // sends to the server.
  134. if brokerReport.ConnectionID != clientConnectionID {
  135. // Limitation: as the BrokerServerReport is a one-way message with
  136. // no response, the broker will not be notified of tunnel failure
  137. // errors including "connection ID mismatch", and cannot log this
  138. // connection attempt outcome.
  139. logger.WithTraceFields(common.LogFields{
  140. "client_inproxy_connection_id": clientConnectionID,
  141. "broker_inproxy_connection_id": brokerReport.ConnectionID,
  142. }).Error("connection ID mismatch")
  143. ok = false
  144. }
  145. if ok {
  146. handler(brokerReport.ClientIP, logFields)
  147. }
  148. // Returns nil, as there is no response to the report, and so no
  149. // additional packet to relay.
  150. return nil, nil
  151. }
  152. out, err := s.sessions.HandlePacket(in, handleUnwrappedReport)
  153. return out, errors.Trace(err)
  154. }