Преглед изворни кода

Return client's public network address in handshake response

- A client may use this to learn its public network address

- Notice output is optional and defaults off
Rod Hynes пре 4 година
родитељ
комит
719d537ba9

+ 1 - 0
psiphon/common/protocol/protocol.go

@@ -445,6 +445,7 @@ type HandshakeResponse struct {
 	HttpsRequestRegexes      []map[string]string `json:"https_request_regexes"`
 	EncodedServerList        []string            `json:"encoded_server_list"`
 	ClientRegion             string              `json:"client_region"`
+	ClientAddress            string              `json:"client_address"`
 	ServerTimestamp          string              `json:"server_timestamp"`
 	ActiveAuthorizationIDs   []string            `json:"active_authorization_ids"`
 	TacticsPayload           json.RawMessage     `json:"tactics_payload"`

+ 4 - 0
psiphon/config.go

@@ -437,6 +437,10 @@ type Config struct {
 	// EmitServerAlerts indicates whether to emit notices for server alerts.
 	EmitServerAlerts bool
 
+	// EmitClientAddress indicates whether to emit the client's public network
+	// address, IP and port, as seen by the server.
+	EmitClientAddress bool
+
 	// RateLimits specify throttling configuration for the tunnel.
 	RateLimits common.RateLimits
 

+ 9 - 0
psiphon/notice.go

@@ -667,6 +667,15 @@ func NoticeClientRegion(region string) {
 		"region", region)
 }
 
+// NoticeClientAddress is the client's public network address, the IP address
+// and port, as seen by the server and reported to the client in the
+// handshake.
+func NoticeClientAddress(address string) {
+	singletonNoticeLogger.outputNotice(
+		"ClientAddress", 0,
+		"address", address)
+}
+
 // NoticeTunnels is how many active tunnels are available. The client should use this to
 // determine connecting/unexpected disconnect state transitions. When count is 0, the core is
 // disconnected; when count > 1, the core is connected.

+ 20 - 4
psiphon/server/api.go

@@ -60,6 +60,7 @@ const (
 //
 func sshAPIRequestHandler(
 	support *SupportServices,
+	clientAddr string,
 	geoIPData GeoIPData,
 	authorizedAccessTypes []string,
 	name string,
@@ -87,6 +88,7 @@ func sshAPIRequestHandler(
 	return dispatchAPIRequestHandler(
 		support,
 		protocol.PSIPHON_SSH_API_PROTOCOL,
+		clientAddr,
 		geoIPData,
 		authorizedAccessTypes,
 		name,
@@ -98,6 +100,7 @@ func sshAPIRequestHandler(
 func dispatchAPIRequestHandler(
 	support *SupportServices,
 	apiProtocol string,
+	clientAddr string,
 	geoIPData GeoIPData,
 	authorizedAccessTypes []string,
 	name string,
@@ -146,14 +149,22 @@ func dispatchAPIRequestHandler(
 	}
 
 	switch name {
+
 	case protocol.PSIPHON_API_HANDSHAKE_REQUEST_NAME:
-		return handshakeAPIRequestHandler(support, apiProtocol, geoIPData, params)
+		return handshakeAPIRequestHandler(
+			support, apiProtocol, clientAddr, geoIPData, params)
+
 	case protocol.PSIPHON_API_CONNECTED_REQUEST_NAME:
-		return connectedAPIRequestHandler(support, geoIPData, authorizedAccessTypes, params)
+		return connectedAPIRequestHandler(
+			support, clientAddr, geoIPData, authorizedAccessTypes, params)
+
 	case protocol.PSIPHON_API_STATUS_REQUEST_NAME:
-		return statusAPIRequestHandler(support, geoIPData, authorizedAccessTypes, params)
+		return statusAPIRequestHandler(
+			support, clientAddr, geoIPData, authorizedAccessTypes, params)
+
 	case protocol.PSIPHON_API_CLIENT_VERIFICATION_REQUEST_NAME:
-		return clientVerificationAPIRequestHandler(support, geoIPData, authorizedAccessTypes, params)
+		return clientVerificationAPIRequestHandler(
+			support, clientAddr, geoIPData, authorizedAccessTypes, params)
 	}
 
 	return nil, errors.Tracef("invalid request name: %s", name)
@@ -177,6 +188,7 @@ var handshakeRequestParams = append(
 func handshakeAPIRequestHandler(
 	support *SupportServices,
 	apiProtocol string,
+	clientAddr string,
 	geoIPData GeoIPData,
 	params common.APIParameters) ([]byte, error) {
 
@@ -324,6 +336,7 @@ func handshakeAPIRequestHandler(
 		HttpsRequestRegexes:      httpsRequestRegexes,
 		EncodedServerList:        encodedServerList,
 		ClientRegion:             geoIPData.Country,
+		ClientAddress:            clientAddr,
 		ServerTimestamp:          common.GetCurrentTimestamp(),
 		ActiveAuthorizationIDs:   handshakeStateInfo.activeAuthorizationIDs,
 		TacticsPayload:           marshaledTacticsPayload,
@@ -370,6 +383,7 @@ var updateOnConnectedParamNames = append(
 // connected_timestamp is truncated as a privacy measure.
 func connectedAPIRequestHandler(
 	support *SupportServices,
+	clientAddr string,
 	geoIPData GeoIPData,
 	authorizedAccessTypes []string,
 	params common.APIParameters) ([]byte, error) {
@@ -497,6 +511,7 @@ var failedTunnelStatParams = append(
 // string). Stats processor must handle this input with care.
 func statusAPIRequestHandler(
 	support *SupportServices,
+	clientAddr string,
 	geoIPData GeoIPData,
 	authorizedAccessTypes []string,
 	params common.APIParameters) ([]byte, error) {
@@ -720,6 +735,7 @@ func statusAPIRequestHandler(
 // for older Android clients that still send verification requests
 func clientVerificationAPIRequestHandler(
 	support *SupportServices,
+	clientAddr string,
 	geoIPData GeoIPData,
 	authorizedAccessTypes []string,
 	params common.APIParameters) ([]byte, error) {

+ 10 - 0
psiphon/server/tunnelServer.go

@@ -1158,6 +1158,7 @@ func (sshServer *sshServer) handleClient(
 		tunnelProtocol,
 		serverPacketManipulation,
 		replayedServerPacketManipulation,
+		clientAddr,
 		geoIPData)
 
 	// sshClient.run _must_ call onSSHHandshakeFinished to release the semaphore:
@@ -1203,6 +1204,7 @@ type sshClient struct {
 	throttledConn                        *common.ThrottledConn
 	serverPacketManipulation             string
 	replayedServerPacketManipulation     bool
+	clientAddr                           net.Addr
 	geoIPData                            GeoIPData
 	sessionID                            string
 	isFirstTunnelInSession               bool
@@ -1296,6 +1298,7 @@ func newSshClient(
 	tunnelProtocol string,
 	serverPacketManipulation string,
 	replayedServerPacketManipulation bool,
+	clientAddr net.Addr,
 	geoIPData GeoIPData) *sshClient {
 
 	runCtx, stopRunning := context.WithCancel(context.Background())
@@ -1310,6 +1313,7 @@ func newSshClient(
 		tunnelProtocol:                   tunnelProtocol,
 		serverPacketManipulation:         serverPacketManipulation,
 		replayedServerPacketManipulation: replayedServerPacketManipulation,
+		clientAddr:                       clientAddr,
 		geoIPData:                        geoIPData,
 		isFirstTunnelInSession:           true,
 		tcpPortForwardLRU:                common.NewLRUConns(),
@@ -1988,8 +1992,14 @@ func (sshClient *sshClient) handleSSHRequests(requests <-chan *ssh.Request) {
 			// Note: unlock before use is only safe as long as referenced sshClient data,
 			// such as slices in handshakeState, is read-only after initially set.
 
+			clientAddr := ""
+			if sshClient.clientAddr != nil {
+				clientAddr = sshClient.clientAddr.String()
+			}
+
 			responsePayload, err = sshAPIRequestHandler(
 				sshClient.sshServer.support,
+				clientAddr,
 				sshClient.geoIPData,
 				authorizedAccessTypes,
 				request.Type,

+ 4 - 0
psiphon/server/webServer.go

@@ -240,6 +240,7 @@ func (webServer *webServer) handshakeHandler(w http.ResponseWriter, r *http.Requ
 		responsePayload, err = dispatchAPIRequestHandler(
 			webServer.support,
 			protocol.PSIPHON_WEB_API_PROTOCOL,
+			r.RemoteAddr,
 			webServer.lookupGeoIPData(params),
 			nil,
 			protocol.PSIPHON_API_HANDSHAKE_REQUEST_NAME,
@@ -271,6 +272,7 @@ func (webServer *webServer) connectedHandler(w http.ResponseWriter, r *http.Requ
 		responsePayload, err = dispatchAPIRequestHandler(
 			webServer.support,
 			protocol.PSIPHON_WEB_API_PROTOCOL,
+			r.RemoteAddr,
 			webServer.lookupGeoIPData(params),
 			nil, // authorizedAccessTypes not logged in web API transport
 			protocol.PSIPHON_API_CONNECTED_REQUEST_NAME,
@@ -296,6 +298,7 @@ func (webServer *webServer) statusHandler(w http.ResponseWriter, r *http.Request
 		responsePayload, err = dispatchAPIRequestHandler(
 			webServer.support,
 			protocol.PSIPHON_WEB_API_PROTOCOL,
+			r.RemoteAddr,
 			webServer.lookupGeoIPData(params),
 			nil, // authorizedAccessTypes not logged in web API transport
 			protocol.PSIPHON_API_STATUS_REQUEST_NAME,
@@ -322,6 +325,7 @@ func (webServer *webServer) clientVerificationHandler(w http.ResponseWriter, r *
 		responsePayload, err = dispatchAPIRequestHandler(
 			webServer.support,
 			protocol.PSIPHON_WEB_API_PROTOCOL,
+			r.RemoteAddr,
 			webServer.lookupGeoIPData(params),
 			nil, // authorizedAccessTypes not logged in web API transport
 			protocol.PSIPHON_API_CLIENT_VERIFICATION_REQUEST_NAME,

+ 5 - 3
psiphon/serverApi.go

@@ -55,7 +55,6 @@ type ServerContext struct {
 	tunnel                   *Tunnel
 	psiphonHttpsClient       *http.Client
 	statsRegexps             *transferstats.Regexps
-	clientRegion             string
 	clientUpgradeVersion     string
 	serverHandshakeTimestamp string
 	paddingPRNG              *prng.PRNG
@@ -225,8 +224,11 @@ func (serverContext *ServerContext) doHandshakeRequest(
 		return errors.Trace(err)
 	}
 
-	serverContext.clientRegion = handshakeResponse.ClientRegion
-	NoticeClientRegion(serverContext.clientRegion)
+	if serverContext.tunnel.config.EmitClientAddress {
+		NoticeClientAddress(handshakeResponse.ClientAddress)
+	}
+
+	NoticeClientRegion(handshakeResponse.ClientRegion)
 
 	var serverEntries []protocol.ServerEntryFields