Skip to content

Commit 2700451

Browse files
committed
Shoco lib, better compression, license
1 parent d3593b2 commit 2700451

18 files changed

+26449
-15
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
top-1m.csv

LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 coyove <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.
22+

config/config.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ var (
1616
G_Password = flag.String("p", "password", "proxy password")
1717
G_Upstream = flag.String("up", "", "upstream server address (e.g. 127.0.0.1:8100)")
1818
G_Local = flag.String("l", ":8100", "local listening")
19-
G_Dummies = flag.String("dummy", "", "dummy hosts, separated by |")
19+
G_Dummies = flag.String("dummy", "china", "dummy hosts, separated by |")
2020

2121
G_Debug = flag.Bool("debug", false, "debug mode")
2222
G_UnsafeHttp = flag.Bool("disable-sh", false, "do not encrypt http content")
2323
G_NoPA = flag.Bool("disable-pa", false, "disable proxy authentication")
24+
G_NoShoco = flag.Bool("disable-shoco", false, "disable shoco compression")
2425
G_ProxyAll = flag.Bool("all", false, "proxy Chinese websites")
2526

2627
G_SuppressSocketReadWriteError = flag.Bool("ssrwe", false, "suppress socket read/write error")
@@ -80,6 +81,7 @@ func LoadConfig(path string) {
8081
setBool(G_UnsafeHttp, m["unsafehttp"])
8182
setBool(G_SuppressSocketReadWriteError, m["ssrwe"])
8283
setBool(G_NoPA, m["disablepa"])
84+
setBool(G_NoShoco, m["disableshoco"])
8385
setBool(G_ProxyAll, m["proxyall"])
8486

8587
setInt(G_DNSCacheEntries, m["dnscache"])

lookup/lookup.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func IsPrivateIP(ip string) bool {
8282
func LookupIP(host string) string {
8383
ip, err := net.ResolveIPAddr("ip4", host)
8484
if err != nil {
85-
logg.L("dns lookup: ", err)
85+
logg.L("[DNS] ", err)
8686
return ""
8787
}
8888

lru/lru.go

+9-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package lru
33
import (
44
"container/list"
55
"sync"
6+
7+
"../logg"
68
)
79

810
type Cache struct {
@@ -50,9 +52,11 @@ func (c *Cache) Clear() {
5052
func (c *Cache) Info(callback func(Key, interface{}, int64)) {
5153
c.RLock()
5254
f := c.ll.Front()
55+
r := 0
5356

54-
for {
55-
if f == nil {
57+
for f != nil {
58+
if r++; r > c.MaxEntries {
59+
logg.E("something bad happened: we had a loop")
5660
break
5761
}
5862

@@ -84,7 +88,7 @@ func (c *Cache) Add(key Key, value interface{}) {
8488
return
8589
}
8690

87-
ele := c.ll.PushFront(&entry{key, value, 0})
91+
ele := c.ll.PushFront(&entry{key, value, 1})
8892
c.cache[key] = ele
8993
if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries {
9094
c.removeOldest()
@@ -125,8 +129,8 @@ func (c *Cache) Remove(key Key) {
125129

126130
// Len returns the number of items in the cache.
127131
func (c *Cache) Len() int {
128-
c.Lock()
129-
defer c.Unlock()
132+
c.RLock()
133+
defer c.RUnlock()
130134

131135
if c.cache == nil {
132136
return 0

proxy/proxy.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request)
8888
return
8989
}
9090

91-
rkey := RandomKey()
91+
rkey, rhost := RandomKey(), dummyHosts[NewRand().Intn(len(dummyHosts))]
9292
upstreamConn.Write([]byte(fmt.Sprintf(
93-
"CONNECT www.baidu.com HTTP/1.1\r\nHost: www.baidu.com\r\nX-Forwarded-Host: %s\r\n%s: %s\r\n\r\n", host, rkeyHeader, rkey)))
93+
"CONNECT www.%s.com HTTP/1.1\r\nHost: www.%s.com\r\nX-Forwarded-Host: %s\r\n%s: %s\r\n\r\n", rhost, rhost, host, rkeyHeader, rkey)))
9494

9595
TwoWayBridge(proxyClient, upstreamConn, rkey)
9696
} else {
@@ -219,15 +219,15 @@ func (proxy *ProxyHttpServer) CanDirectConnect(host string) bool {
219219
resp, err := client.Do(req)
220220

221221
if err != nil {
222-
logg.W("host lookup: ", err)
222+
logg.W("[REMOTE LOOKUP] ", err)
223223
return maybeChinese
224224
}
225225

226226
ipbuf, err := ioutil.ReadAll(resp.Body)
227227
tryClose(resp.Body)
228228

229229
if err != nil {
230-
logg.W("host lookup: ", err)
230+
logg.W("[REMOTE LOOKUP] ", err)
231231
return maybeChinese
232232
}
233233

proxy/util.go

+40-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
. "../config"
55
"../logg"
66
"../lru"
7+
"../shoco"
78

89
"bytes"
910
"crypto/tls"
@@ -17,6 +18,7 @@ import (
1718
"net/http"
1819
"net/url"
1920
"regexp"
21+
"strconv"
2022
"strings"
2123
"sync"
2224
"time"
@@ -31,7 +33,7 @@ var (
3133
dnsHeaderID = "X-Host-Lookup-ID"
3234
dnsHeader = "X-Host-Lookup"
3335

34-
hostHeadHolder = "%s.%s.com:433"
36+
hostHeadHolder = "%s.%s.com:%d"
3537
dummyHosts = append([]string{"baidu", "qq", "taobao", "sina", "163", "youku"}, strings.Split(*G_Dummies, "|")...)
3638
hostHeadExtract = regexp.MustCompile(`(\S+)\.(?:` + strings.Join(dummyHosts, "|") + `)\.com`)
3739
urlExtract = regexp.MustCompile(`\?q=(\S+)$`)
@@ -149,13 +151,47 @@ func DecryptRequest(req *http.Request) string {
149151
return rkey
150152
}
151153

154+
func SplitHostPort(host string) (string, int) {
155+
if idx := strings.Index(host, ":"); idx > 0 {
156+
n, err := strconv.Atoi(host[idx+1:])
157+
if err != nil {
158+
logg.E("cannot split: ", host)
159+
return host, 80
160+
}
161+
162+
return host[:idx], n
163+
} else {
164+
return host, 80
165+
}
166+
}
167+
152168
func EncryptHost(host string) string {
153-
return fmt.Sprintf(hostHeadHolder, Skip32EncodeString(G_KeyBytes, host), dummyHosts[NewRand().Intn(len(dummyHosts))])
169+
h, p := SplitHostPort(host)
170+
dummy := dummyHosts[NewRand().Intn(len(dummyHosts))]
171+
172+
if *G_NoShoco {
173+
return fmt.Sprintf(hostHeadHolder, Skip32EncodeString(G_KeyBytes, h), dummy, p)
174+
}
175+
176+
x := Base36Encode(Skip32Encode(G_KeyBytes, shoco.CompressHost(h), false))
177+
return fmt.Sprintf(hostHeadHolder, x, dummy, p)
154178
}
155179

156180
func DecryptHost(host string) string {
157-
if p := hostHeadExtract.FindStringSubmatch(host); len(p) > 1 {
158-
return Skip32DecodeString(G_KeyBytes, p[1])
181+
defer func() {
182+
if r := recover(); r != nil {
183+
logg.E("[SHOCO] - ", r)
184+
}
185+
}()
186+
187+
h, p := SplitHostPort(host)
188+
189+
if s := hostHeadExtract.FindStringSubmatch(h); len(s) > 1 {
190+
if *G_NoShoco {
191+
return Skip32DecodeString(G_KeyBytes, s[1]) + ":" + strconv.Itoa(p)
192+
}
193+
194+
return shoco.DecompressHost(Skip32Decode(G_KeyBytes, Base36Decode(s[1]), false)) + ":" + strconv.Itoa(p)
159195
}
160196

161197
return ""

shoco/LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2014 Christian Schramm <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.
22+

0 commit comments

Comments
 (0)