From 7fe3c1d552e9a49f75b86198a51dbaa91bc6dca3 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Fri, 22 Nov 2013 13:32:32 +0800 Subject: [PATCH 1/6] Reset server conn state after getting from pool. --- proxy.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/proxy.go b/proxy.go index 5cae3742..e09b0c53 100644 --- a/proxy.go +++ b/proxy.go @@ -693,6 +693,10 @@ func (c *clientConn) getServerConn(r *Request) (*serverConn, error) { } sv := connPool.Get(r.URL.HostPort, siteInfo.AsDirect()) if sv != nil { + // For websites like feedly, the site itself is not blocked, but the + // content it loads may result reset. So we should reset server + // connection state to just connected. + sv.state = svConnected if debug { debug.Printf("cli(%s) connPool get %s\n", c.RemoteAddr(), r.URL.HostPort) } From 091d879367aaf44a40994e67c8d8ca11560819a2 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Fri, 22 Nov 2013 14:22:08 +0800 Subject: [PATCH 2/6] Avoid stat corruption caused by signal during saving. --- sitestat.go | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/sitestat.go b/sitestat.go index 4acebce7..75e1e7b7 100644 --- a/sitestat.go +++ b/sitestat.go @@ -288,14 +288,27 @@ func (ss *SiteStat) store(file string) (err error) { panic("internal error: error marshalling site") } - f, err := os.Create(file) + // Store stat into temp file first and then rename. + // This avoids problem if SIGINT causes program to exit but stat writing + // is half done. + + f, err := ioutil.TempFile("", "stat") if err != nil { - errl.Println("Can't create stat file:", err) + errl.Println("create tmp file to store stat", err) return } - defer f.Close() if _, err = f.Write(b); err != nil { errl.Println("Error writing stat file:", err) + f.Close() + return + } + f.Close() + + // Windows don't allow rename to existing file. + os.Remove(file + ".bak") + os.Rename(file, file+".bak") // original stat may not exist + if err = os.Rename(f.Name(), file); err != nil { + errl.Println("can't rename newly created stat file", err) return } return @@ -425,8 +438,12 @@ func initSiteStat() { }() } +var storeLock sync.Mutex + func storeSiteStat() { + storeLock.Lock() siteStat.store(dsFile.stat) + storeLock.Unlock() } func loadSiteList(fpath string) (lst []string, err error) { From 4abdffcc1ab56267822db76af39de9f25e6efb26 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Fri, 22 Nov 2013 14:24:01 +0800 Subject: [PATCH 3/6] Tweak parent proxy connection error message. --- parent_proxy.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/parent_proxy.go b/parent_proxy.go index 22875a4a..05b15225 100644 --- a/parent_proxy.go +++ b/parent_proxy.go @@ -137,11 +137,11 @@ func (hp *httpParent) initAuth(userPasswd string) { func (hp *httpParent) connect(url *URL) (net.Conn, error) { c, err := net.Dial("tcp", hp.server) if err != nil { - errl.Printf("can't connect to http parent proxy %s for %s: %v\n", + errl.Printf("can't connect to http parent %s for %s: %v\n", hp.server, url.HostPort, err) return nil, err } - debug.Printf("connected to: %s via http parent proxy: %s\n", + debug.Printf("connected to: %s via http parent: %s\n", url.HostPort, hp.server) return httpConn{c, hp}, nil } @@ -192,8 +192,8 @@ func (sp *shadowsocksParent) initCipher(method, passwd string) { func (sp *shadowsocksParent) connect(url *URL) (net.Conn, error) { c, err := ss.Dial(url.HostPort, sp.server, sp.cipher.Copy()) if err != nil { - errl.Printf("create shadowsocks connection to %s through server %s failed %v\n", - url.HostPort, sp.server, err) + errl.Printf("can't connect to shadowsocks parent %s for %s: %v\n", + sp.server, url.HostPort, err) return nil, err } debug.Println("connected to:", url.HostPort, "via shadowsocks:", sp.server) @@ -230,11 +230,11 @@ func (cp *cowParent) genConfig() string { func (cp *cowParent) connect(url *URL) (net.Conn, error) { c, err := net.Dial("tcp", cp.server) if err != nil { - errl.Printf("can't connect to cow parent proxy %s for %s: %v\n", + errl.Printf("can't connect to cow parent %s for %s: %v\n", cp.server, url.HostPort, err) return nil, err } - debug.Printf("connected to: %s via cow parent proxy: %s\n", + debug.Printf("connected to: %s via cow parent: %s\n", url.HostPort, cp.server) ssconn := ss.NewConn(c, cp.cipher.Copy()) return cowConn{ssconn, cp}, nil @@ -287,7 +287,7 @@ func (sp *socksParent) genConfig() string { func (sp *socksParent) connect(url *URL) (net.Conn, error) { c, err := net.Dial("tcp", sp.server) if err != nil { - errl.Printf("can't connect to socks server %s for %s: %v\n", + errl.Printf("can't connect to socks parent %s for %s: %v\n", sp.server, url.HostPort, err) return nil, err } @@ -356,7 +356,7 @@ func (sp *socksParent) connect(url *URL) (net.Conn, error) { errl.Printf("read socks reply err %v n %d\n", err, n) } hasErr = true - return nil, errors.New("Connection failed (by socks server). No such host?") + return nil, errors.New("connection failed (by socks server " + sp.server + "). No such host?") } // debug.Printf("Socks reply length %d\n", n) From ab468039ac7aeb8416cb15d0c0dfe81724f48ee3 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Mon, 2 Dec 2013 20:36:44 +0800 Subject: [PATCH 4/6] Update PAC every minute. --- pac.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pac.go b/pac.go index 1440666c..f49d1f3c 100644 --- a/pac.go +++ b/pac.go @@ -191,12 +191,12 @@ func genPAC(c *clientConn) []byte { } func initPAC() { - // we can't control goroutine scheduling, this is to make sure when + // we can't control goroutine scheduling, make sure when // initPAC is done, direct list is updated updateDirectList() go func() { for { - time.Sleep(5 * time.Minute) + time.Sleep(time.Minute) updateDirectList() } }() From c5432c9610909d97b2c66f52b48bd8e3cf43fb44 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Mon, 2 Dec 2013 20:40:06 +0800 Subject: [PATCH 5/6] Decrease direct/blocked delta value. To make learning take effect faster. --- sitestat.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sitestat.go b/sitestat.go index 75e1e7b7..f11de023 100644 --- a/sitestat.go +++ b/sitestat.go @@ -22,8 +22,8 @@ func init() { // judging whether a site is blocked or not is more reliable. const ( - directDelta = 15 - blockedDelta = 10 + directDelta = 5 + blockedDelta = 5 maxCnt = 100 // no protect to update visit cnt, smaller value is unlikely to overflow userCnt = -1 // this represents user specified host or domain ) From adc0b7e14c5ee9b2cba0731eaa63d3dbcd65c2a2 Mon Sep 17 00:00:00 2001 From: Chen Yufei Date: Mon, 2 Dec 2013 21:58:55 +0800 Subject: [PATCH 6/6] Bump version to 0.9 --- CHANGELOG | 6 ++++-- README.md | 6 +++--- config.go | 2 +- doc/sample-config/rc | 2 +- install-cow.sh | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6a6ba358..9645e85a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,12 @@ -0.9 (Not released) +0.9 (2013-12-02) * New feature: two COW servers can be connected using encrypted connection, thus we have an encrypted HTTP proxy chain that can be used to bypass the firewall * Allow client to use HTTP basic authentication - * Simplified configuration syntax + * Simplify configuration syntax * Better reuse for HTTP parent connections + * Reduce direct/blocked delta + * Generate new PAC every minute 0.8 (2013-08-10) * Share server connections between different clients diff --git a/README.md b/README.md index 6deeb3de..e44865c2 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ COW 是一个简化穿墙的 HTTP 代理服务器。它能自动检测被墙网站,仅对这些网站使用二级代理。 -当前版本:0.9-rc1 [CHANGELOG](CHANGELOG) +当前版本:0.9 [CHANGELOG](CHANGELOG) [![Build Status](https://travis-ci.org/cyfdecyf/cow.png?branch=develop)](https://travis-ci.org/cyfdecyf/cow) **欢迎在 develop branch 进行开发并发送 pull request :)** @@ -18,7 +18,7 @@ COW 的设计目标是自动化,理想情况下用户无需关心哪些网站 - 自动生成包含直连网站的 PAC,访问这些网站时可绕过 COW - 内置[常见可直连网站](site_direct.go),如国内社交、视频、银行、电商等网站(可手工添加) -# Quick Start +# 快速开始 安装: @@ -27,7 +27,7 @@ COW 的设计目标是自动化,理想情况下用户无需关心哪些网站 curl -L git.io/cow | bash - **Windows:** [点此下载](http://dl.chenyufei.info/cow/) -- 熟悉 Go 的用户可用 `go get` 从源码安装 +- 熟悉 Go 的用户可用 `go get github.com/cyfdecyf/cow` 从源码安装 编辑 `~/.cow/rc` (Linux) 或 `rc.txt` (Windows),简单的配置例子如下: diff --git a/config.go b/config.go index 90776421..2f7b7c58 100644 --- a/config.go +++ b/config.go @@ -15,7 +15,7 @@ import ( ) const ( - version = "0.9-rc1" + version = "0.9" defaultListenAddr = "127.0.0.1:7777" ) diff --git a/doc/sample-config/rc b/doc/sample-config/rc index c3f1e4d8..f00578c2 100644 --- a/doc/sample-config/rc +++ b/doc/sample-config/rc @@ -66,7 +66,7 @@ listen = http://127.0.0.1:7777 # # authinfo 中指定加密方法和密码,所有支持的加密方法如下: # aes-128-cfb, aes-192-cfb, aes-256-cfb, -# bf-cfb, cast5-cfb, des-cfb +# bf-cfb, cast5-cfb, des-cfb, table, rc4 # 推荐使用 aes-128-cfb # # cow: diff --git a/install-cow.sh b/install-cow.sh index 14572cff..3a962de2 100755 --- a/install-cow.sh +++ b/install-cow.sh @@ -1,6 +1,6 @@ #!/bin/bash -version=0.9-rc1 +version=0.9 arch=`uname -m` case $arch in