Skip to content

Commit

Permalink
ServerName rotation (#158)
Browse files Browse the repository at this point in the history
* inital servername rotation

* Move MockDomainList to LocalConnConfig as the list doesn't need to be sent to the remote

* Use CSPRNG to pick the next candidate of MockDomains

Co-authored-by: Andy Wang <[email protected]>
  • Loading branch information
lima0 and cbeuw authored Mar 25, 2021
1 parent 91106f3 commit ae14e28
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 7 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ encryption and authentication (via AEAD or similar techniques).**
`ServerName` is the domain you want to make your ISP or firewall _think_ you are visiting. Ideally it should
match `RedirAddr` in the server's configuration, a major site the censor allows, but it doesn't have to.

`AlternativeNames` is an array used alongside `ServerName` to shuffle between different ServerNames for every new connection

`CDNOriginHost` is the domain name of the _origin_ server (i.e. the server running Cloak) under `CDN` mode. This only
has effect when `Transport` is set to `CDN`. If unset, it will default to the remote hostname supplied via the
commandline argument (in standalone mode), or by Shadowsocks (in plugin mode). After a TLS session is established with
Expand Down
5 changes: 5 additions & 0 deletions cmd/ck-client/ck-client.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ func main() {
log.Infof("Listening on %v %v for %v client", network, localConfig.LocalAddr, authInfo.ProxyMethod)
seshMaker = func() *mux.Session {
authInfo := authInfo // copy the struct because we are overwriting SessionId

randByte := make([]byte, 1)
common.RandRead(authInfo.WorldState.Rand, randByte)
authInfo.MockDomain = localConfig.MockDomainList[int(randByte[0])%len(localConfig.MockDomainList)]

// sessionID is usergenerated. There shouldn't be a security concern because the scope of
// sessionID is limited to its UID.
quad := make([]byte, 4)
Expand Down
1 change: 1 addition & 0 deletions cmd/ck-client/protector_android.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// +build android

package main

// Stolen from https://github.com/shadowsocks/overture/blob/shadowsocks/core/utils/utils_android.go
Expand Down
31 changes: 24 additions & 7 deletions internal/client/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ type RawConfig struct {
UID []byte
PublicKey []byte
NumConn int
LocalHost string // jsonOptional
LocalPort string // jsonOptional
RemoteHost string // jsonOptional
RemotePort string // jsonOptional

LocalHost string // jsonOptional
LocalPort string // jsonOptional
RemoteHost string // jsonOptional
RemotePort string // jsonOptional
AlternativeNames []string // jsonOptional
// defaults set in ProcessRawConfig
UDP bool // nullable
BrowserSig string // nullable
Expand All @@ -49,8 +49,9 @@ type RemoteConnConfig struct {
}

type LocalConnConfig struct {
LocalAddr string
Timeout time.Duration
LocalAddr string
Timeout time.Duration
MockDomainList []string
}

type AuthInfo struct {
Expand Down Expand Up @@ -94,6 +95,20 @@ func ssvToJson(ssv string) (ret []byte) {
}
key := sp[0]
value := sp[1]
if strings.HasPrefix(key, "AlternativeNames") {
switch strings.Contains(value, ",") {
case true:
domains := strings.Split(value, ",")
for index, domain := range domains {
domains[index] = `"` + domain + `"`
}
value = strings.Join(domains, ",")
ret = append(ret, []byte(`"`+key+`":[`+value+`],`)...)
case false:
ret = append(ret, []byte(`"`+key+`":["`+value+`"],`)...)
}
continue
}
// JSON doesn't like quotation marks around int and bool
// This is extremely ugly but it's still better than writing a tokeniser
if elem(key, unquoted) {
Expand Down Expand Up @@ -139,6 +154,8 @@ func (raw *RawConfig) ProcessRawConfig(worldState common.WorldState) (local Loca
return nullErr("ServerName")
}
auth.MockDomain = raw.ServerName
local.MockDomainList = raw.AlternativeNames
local.MockDomainList = append(local.MockDomainList, auth.MockDomain)
if raw.ProxyMethod == "" {
return nullErr("ServerName")
}
Expand Down

0 comments on commit ae14e28

Please sign in to comment.