@@ -178,6 +178,7 @@ var (
178178 errWsRetryUpdate = errors .New ("ws: retry update" )
179179 errWsNoCcConfig = errors .New ("ws: not available in that location" )
180180 errWsNoFilters = errors .New ("ws: no filter list" )
181+ errWsCCExcluded = errors .New ("ws: cc excluded" )
181182)
182183
183184/*
@@ -1054,6 +1055,7 @@ func (a *WsClient) Locations() (x.RpnServers, error) {
10541055 if len (c .Configs ) <= 0 {
10551056 return nil , errWsNoCcConfig
10561057 }
1058+ excl := ccCsvAsSet (a .Ops ().ExcludeCCs ())
10571059 visited := make (map [string ]bool , len (c .Configs ))
10581060 s := make ([]x.RpnServer , 0 , len (c .Configs )/ maxPerRegionWgConfs )
10591061 for i , rc := range c .Configs {
@@ -1070,14 +1072,16 @@ func (a *WsClient) Locations() (x.RpnServers, error) {
10701072 continue
10711073 }
10721074 if ! visited [rc .Name ] {
1075+ _ , isExcluded := excl [rc .CC ]
10731076 s = append (s , x.RpnServer {
1074- CC : rc .CC ,
1075- City : rc .City ,
1076- Name : rc .Name ,
1077- Load : rc .Load ,
1078- Link : rc .Link ,
1079- Count : rc .Count ,
1080- Premium : rc .Premium ,
1077+ CC : rc .CC ,
1078+ City : rc .City ,
1079+ Name : rc .Name ,
1080+ Load : rc .Load ,
1081+ Link : rc .Link ,
1082+ Count : rc .Count ,
1083+ Premium : rc .Premium ,
1084+ Excluded : isExcluded ,
10811085 // cc is always suffixed; see proxy.go:proxifier.postAddRpnProxy
10821086 Key : strings .Join ([]string {rc .City , rc .CC }, confKeySep ),
10831087 Addrs : strings .Join ([]string {rc .ServerDomainPort , rc .addrCsv ()}, "," ),
@@ -1100,9 +1104,15 @@ func (a *WsClient) Update(ops *x.RpnOps) (newstate []byte, err error) {
11001104 curops := a .Ops ()
11011105 if ops == nil {
11021106 ops = curops
1103- } else if len (ops .DNSConfig ()) <= 0 {
1104- // retain existing dns config
1105- ops .SetDNSConfig (curops .DNSConfig ())
1107+ } else {
1108+ if len (ops .DNSConfig ()) <= 0 {
1109+ // retain existing dns config
1110+ ops .SetDNSConfig (curops .DNSConfig ())
1111+ }
1112+ // retain existing excludeCCs if not set by incoming ops
1113+ if len (ops .ExcludeCCs ()) <= 0 {
1114+ ops .SetExcludeCCs (curops .ExcludeCCs ())
1115+ }
11061116 }
11071117 start := time .Now ()
11081118 b , refreshed , needsRedo , err := makeWsWgFrom (a .http , c , * ops , true /*updating*/ , ops .ChangesConfig (* curops ))
@@ -1159,12 +1169,28 @@ func (a *WsClient) Conf(cc string) (string, error) {
11591169 city = cccsv [0 ]
11601170 cc = cccsv [1 ]
11611171 }
1162- visited := make (map [string ]struct {}, 0 )
11631172 // in sync with anyCountryCode / noCountryForOldMen vars in proxy.go
11641173 chooseAny := cc == "**" || len (cc ) <= 0
11651174 hasCity := len (city ) > 0
1166- tot := 0
1167- c := 0
1175+ cc = strings .ToUpper (cc )
1176+
1177+ excl := ccCsvAsSet (a .Ops ().ExcludeCCs ())
1178+ // if a specific (non-wildcard) CC is explicitly excluded, bail early
1179+ if ! chooseAny && len (excl ) > 0 {
1180+ if _ , excluded := excl [cc ]; excluded {
1181+ log .W ("ws: conf: cc %s is excluded..." , cc )
1182+ return "" , errWsCCExcluded
1183+ }
1184+ }
1185+
1186+ retried := false
1187+ reconf:
1188+ tot := 0 // total seen
1189+ c := 0 // good cc conf
1190+ badc := 0 // bad cc conf
1191+ x := 0 // total excluded
1192+ v := 0 // total visited
1193+ visited := make (map [string ]struct {}, len (cfg .Configs ))
11681194 out := make ([]string , 0 , maxPerRegionWgConfs )
11691195 ids := make ([]string , 0 , maxPerRegionWgConfs )
11701196 for _ , rc := range cfg .Configs {
@@ -1175,8 +1201,14 @@ func (a *WsClient) Conf(cc string) (string, error) {
11751201 continue
11761202 }
11771203 visited [rc .CC ] = struct {}{}
1204+ v ++
1205+ // skip CCs the user has excluded
1206+ if _ , excluded := excl [rc .CC ]; excluded {
1207+ x ++
1208+ continue
1209+ }
11781210 if c > 2 {
1179- // choose only low load and high link speed servers
1211+ // after a couple random servers, prefer low load and high link speed servers
11801212 gbps10 := rc .Link >= 10000
11811213 healthy50 := rc .Load <= 50
11821214 gbps1 := rc .Link >= 1000
@@ -1211,6 +1243,8 @@ func (a *WsClient) Conf(cc string) (string, error) {
12111243 out = append (out , confstr )
12121244 ids = append (ids , strings .Join ([]string {rc .CC , rc .City , rc .Name }, "/" ))
12131245 c ++
1246+ } else {
1247+ badc ++
12141248 }
12151249 }
12161250 tot ++
@@ -1220,6 +1254,16 @@ func (a *WsClient) Conf(cc string) (string, error) {
12201254 log .I ("ws: conf: cc %s(%s): %d/%d => chosen (any? %t): %d[%s] (port: %s)" , cc , city , c , len (out ), chooseAny , r , ids [r ], portstr )
12211255 return out [r ], nil
12221256 }
1257+ if tot == 0 || v <= x { // fail open if all CCs excluded
1258+ logew (retried )("ws: conf: cc %s(%s): all visited(%d) / excluded(%d) / bad(%d); tot: %d / excl: %d; retry?" ,
1259+ cc , city , v , x , badc , tot , len (excl ), ! retried )
1260+ if ! retried {
1261+ clear (excl ) // fail open; excluded none
1262+ clear (visited )
1263+ retried = true
1264+ goto reconf
1265+ }
1266+ }
12231267 log .E ("ws: conf: cc %s(%s) not found (tot: %d)" , cc , city , tot )
12241268 return "" , errWsNoCcConfig
12251269}
@@ -2555,6 +2599,22 @@ func createPermaCreds(h *http.Client, ent *WsEntitlement, bearer, pubkey string)
25552599 return & cfg , nil
25562600}
25572601
2602+ // ccCsvAsSet mods a csv of country codes into a set.
2603+ func ccCsvAsSet (csv string ) map [string ]struct {} {
2604+ if len (csv ) <= 0 {
2605+ return nil
2606+ }
2607+ parts := strings .Split (csv , "," )
2608+ out := make (map [string ]struct {}, len (parts ))
2609+ for _ , p := range parts {
2610+ p = strings .ToUpper (strings .TrimSpace (p ))
2611+ if len (p ) > 0 {
2612+ out [p ] = struct {}{}
2613+ }
2614+ }
2615+ return out
2616+ }
2617+
25582618func wsBriefPauseBeforeRetry () {
25592619 time .Sleep (2200 * time .Millisecond )
25602620}
@@ -2566,6 +2626,13 @@ func loge(err error) log.LogFn {
25662626 return log .E
25672627}
25682628
2629+ func logew (cond bool ) log.LogFn {
2630+ if cond {
2631+ return log .E
2632+ }
2633+ return log .W
2634+ }
2635+
25692636func sha (p string ) []byte {
25702637 return shab ([]byte (p ))
25712638}
0 commit comments