Просмотр исходного кода

Add network_type and client_app_id metrics parameters

Rod Hynes 6 лет назад
Родитель
Сommit
5b2dc0f935
5 измененных файлов с 58 добавлено и 5 удалено
  1. 20 0
      psiphon/dialParameters.go
  2. 1 0
      psiphon/notice.go
  3. 19 0
      psiphon/server/api.go
  4. 17 5
      psiphon/server/server_test.go
  5. 1 0
      psiphon/serverApi.go

+ 20 - 0
psiphon/dialParameters.go

@@ -27,6 +27,7 @@ import (
 	"net"
 	"net/http"
 	"net/url"
+	"strings"
 	"sync/atomic"
 	"time"
 
@@ -693,6 +694,25 @@ func (dialParams *DialParameters) GetMeekConfig() *MeekConfig {
 	return dialParams.meekConfig
 }
 
+// GetNetworkType returns a network type name, suitable for metrics, which is
+// derived from the network ID.
+func (dialParams *DialParameters) GetNetworkType() string {
+
+	// Unlike the logic in loggingNetworkIDGetter.GetNetworkID, we don't take the
+	// arbitrary text before the first "-" since some platforms without network
+	// detection support stub in random values to enable tactics. Instead we
+	// check for and use the common network type prefixes currently used in
+	// NetworkIDGetter implementations.
+
+	if strings.HasPrefix(dialParams.NetworkID, "WIFI") {
+		return "WIFI"
+	}
+	if strings.HasPrefix(dialParams.NetworkID, "MOBILE") {
+		return "MOBILE"
+	}
+	return "UNKNOWN"
+}
+
 func (dialParams *DialParameters) Succeeded() {
 
 	// When TTL is 0, don't store dial parameters.

+ 1 - 0
psiphon/notice.go

@@ -433,6 +433,7 @@ func noticeWithDialParameters(noticeType string, dialParams *DialParameters) {
 		"protocol", dialParams.TunnelProtocol,
 		"isReplay", dialParams.IsReplay,
 		"candidateNumber", dialParams.CandidateNumber,
+		"networkType", dialParams.GetNetworkType(),
 	}
 
 	if GetEmitNetworkParameters() {

+ 19 - 0
psiphon/server/api.go

@@ -774,6 +774,7 @@ var baseRequestParams = []requestParamSpec{
 	{"meek_tls_padding", isIntString, requestParamOptional | requestParamLogStringAsInt},
 	{"network_latency_multiplier", isFloatString, requestParamOptional | requestParamLogStringAsFloat},
 	{"client_bpf", isAnyString, requestParamOptional},
+	{"network_type", isAnyString, requestParamOptional},
 }
 
 func validateRequestParams(
@@ -980,6 +981,24 @@ func getRequestLogFields(
 				// the field in this case.
 
 			default:
+
+				// Add a distinct app ID field when the value is present in
+				// client_platform.
+				if expectedParam.name == "client_platform" {
+					index := -1
+					if strings.HasPrefix(strValue, "iOS") {
+						index = 3
+					} else if strings.HasPrefix(strValue, "Android") {
+						index = 2
+					}
+					if index > 0 {
+						components := strings.Split(strValue, "_")
+						if index < len(components) {
+							logFields["client_app_id"] = components[index]
+						}
+					}
+				}
+
 				if expectedParam.flags&requestParamLogStringAsInt != 0 {
 					intValue, _ := strconv.Atoi(strValue)
 					logFields[expectedParam.name] = intValue

+ 17 - 5
psiphon/server/server_test.go

@@ -543,6 +543,8 @@ type runServerConfig struct {
 var (
 	testSSHClientVersions = []string{"SSH-2.0-A", "SSH-2.0-B", "SSH-2.0-C"}
 	testUserAgents        = []string{"ua1", "ua2", "ua3"}
+	testNetworkType       = "WIFI"
+	testAppID             = "com.test.app"
 )
 
 func runServer(t *testing.T, runConfig *runServerConfig) {
@@ -806,10 +808,10 @@ func runServer(t *testing.T, runConfig *runServerConfig) {
 	localSOCKSProxyPort := 1081
 	localHTTPProxyPort := 8081
 
-	// Use a distinct prefix for network ID for each test run to
+	// Use a distinct suffix for network ID for each test run to
 	// ensure tactics from different runs don't apply; this is
 	// a workaround for the singleton datastore.
-	jsonNetworkID := fmt.Sprintf(`,"NetworkID" : "%s-%s"`, time.Now().String(), "NETWORK1")
+	jsonNetworkID := fmt.Sprintf(`,"NetworkID" : "WIFI-%s"`, time.Now().String())
 
 	jsonLimitTLSProfiles := ""
 	if runConfig.tlsProfile != "" {
@@ -818,7 +820,7 @@ func runServer(t *testing.T, runConfig *runServerConfig) {
 
 	clientConfigJSON := fmt.Sprintf(`
     {
-        "ClientPlatform" : "Windows",
+        "ClientPlatform" : "Android_10_%s",
         "ClientVersion" : "0",
         "SponsorId" : "0",
         "PropagationChannelId" : "0",
@@ -830,7 +832,7 @@ func runServer(t *testing.T, runConfig *runServerConfig) {
         "LimitTunnelProtocols" : ["%s"]
         %s
         %s
-    }`, numTunnels, runConfig.tunnelProtocol, jsonLimitTLSProfiles, jsonNetworkID)
+    }`, testAppID, numTunnels, runConfig.tunnelProtocol, jsonLimitTLSProfiles, jsonNetworkID)
 
 	clientConfig, err := psiphon.LoadConfig([]byte(clientConfigJSON))
 	if err != nil {
@@ -1184,13 +1186,15 @@ func checkExpectedLogFields(
 		"dial_duration",
 		"candidate_number",
 		"network_latency_multiplier",
+		"network_type",
+		"client_app_id",
 	} {
 		if fields[name] == nil || fmt.Sprintf("%s", fields[name]) == "" {
 			return fmt.Errorf("missing expected field '%s'", name)
 		}
 	}
 
-	if fields["relay_protocol"] != runConfig.tunnelProtocol {
+	if fields["relay_protocol"].(string) != runConfig.tunnelProtocol {
 		return fmt.Errorf("unexpected relay_protocol '%s'", fields["relay_protocol"])
 	}
 
@@ -1331,6 +1335,14 @@ func checkExpectedLogFields(
 		}
 	}
 
+	if fields["network_type"].(string) != testNetworkType {
+		return fmt.Errorf("unexpected network_type '%s'", fields["network_type"])
+	}
+
+	if fields["client_app_id"].(string) != testAppID {
+		return fmt.Errorf("unexpected client_app_id '%s'", fields["client_app_id"])
+	}
+
 	return nil
 }
 

+ 1 - 0
psiphon/serverApi.go

@@ -821,6 +821,7 @@ func getBaseAPIParameters(
 	params["client_platform"] = config.ClientPlatform
 	params["client_build_rev"] = buildinfo.GetBuildInfo().BuildRev
 	params["tunnel_whole_device"] = strconv.Itoa(config.TunnelWholeDevice)
+	params["network_type"] = dialParams.GetNetworkType()
 
 	// The following parameters may be blank and must
 	// not be sent to the server if blank.