@@ -36,8 +36,8 @@ const (
3636 wsProdAssets = "https://assets.windscribe.com/"
3737 wsProdAssets2 = "https://assets.totallyacdn.com/"
3838
39- wsMyIp = "https://checkip.windscribe.com/"
40- wsMyIp2 = "https://checkip.totallyacdn.com/"
39+ // wsMyIp = "https://checkip.windscribe.com/"
40+ // wsMyIp2 = "https://checkip.totallyacdn.com/"
4141)
4242
4343const (
@@ -92,13 +92,13 @@ const (
9292 // github.com/Windscribe/Android-App/blob/3f9c2ab98a70fa/base/src/main/java/com/windscribe/vpn/repository/WgConfigRepository.kt#L143
9393 wgttl = "3600" // an hour in seconds
9494
95- wspxpath = "ServerCredentials/"
96-
9795 wssessionpath = "Session/"
9896 wsportpath = "PortMap/"
99- wslocpath = "/ serverlist/mob-v2/1/" // + $loc_hash
97+ wslocpath = "serverlist/mob-v2/1/" // + $loc_hash
10098
101- wsbestloc = "/BestLocation"
99+ // for ovpn (unused):
100+ // wspxpath = "ServerCredentials/"
101+ // wsbestloc = "BestLocation/"
102102
103103 wsMinServerLinkSpeed = 1 // 1mbps
104104 wsMaxServerHealth = 100 // min is 0
@@ -119,7 +119,6 @@ var (
119119 errWsNoConfig = errors .New ("ws: no config" )
120120 errWsNoJsonConfig = errors .New ("ws: no json config" )
121121 errWsNoSession = errors .New ("ws: no session info" )
122- errWsSessionExpired = errors .New ("ws: session expired" )
123122 errWsNoClient = errors .New ("ws: no client" )
124123 errWsNoEntitlement = errors .New ("ws: missing entitlement" )
125124 errWsNoToken = errors .New ("ws: missing token" )
@@ -893,14 +892,36 @@ func (a *WsClient) Conf(cc string) (string, error) {
893892 return "" , errWsNoCcConfig
894893}
895894
895+ // unused on the control plane, so use a fixed but valid hostname
896+ func fixedValidWsEndpoint (test bool ) string {
897+ if test {
898+ return "ca.windscribe.dev"
899+ }
900+ return "ca.windscribe.com"
901+ }
902+
896903func baseurl (test bool ) string {
897904 if test {
898905 return wsTestUrl
899906 }
900907 // TODO: use wsProdUrl2 if wsProdUrl is not reachable?
908+ if rand .IntN (10000 )% 2 == 0 {
909+ return wsProdUrl2
910+ }
901911 return wsProdUrl
902912}
903913
914+ func assetsurl (test bool ) string {
915+ if test {
916+ return wsTestAssets
917+ }
918+ // TODO: use wsProdAssets2 if wsProdUrl is not reachable?
919+ if rand .IntN (10000 )% 2 == 0 {
920+ return wsProdAssets2
921+ }
922+ return wsProdAssets
923+ }
924+
904925func authHeader (req * http.Request , t string ) {
905926 if req == nil {
906927 return
@@ -1007,27 +1028,6 @@ func skipWsServer(server WsServerList) bool {
10071028 return false // this server is okay to use
10081029}
10091030
1010- func anyWsEndpoint (s []WsServerList ) string {
1011- if len (s ) <= 0 {
1012- return ""
1013- }
1014- for _ , server := range s {
1015- if skipWsServer (server ) {
1016- continue
1017- }
1018- for _ , g := range server .Groups {
1019- if len (g .Nodes ) <= 0 {
1020- continue // skip servers without nodes
1021- }
1022- if len (g .WgPubKey ) <= 0 || len (g .WgEndpoint ) <= 0 {
1023- continue // skip servers without wg
1024- }
1025- return g .WgEndpoint // return the first wg endpoint found
1026- }
1027- }
1028- return "" // no wg endpoint found
1029- }
1030-
10311031func wsRandomPort () string {
10321032 // return a random port from the list of WireGuard ports
10331033 return wswgports [rand .Int32N (int32 (len (wswgports )))]
@@ -1040,6 +1040,18 @@ func wsRandomIP3(nodes []WsServerNode) string {
10401040 return nodes [rand .Int32N (int32 (len (nodes )))].IP3
10411041}
10421042
1043+ func hasIP3 (nodes []WsServerNode ) bool {
1044+ if len (nodes ) <= 0 {
1045+ return false
1046+ }
1047+ for _ , node := range nodes {
1048+ if len (node .IP3 ) > 0 {
1049+ return true
1050+ }
1051+ }
1052+ return false
1053+ }
1054+
10431055func convertToRegionalWgConfs (id * WsWgCreds , reservation * WsWgConnectData , list []WsServerList , sess * WsSession , test bool ) ([]* RegionalWgConf , error ) {
10441056 if id == nil || reservation == nil || len (list ) <= 0 {
10451057 return nil , errWsNoServerList
@@ -1072,8 +1084,9 @@ func convertToRegionalWgConfs(id *WsWgCreds, reservation *WsWgConnectData, list
10721084 if len (group .WgPubKey ) <= 0 || len (group .WgEndpoint ) <= 0 {
10731085 continue // skip servers without wg
10741086 }
1075- if len (group .Nodes ) <= 0 {
1076- log .W ("ws: wgconfs: no nodes in %s (%s)" , group .City , group .Nick )
1087+ noip3 := ! hasIP3 (group .Nodes )
1088+ if len (group .Nodes ) <= 0 || noip3 {
1089+ log .W ("ws: wgconfs: no nodes in %s (%s); ip3? %t" , group .City , group .Nick , noip3 )
10771090 continue // skip servers without nodes
10781091 }
10791092 if tot [cc ] >= maxPerRegionWgConfs * 2 {
@@ -1082,22 +1095,27 @@ func convertToRegionalWgConfs(id *WsWgCreds, reservation *WsWgConnectData, list
10821095 break // we have enough configs for this region
10831096 }
10841097 tot [cc ] = tot [cc ] + 1
1098+ dnsaddr := reservation .Config .DNS
1099+ if len (dnsaddr ) <= 0 {
1100+ dnsaddr = cfdns4
1101+ }
1102+ // Use any IPv4 permutation of AllowedIPs. The API only sends a hint.
1103+ // IPv6s are firewalled.
1104+ allowed := []string {gw4 }
10851105 out = append (out , & RegionalWgConf {
10861106 CC : server .CountryCode ,
10871107 Name : servername ,
10881108 ClientAddr4 : reservation .Config .Address ,
10891109 ClientPrivKey : id .PrivateKey ,
10901110 ClientPubKey : id .PublicKey ,
1091- ClientDNS4 : reservation . Config . DNS ,
1111+ ClientDNS4 : dnsaddr ,
10921112 PskKey : id .PresharedKey ,
10931113 ServerPubKey : group .WgPubKey ,
10941114 ServerDomainPort : net .JoinHostPort (group .WgEndpoint , port ),
10951115 ServerIPPort4 : net .JoinHostPort (wsRandomIP3 (group .Nodes ), port ),
1096- // TODO: ipv6 or use id.AllowedIPs
1097- AllowedIPs : []string {gw4 },
1116+ AllowedIPs : allowed ,
10981117 })
10991118 }
1100-
11011119 }
11021120
11031121 if len (out ) <= 0 {
@@ -1122,7 +1140,7 @@ func getServerList(h *http.Client, sess *WsSession, ent *WsEntitlement) (*WsServ
11221140 test := ent .Test
11231141
11241142 // curl -x GET '.../serverlist/mob-v2/1/<lochash>'
1125- locreq , err := http .NewRequest ("GET" , baseurl (test )+ wslocpath + lochash , nil )
1143+ locreq , err := http .NewRequest ("GET" , assetsurl (test )+ wslocpath + lochash , nil )
11261144 if err != nil {
11271145 return nil , fmt .Errorf ("ws: wgconfs: req err: %v" , err )
11281146 }
@@ -1264,10 +1282,11 @@ initagain:
12641282
12651283 log .I ("ws: wgconfs: got creds for %s, usingExisting? %t" , trunc8 (pubkeybase64 ), useExistingCreds )
12661284
1267- someEndpoint := anyWsEndpoint ( servers )
1285+ someEndpoint := fixedValidWsEndpoint ( test )
12681286 if len (someEndpoint ) <= 0 {
12691287 return nil , nil , fmt .Errorf ("ws: wgconfs: no endpoint" )
12701288 }
1289+ // github.com/Windscribe/Android-App/blob/746d505dc69/base/src/main/java/com/windscribe/vpn/backend/utils/WindVpnController.kt#L159
12711290 /*
12721291 curl -x POST '.../WgConfigs/connect' \
12731292 --data-urlencode 'hostname=<>' \
@@ -1277,7 +1296,8 @@ initagain:
12771296 -H 'Authorization: Bearer id:typ:epochsec:sig1:sig2'
12781297 */
12791298 cdata := url.Values {}
1280- // github.com/Windscribe/Android-App/blob/746d505dc69/base/src/main/java/com/windscribe/vpn/backend/utils/WindVpnController.kt#L159
1299+ // The "hostname" for WgConfigs/connect call is requested, but currently it
1300+ // does nothing as we never made use of this server side.
12811301 cdata .Set ("hostname" , someEndpoint )
12821302 cdata .Set ("wg_pubkey" , pubkeybase64 )
12831303 cdata .Set ("wg_ttl" , wgttl )
@@ -1487,6 +1507,10 @@ func makeWsWgFrom(h *http.Client, existingConf *WsWgConfig) (ws *WsClient, refre
14871507 }
14881508
14891509 exp , err := time .Parse (time .DateOnly , newSess .ExpiryDate )
1510+ if err != nil {
1511+ err = fmt .Errorf ("ws: make: parsing expiry %s; err: %v" , newSess .ExpiryDate , err )
1512+ return
1513+ }
14901514 active := exp .After (time .Now ())
14911515 if ! active {
14921516 log .W ("ws: make: session expired at %s" , fmtTime (exp ))
0 commit comments