server.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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. // ServerBrokerSessions manages the secure sessions that handle
  25. // BrokerServerRequests from brokers. Each in-proxy-capable Psiphon server
  26. // maintains a ServerBrokerSessions, with a set of established sessions for
  27. // each broker. Session messages are relayed between the broker and the
  28. // server by the client.
  29. type ServerBrokerSessions struct {
  30. sessions *ResponderSessions
  31. }
  32. // NewServerBrokerSessions create a new ServerBrokerSessions, with the
  33. // specified key material. The expected brokers are authenticated with
  34. // brokerPublicKeys, an allow list.
  35. func NewServerBrokerSessions(
  36. serverPrivateKey SessionPrivateKey,
  37. serverRootObfuscationSecret ObfuscationSecret,
  38. brokerPublicKeys []SessionPublicKey) (*ServerBrokerSessions, error) {
  39. sessions, err := NewResponderSessionsForKnownInitiators(
  40. serverPrivateKey, serverRootObfuscationSecret, brokerPublicKeys)
  41. if err != nil {
  42. return nil, errors.Trace(err)
  43. }
  44. return &ServerBrokerSessions{
  45. sessions: sessions,
  46. }, nil
  47. }
  48. // ProxiedConnectionHandler is a callback, provided by the Psiphon server,
  49. // that receives information from a BrokerServerRequest for the client
  50. // associated with the callback.
  51. //
  52. // The server must use the brokerVerifiedOriginalClientIP for all GeoIP
  53. // operations associated with the client, including traffic rule selection
  54. // and client-side tactics selection.
  55. //
  56. // Since the BrokerServerRequest may be delivered later than the Psiphon
  57. // handshake -- in the case where the broker/server session needs to be
  58. // established there will be additional round trips -- the server should
  59. // delay traffic rule application, tactics responses, and allowing tunneled
  60. // traffic until after the ProxiedConnectionHandler callback is invoked for
  61. // the client. As a consequence, Psiphon Servers should be configured to
  62. // require Proxies to be used for designated protocols. It's expected that
  63. // server-side tactics such as packet manipulation will be applied based on
  64. // the proxy's IP address.
  65. //
  66. // The fields in logFields should be added to server_tunnel logs.
  67. type ProxiedConnectionHandler func(
  68. brokerVerifiedOriginalClientIP string,
  69. logFields common.LogFields)
  70. // HandlePacket handles a broker/server session packet, which are relayed by
  71. // clients. In Psiphon, the packets may be sent in the Psiphon handshake, or
  72. // in subsequent requests; while responses should be returned in the
  73. // handshake response or responses for later requests. When the broker/server
  74. // session is already established, it's expected that the BrokerServerRequest
  75. // arrives in the packet that accompanies the Psiphon handshake, and so no
  76. // additional round trip is required.
  77. //
  78. // Once the session is established and a verified BrokerServerRequest arrives,
  79. // the information from that request is sent to the ProxiedConnectionHandler
  80. // callback. The callback should be associated with the client that is
  81. // relaying the packets.
  82. //
  83. // clientConnectionID is the in-proxy connection ID specified by the client in
  84. // its Psiphon handshake.
  85. //
  86. // When the retOut return value is not nil, it should be relayed back to the
  87. // client in the handshake response or other tunneled response. When retOut
  88. // is nil, the relay is complete.
  89. //
  90. // When the retErr return value is not nil, it should be logged, and an error
  91. // flag (but not the retErr value) relayed back to the client. retErr may be
  92. // non-nil in expected conditions, such as the broker attempting to use a
  93. // session which has expired.
  94. func (s *ServerBrokerSessions) HandlePacket(
  95. logger common.Logger,
  96. in []byte,
  97. clientConnectionID ID,
  98. handler ProxiedConnectionHandler) (retOut []byte, retErr error) {
  99. handleUnwrappedRequest := func(initiatorID ID, unwrappedRequestPayload []byte) ([]byte, error) {
  100. brokerRequest, err := UnmarshalBrokerServerRequest(unwrappedRequestPayload)
  101. if err != nil {
  102. return nil, errors.Trace(err)
  103. }
  104. logFields, err := brokerRequest.ValidateAndGetLogFields()
  105. if err != nil {
  106. return nil, errors.Trace(err)
  107. }
  108. // The initiatorID is the broker's public key.
  109. logFields["broker_id"] = initiatorID
  110. var errorMessage string
  111. // The client must supply same connection ID to server that the broker
  112. // sends to the server.
  113. if brokerRequest.ConnectionID != clientConnectionID {
  114. // Errors such as this are not error return values, as this is not
  115. // an error in the session protocol. Instead, a response is sent
  116. // to the broker containing the error message, which the broker may log.
  117. errorMessage = "connection ID mismatch"
  118. logger.WithTraceFields(common.LogFields{
  119. "client_connection_id": clientConnectionID,
  120. "broker_connection_id": brokerRequest.ConnectionID,
  121. }).Error(errorMessage)
  122. }
  123. if errorMessage == "" {
  124. handler(brokerRequest.ClientIP, logFields)
  125. }
  126. brokerResponse, err := MarshalBrokerServerResponse(
  127. &BrokerServerResponse{
  128. ConnectionID: brokerRequest.ConnectionID,
  129. ErrorMessage: errorMessage,
  130. })
  131. if err != nil {
  132. return nil, errors.Trace(err)
  133. }
  134. return brokerResponse, nil
  135. }
  136. // An error here may be due to the broker using a session that has
  137. // expired. In that case, the client should relay back that the session
  138. // failed, and the broker will start reestablishing the session.
  139. //
  140. // TODO: distinguish between session expired, an expected error, and
  141. // unexpected errors and then log only unexpected errors? However, expiry
  142. // may be rare, and still useful to log.
  143. out, err := s.sessions.HandlePacket(
  144. in, handleUnwrappedRequest)
  145. if err != nil {
  146. return nil, errors.Trace(err)
  147. }
  148. return out, nil
  149. }