mirror of https://github.com/cbeuw/Cloak
ServerName rotation (#158)
* 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 <cbeuw.andy@gmail.com>
This commit is contained in:
parent
91106f3c49
commit
ae14e28999
|
|
@ -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
|
`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.
|
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
|
`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
|
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
|
commandline argument (in standalone mode), or by Shadowsocks (in plugin mode). After a TLS session is established with
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,11 @@ func main() {
|
||||||
log.Infof("Listening on %v %v for %v client", network, localConfig.LocalAddr, authInfo.ProxyMethod)
|
log.Infof("Listening on %v %v for %v client", network, localConfig.LocalAddr, authInfo.ProxyMethod)
|
||||||
seshMaker = func() *mux.Session {
|
seshMaker = func() *mux.Session {
|
||||||
authInfo := authInfo // copy the struct because we are overwriting SessionId
|
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 usergenerated. There shouldn't be a security concern because the scope of
|
||||||
// sessionID is limited to its UID.
|
// sessionID is limited to its UID.
|
||||||
quad := make([]byte, 4)
|
quad := make([]byte, 4)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
// +build android
|
// +build android
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
// Stolen from https://github.com/shadowsocks/overture/blob/shadowsocks/core/utils/utils_android.go
|
// Stolen from https://github.com/shadowsocks/overture/blob/shadowsocks/core/utils/utils_android.go
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,11 @@ type RawConfig struct {
|
||||||
UID []byte
|
UID []byte
|
||||||
PublicKey []byte
|
PublicKey []byte
|
||||||
NumConn int
|
NumConn int
|
||||||
LocalHost string // jsonOptional
|
LocalHost string // jsonOptional
|
||||||
LocalPort string // jsonOptional
|
LocalPort string // jsonOptional
|
||||||
RemoteHost string // jsonOptional
|
RemoteHost string // jsonOptional
|
||||||
RemotePort string // jsonOptional
|
RemotePort string // jsonOptional
|
||||||
|
AlternativeNames []string // jsonOptional
|
||||||
// defaults set in ProcessRawConfig
|
// defaults set in ProcessRawConfig
|
||||||
UDP bool // nullable
|
UDP bool // nullable
|
||||||
BrowserSig string // nullable
|
BrowserSig string // nullable
|
||||||
|
|
@ -49,8 +49,9 @@ type RemoteConnConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type LocalConnConfig struct {
|
type LocalConnConfig struct {
|
||||||
LocalAddr string
|
LocalAddr string
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
|
MockDomainList []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthInfo struct {
|
type AuthInfo struct {
|
||||||
|
|
@ -94,6 +95,20 @@ func ssvToJson(ssv string) (ret []byte) {
|
||||||
}
|
}
|
||||||
key := sp[0]
|
key := sp[0]
|
||||||
value := sp[1]
|
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
|
// JSON doesn't like quotation marks around int and bool
|
||||||
// This is extremely ugly but it's still better than writing a tokeniser
|
// This is extremely ugly but it's still better than writing a tokeniser
|
||||||
if elem(key, unquoted) {
|
if elem(key, unquoted) {
|
||||||
|
|
@ -139,6 +154,8 @@ func (raw *RawConfig) ProcessRawConfig(worldState common.WorldState) (local Loca
|
||||||
return nullErr("ServerName")
|
return nullErr("ServerName")
|
||||||
}
|
}
|
||||||
auth.MockDomain = raw.ServerName
|
auth.MockDomain = raw.ServerName
|
||||||
|
local.MockDomainList = raw.AlternativeNames
|
||||||
|
local.MockDomainList = append(local.MockDomainList, auth.MockDomain)
|
||||||
if raw.ProxyMethod == "" {
|
if raw.ProxyMethod == "" {
|
||||||
return nullErr("ServerName")
|
return nullErr("ServerName")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue