mirror of https://github.com/cbeuw/Cloak
Compare commits
8 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
bea21b7166 | |
|
|
8317f447d1 | |
|
|
ba7f29d9e6 | |
|
|
10c17c4aca | |
|
|
930e647226 | |
|
|
7be1586973 | |
|
|
a3c3a9b03f | |
|
|
2dd48ef71e |
19
README.md
19
README.md
|
|
@ -1,11 +1,11 @@
|
|||
# Cloak
|
||||
A Shadowsocks plugin that obfuscates the traffic as normal HTTPS traffic and disguises the proxy server as a normal webserver.
|
||||
A Shadowsocks plugin that obfuscates the traffic as normal HTTPS traffic to non-blocked websites through domain fronting and disguises the proxy server as a normal webserver.
|
||||
|
||||
Cloak multiplexes all traffic through a fixed amount of underlying TCP connections which eliminates the TCP handshake overhead when using vanilla Shadowsocks. Cloak also provides user management, allowing multiple users to connect to the proxy server using **one single port**. It also provides QoS controls for individual users such as upload and download credit limit, as well as bandwidth control.
|
||||
|
||||
To external observers (such as the GFW), Cloak is completely transparent and behaves like an ordinary HTTPS server. This is done through several [cryptographic mechanisms](https://github.com/cbeuw/Cloak/wiki/Cryptographic-Mechanisms). This eliminates the risk of being detected by traffic analysis and/or active probing
|
||||
To external observers (such as the GFW), Cloak is completely transparent and behaves like an ordinary HTTPS server. This is done through several [cryptographic mechanisms](https://github.com/cbeuw/Cloak/wiki/Cryptographic-Mechanisms). This eliminates the risk of being detected by traffic analysis and/or active probing.
|
||||
|
||||
This project is based on my previous project [GoQuiet](https://github.com/cbeuw/GoQuiet). The most significant improvement form GoQuiet is that there will not be new TLS handshake being done each time a client application establishes a new connection to the Shadowsocks client. This gives a siginifcant boost to webpage loading time (reduction in time ranges from 10% to 50+%, depending on the amount of content on the webpage, see [benchmarks](https://github.com/cbeuw/Cloak/wiki/Web-page-loading-benchmarks)).
|
||||
This project is based on a previous project [GoQuiet](https://github.com/cbeuw/GoQuiet). Through multiplexing, Cloak provides a siginifcant reduction in webpage loading time compared to GoQuiet (from 10% to 50+%, depending on the amount of content on the webpage, see [benchmarks](https://github.com/cbeuw/Cloak/wiki/Web-page-loading-benchmarks)).
|
||||
|
||||
## Build
|
||||
Simply `make client` and `make server`. Output binary will be in the build folder.
|
||||
|
|
@ -20,7 +20,7 @@ Do `make server_pprof` if you want to access the live profiling data.
|
|||
|
||||
`AdminUID` is the UID of the admin user in base64.
|
||||
|
||||
`DatabasePath` is the path to userinfo.db. If userinfo.db doesn't exist in this directory, Cloak will create one automatically. **If Cloak is started as a Shadowsocks plugin and Shadowsocks is started with its working directory as / (e.g. starting ss-server with systemctl), you need to set this field as an absolute path to a desired folder. If you leave it as default then Cloak will attempt to create userinfo.db under /, which it doesn't have the permission to do so and will raise an error. See Issue #13.
|
||||
`DatabasePath` is the path to userinfo.db. If userinfo.db doesn't exist in this directory, Cloak will create one automatically. **If Cloak is started as a Shadowsocks plugin and Shadowsocks is started with its working directory as / (e.g. starting ss-server with systemctl), you need to set this field as an absolute path to a desired folder. If you leave it as default then Cloak will attempt to create userinfo.db under /, which it doesn't have the permission to do so and will raise an error. See Issue #13.**
|
||||
|
||||
`BackupDirPath` is the path to save the backups of userinfo.db whenever you delete a user. If left blank, Cloak will attempt to create a folder called db-backup under its working directory. This may not be desired. See notes above.
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ Do `make server_pprof` if you want to access the live profiling data.
|
|||
|
||||
## Setup
|
||||
### For the administrator of the server
|
||||
**Run this script: https://gist.github.com/cbeuw/37a9d434c237840d7e6d5e497539c1ca** or do it manually:
|
||||
**Run this script: https://github.com/HirbodBehnam/Shadowsocks-Cloak-Installer/blob/master/Shadowsocks-Cloak-Installer.sh (thanks to [@HirbodBehnam](https://github.com/HirbodBehnam))** or do it manually:
|
||||
|
||||
0. [Install and configure shadowsocks-libev on your server](https://github.com/shadowsocks/shadowsocks-libev#installation)
|
||||
1. Download [the latest release](https://github.com/cbeuw/Cloak/releases) or clone and build this repo. If you wish to build it, make sure you fetch the dependencies using `go get github.com/boltdb/bolt`, `go get github.com/juju/ratelimit` and `go get golang.org/x/crypto/curve25519`
|
||||
|
|
@ -66,3 +66,12 @@ Note: the user database is persistent as it's in-disk. You don't need to add the
|
|||
2. Obtain the public key and your UID (or the AdminUID, if you are the server admin) from the administrator of your server
|
||||
3. Put the public key and the UID you obtained into config/ckclient.json
|
||||
4. Configure your shadowsocks client with your server information. The field `plugin` should be the path to ck-server binary and `plugin_opts` should be the path to ckclient.json
|
||||
|
||||
## Support me
|
||||
If you find this project useful, donations are greatly appreciated!
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SAUYKGSREP8GL&source=url)
|
||||
|
||||
BTC: `bc1q59yvpnh0356qq9vf0j2y7hx36t9ysap30spx9h`
|
||||
|
||||
ETH: `0x8effF29a8F9bD38A367580527AC303972c92b60c`
|
||||
|
|
|
|||
|
|
@ -85,6 +85,41 @@ func makeRemoteConn(sta *client.State) (net.Conn, error) {
|
|||
|
||||
}
|
||||
|
||||
func makeSession(sta *client.State) *mux.Session {
|
||||
log.Println("Attemtping to start a new session")
|
||||
// sessionID is usergenerated. There shouldn't be a security concern because the scope of
|
||||
// sessionID is limited to its UID.
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
sessionID := rand.Uint32()
|
||||
sta.SetSessionID(sessionID)
|
||||
var UNLIMITED_DOWN int64 = 1e15
|
||||
var UNLIMITED_UP int64 = 1e15
|
||||
valve := mux.MakeValve(1e12, 1e12, &UNLIMITED_DOWN, &UNLIMITED_UP)
|
||||
obfs := mux.MakeObfs(sta.UID)
|
||||
deobfs := mux.MakeDeobfs(sta.UID)
|
||||
sesh := mux.MakeSession(sessionID, valve, obfs, deobfs, util.ReadTLS)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < sta.NumConn; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
makeconn:
|
||||
conn, err := makeRemoteConn(sta)
|
||||
if err != nil {
|
||||
log.Printf("Failed to establish new connections to remote: %v\n", err)
|
||||
time.Sleep(time.Second * 3)
|
||||
goto makeconn
|
||||
}
|
||||
sesh.AddConnection(conn)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
log.Printf("Session %v established", sessionID)
|
||||
return sesh
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Should be 127.0.0.1 to listen to ss-local on this machine
|
||||
var localHost string
|
||||
|
|
@ -170,48 +205,17 @@ func main() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
start:
|
||||
log.Println("Attemtping to start a new session")
|
||||
// sessionID is usergenerated. There shouldn't be a security concern because the scope of
|
||||
// sessionID is limited to its UID.
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
sessionID := rand.Uint32()
|
||||
sta.SetSessionID(sessionID)
|
||||
var UNLIMITED_DOWN int64 = 1e15
|
||||
var UNLIMITED_UP int64 = 1e15
|
||||
valve := mux.MakeValve(1e12, 1e12, &UNLIMITED_DOWN, &UNLIMITED_UP)
|
||||
obfs := mux.MakeObfs(sta.UID)
|
||||
deobfs := mux.MakeDeobfs(sta.UID)
|
||||
sesh := mux.MakeSession(sessionID, valve, obfs, deobfs, util.ReadTLS)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < sta.NumConn; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
makeconn:
|
||||
conn, err := makeRemoteConn(sta)
|
||||
if err != nil {
|
||||
log.Printf("Failed to establish new connections to remote: %v\n", err)
|
||||
time.Sleep(time.Second * 3)
|
||||
goto makeconn
|
||||
}
|
||||
sesh.AddConnection(conn)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
log.Printf("Session %v established", sessionID)
|
||||
var sesh *mux.Session
|
||||
|
||||
for {
|
||||
if sesh.IsBroken() {
|
||||
goto start
|
||||
}
|
||||
ssConn, err := listener.Accept()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
if sesh == nil || sesh.IsBroken() {
|
||||
sesh = makeSession(sta)
|
||||
}
|
||||
go func() {
|
||||
data := make([]byte, 10240)
|
||||
i, err := io.ReadAtLeast(ssConn, data, 1)
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ func MakeSession(id uint32, valve *Valve, obfs Obfser, deobfs Deobfser, obfsedRe
|
|||
die: make(chan struct{}),
|
||||
}
|
||||
sesh.sb = makeSwitchboard(sesh, valve)
|
||||
go sesh.timeoutAfter(30 * time.Second)
|
||||
return sesh
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,7 +112,9 @@ func (sb *switchboard) removeConn(closing *connEnclave) {
|
|||
}
|
||||
}
|
||||
if len(sb.ces) == 0 {
|
||||
sb.cesM.Unlock()
|
||||
sb.session.Close()
|
||||
return
|
||||
}
|
||||
sb.cesM.Unlock()
|
||||
}
|
||||
|
|
@ -132,13 +134,13 @@ func (sb *switchboard) deplex(ce *connEnclave) {
|
|||
buf := make([]byte, 20480)
|
||||
for {
|
||||
n, err := sb.session.obfsedRead(ce.remoteConn, buf)
|
||||
sb.rxWait(n)
|
||||
if err != nil {
|
||||
//log.Println(err)
|
||||
go ce.remoteConn.Close()
|
||||
sb.removeConn(ce)
|
||||
return
|
||||
}
|
||||
sb.rxWait(n)
|
||||
if sb.AddRxCredit(-int64(n)) < 0 {
|
||||
log.Println(ErrNoRxCredit)
|
||||
sb.session.Close()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package usermanager
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"os"
|
||||
|
|
@ -308,7 +307,7 @@ func (up *Userpanel) addNewUser(uinfo UserInfo) error {
|
|||
}
|
||||
|
||||
func (up *Userpanel) delUser(UID []byte) error {
|
||||
err := up.backupDB(strconv.FormatInt(time.Now().Unix(), 10) + "_pre_del_" + base64.StdEncoding.EncodeToString(UID) + ".bak")
|
||||
err := up.backupDB(strconv.FormatInt(time.Now().Unix(), 10) + ".bak")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue