Skip to content

Commit

Permalink
Merge branch 'develop', version 0.9.5
Browse files Browse the repository at this point in the history
  • Loading branch information
cyfdecyf committed May 12, 2015
2 parents b465963 + f3ae2bf commit 0dab521
Show file tree
Hide file tree
Showing 16 changed files with 74 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
@@ -1,6 +1,6 @@
language: go
go:
- 1.3
- 1.4.2
env:
- TRAVIS="yes"
install:
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG
@@ -1,3 +1,10 @@
0.9.5 (2015-05-12)
* Support new encryption method "chacha20" and "salsa20"
* Avoid biased parent proxy selection for hash load balacing
* Fix AirDrop on OS X when using PAC
* Fix failed start with corrupted stat file
* Support changing the estimate timeout target

0.9.4 (2014-10-08)
* Bug fix (#179): close stat file after load

Expand Down
7 changes: 4 additions & 3 deletions README.md
Expand Up @@ -4,7 +4,7 @@ COW 是一个简化穿墙的 HTTP 代理服务器。它能自动检测被墙网

[English README](README-en.md).

当前版本:0.9.4 [CHANGELOG](CHANGELOG)
当前版本:0.9.5 [CHANGELOG](CHANGELOG)
[![Build Status](https://travis-ci.org/cyfdecyf/cow.png?branch=master)](https://travis-ci.org/cyfdecyf/cow)

**欢迎在 develop branch 进行开发并发送 pull request :)**
Expand Down Expand Up @@ -37,6 +37,7 @@ COW 的设计目标是自动化,理想情况下用户无需关心哪些网站
#开头的行是注释,会被忽略
# 本地 HTTP 代理地址
# 配置 HTTP 和 HTTPS 代理时请填入该地址
# 若配置代理时有对所有协议使用该代理的选项,且你不清楚此选项的含义,请勾选
# 或者在自动代理配置中填入 http://127.0.0.1:7777/pac
listen = http://127.0.0.1:7777

Expand Down Expand Up @@ -120,14 +121,14 @@ COW 默认配置下检测到被墙后,过两分钟再次尝试直连也是为
- 不提供 cache
- 不支持 HTTP pipeline(Chrome, Firefox 默认都没开启 pipeline,支持这个功能容易增加问题而好处并不明显)

# 致谢
# 致谢 (Acknowledgements)

贡献代码:

- @tevino: http parent proxy basic authentication
- @xupefei: 提供 cow-hide.exe 以在 windows 上在后台执行 cow.exe
- @sunteya: 改进启动和安装脚本
- @fzerorubigd: identify blocked site by HTTP error code
- @fzerorubigd: identify blocked site by HTTP error code and various bug fixes

Bug reporter:

Expand Down
17 changes: 13 additions & 4 deletions config.go
Expand Up @@ -4,19 +4,21 @@ import (
"errors"
"flag"
"fmt"
"github.com/cyfdecyf/bufio"
"net"
"os"
"path"
"reflect"
"strconv"
"strings"
"time"

"github.com/cyfdecyf/bufio"
)

const (
version = "0.9.4"
defaultListenAddr = "127.0.0.1:7777"
version = "0.9.5"
defaultListenAddr = "127.0.0.1:7777"
defaultEstimateTarget = "example.com"
)

type LoadBalanceMode byte
Expand Down Expand Up @@ -64,7 +66,8 @@ type Config struct {

// not configurable in config file
PrintVer bool
EstimateTimeout bool // if run estimateTimeout()
EstimateTimeout bool // Whether to run estimateTimeout().
EstimateTarget string // Timeout estimate target site.

// not config option
saveReqLine bool // for http and cow parent, should save request line from client
Expand Down Expand Up @@ -103,6 +106,8 @@ func init() {
for _, port := range defaultTunnelAllowedPort {
config.TunnelAllowedPort[port] = true
}

config.EstimateTarget = defaultEstimateTarget
}

// Whether command line options specifies listen addr
Expand Down Expand Up @@ -560,6 +565,10 @@ func (p configParser) ParseDetectSSLErr(val string) {
config.DetectSSLErr = parseBool(val, "detectSSLErr")
}

func (p configParser) ParseEstimateTarget(val string) {
config.EstimateTarget = val
}

// overrideConfig should contain options from command line to override options
// in config file.
func parseConfig(rc string, override *Config) {
Expand Down
8 changes: 7 additions & 1 deletion doc/sample-config/rc
Expand Up @@ -10,6 +10,8 @@
# listen = http://127.0.0.1:7777
#
# 上面的例子中,cow 生成的 PAC url 为 http://127.0.0.1:7777/pac
# 配置浏览器或系统 HTTP 和 HTTPS 代理时请填入该地址
# 若配置代理时有对所有协议使用该代理的选项,且你不清楚此选项的含义,请勾选
#
# cow (需两个 cow 服务器配合使用):
# listen = cow://encrypt_method:password@1.2.3.4:5678
Expand Down Expand Up @@ -67,7 +69,8 @@ listen = http://127.0.0.1:7777
#
# authinfo 中指定加密方法和密码,所有支持的加密方法如下:
# aes-128-cfb, aes-192-cfb, aes-256-cfb,
# bf-cfb, cast5-cfb, des-cfb, rc4-md5, rc4, table
# bf-cfb, cast5-cfb, des-cfb, rc4-md5,
# chacha20, salsa20, rc4, table
# 推荐使用 aes-128-cfb
#
# cow:
Expand Down Expand Up @@ -124,6 +127,9 @@ listen = http://127.0.0.1:7777
# 最多允许使用多少个 CPU 核
#core = 2

# 检测超时时间使用的网站,最好使用能快速访问的站点
#estimateTarget = example.com

# 允许建立隧道连接的端口,多个端口用逗号分隔,可重复多次
# 默认总是允许下列服务的端口: ssh, http, https, rsync, imap, pop, jabber, cvs, git, svn
# 如需允许其他端口,请用该选项添加
Expand Down
6 changes: 5 additions & 1 deletion doc/sample-config/rc-en
Expand Up @@ -79,7 +79,8 @@ listen = http://127.0.0.1:7777
# Here are the supported encryption methods:
#
# aes-128-cfb, aes-192-cfb, aes-256-cfb,
# bf-cfb, cast5-cfb, des-cfb, rc4-md5, rc4, table
# bf-cfb, cast5-cfb, des-cfb, rc4-md5,
# chacha20, salsa20, rc4, table
#
# aes-128-cfb is recommended.
#
Expand Down Expand Up @@ -145,6 +146,9 @@ listen = http://127.0.0.1:7777
# Maximum CPU core to use.
#core = 2

# cow uses this site to estimate timeout, better to use a fast website.
#estimateTarget = example.com

# Ports allowed to create tunnel (HTTP CONNECT method), comma separated list
# or repeat to append more ports.
# Ports for the following service are allowed by default:
Expand Down
15 changes: 6 additions & 9 deletions estimate_timeout.go
Expand Up @@ -17,11 +17,8 @@ const maxTimeout = 15 * time.Second
var dialTimeout = defaultDialTimeout
var readTimeout = defaultReadTimeout

// use a fast to fetch web site
const estimateSite = "www.baidu.com"

var estimateReq = []byte("GET / HTTP/1.1\r\n" +
"Host: " + estimateSite + "\r\n" +
"Host: " + config.EstimateTarget + "\r\n" +
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:11.0) Gecko/20100101 Firefox/11.0\r\n" +
"Accept: */*\r\n" +
"Accept-Language: en-us,en;q=0.5\r\n" +
Expand All @@ -32,16 +29,16 @@ var estimateReq = []byte("GET / HTTP/1.1\r\n" +
// how much time is spent on connect and fetch. This avoids incorrectly
// considering non-blocked sites as blocked when network connection is bad.
func estimateTimeout() {
// debug.Println("estimating timeout")
//debug.Println("estimating timeout")
buf := connectBuf.Get()
defer connectBuf.Put(buf)
var est time.Duration

start := time.Now()
c, err := net.Dial("tcp", estimateSite+":80")
c, err := net.Dial("tcp", config.EstimateTarget+":80")
if err != nil {
errl.Printf("estimateTimeout: can't connect to %s: %v, network has problem?\n",
estimateSite, err)
config.EstimateTarget, err)
goto onErr
}
defer c.Close()
Expand Down Expand Up @@ -71,7 +68,7 @@ func estimateTimeout() {
}
if err != io.EOF {
errl.Printf("estimateTimeout: error getting %s: %v, network has problem?\n",
estimateSite, err)
config.EstimateTarget, err)
goto onErr
}
est = time.Now().Sub(start) * 10
Expand All @@ -97,7 +94,7 @@ func runEstimateTimeout() {
dialTimeout = config.DialTimeout
for {
estimateTimeout()
time.Sleep(30 * time.Second)
time.Sleep(time.Minute)
}
}

Expand Down
2 changes: 1 addition & 1 deletion http.go
Expand Up @@ -710,7 +710,7 @@ func parseResponse(sv *serverConn, r *Request, rp *Response) (err error) {

//Check for http error code from config file
if config.HttpErrorCode > 0 && rp.Status == config.HttpErrorCode {
errl.Println("Requested http code is raised")
debug.Println("Requested http code is raised")
return CustomHttpErr
}

Expand Down
4 changes: 2 additions & 2 deletions install-cow.sh
@@ -1,6 +1,6 @@
#!/bin/bash

version=0.9.4
version=0.9.5

arch=`uname -m`
case $arch in
Expand Down Expand Up @@ -83,7 +83,7 @@ fi
bin=cow-$os$arch-$version
tmpdir=`mktemp -d /tmp/cow.XXXXXX`
tmpbin=$tmpdir/cow
binary_url="http://dl.chenyufei.info/cow/$bin.gz"
binary_url="http://dl.chenyufei.info/cow/$version/$bin.gz"
echo "Downloading cow binary $binary_url to $tmpbin.gz"
curl -L "$binary_url" -o $tmpbin.gz || \
exit_on_fail "Downloading cow binary failed"
Expand Down
3 changes: 1 addition & 2 deletions main.go
Expand Up @@ -16,8 +16,7 @@ func sigHandler() {
// TODO On Windows, these signals will not be triggered on closing cmd
// window. How to detect this?
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM,
syscall.SIGHUP)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

for sig := range sigChan {
// May handle other signals in the future.
Expand Down
3 changes: 3 additions & 0 deletions pac.go
Expand Up @@ -116,6 +116,9 @@ function host2Domain(host) {
function FindProxyForURL(url, host) {
if (url.substring(0,4) == "ftp:")
return direct;
if (host.indexOf(".local", host.length - 6) !== -1) {
return direct;
}
var domain = host2Domain(host);
if (host.length == domain.length) {
return directAcc[host] ? direct : httpProxy;
Expand Down
9 changes: 8 additions & 1 deletion pac.js
Expand Up @@ -86,6 +86,9 @@ function host2Domain(host) {
function FindProxyForURL(url, host) {
if (url.substring(0,4) == "ftp:")
return direct;
if (host.indexOf(".local", host.length - 6) !== -1) {
return direct;
}
var domain = host2Domain(host);
if (host.length == domain.length) {
return directAcc[host] ? direct : httpProxy;
Expand Down Expand Up @@ -160,7 +163,11 @@ testData = [
{ host: 'foo.baidu.com', mode: httpProxy},
{ host: 'google.com', mode: httpProxy},
{ host: 'www.google.com', mode: httpProxy},
{ host: 'www.google.com.hk', mode: httpProxy}
{ host: 'www.google.com.hk', mode: httpProxy},

// host in local domain should return direct
{ host: 'test.local', mode: direct},
{ host: '.local', mode: direct},
];

for (i = 0; i < testData.length; i += 1) {
Expand Down
3 changes: 2 additions & 1 deletion parent_proxy.go
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
"hash/crc32"
"io"
"math/rand"
"net"
Expand Down Expand Up @@ -109,7 +110,7 @@ type hashParentPool struct {
}

func (pp *hashParentPool) connect(url *URL) (srvconn net.Conn, err error) {
start := int(stringHash(url.Host) % uint64(len(pp.parent)))
start := int(crc32.ChecksumIEEE([]byte(url.Host)) % uint32(len(pp.parent)))
debug.Printf("hash host %s try %d parent first", url.Host, start)
return connectInOrder(url, pp.parent, start)
}
Expand Down
2 changes: 1 addition & 1 deletion script/build.sh
Expand Up @@ -48,7 +48,7 @@ build() {
}

build darwin amd64 mac64
build darwin 386 mac32
#build darwin 386 mac32
build linux amd64 linux64
build linux 386 linux32
build linux arm linux-armv5tel
Expand Down
16 changes: 13 additions & 3 deletions sitestat.go
Expand Up @@ -4,13 +4,14 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/cyfdecyf/bufio"
"io/ioutil"
"math/rand"
"os"
"strings"
"sync"
"time"

"github.com/cyfdecyf/bufio"
)

func init() {
Expand Down Expand Up @@ -426,9 +427,18 @@ func (ss *SiteStat) GetDirectList() []string {
var siteStat = newSiteStat()

func initSiteStat() {
if err := siteStat.load(configPath.stat); err != nil {
os.Exit(1)
err := siteStat.load(configPath.stat)
if err != nil {
errl.Printf("loading stat file failed, reason : %s", err.Error())
// Simply try to load the stat.back
err = siteStat.load(configPath.stat + ".bak")
// After all its not critical , simply re-create a stat object if anything is not ok
if err != nil {
errl.Printf("loading stat backup failed, creating new one , reason: %s", err.Error())
siteStat = newSiteStat()
}
}

// Dump site stat while running, so we don't always need to close cow to
// get updated stat.
go func() {
Expand Down
9 changes: 0 additions & 9 deletions util.go
Expand Up @@ -453,15 +453,6 @@ func host2Domain(host string) (domain string) {
return host[dot2ndLast+1:]
}

// djb2 string hash function, from http://www.cse.yorku.ca/~oz/hash.html
func stringHash(s string) (hash uint64) {
hash = 5381
for i := 0; i < len(s); i++ {
hash = ((hash << 5) + 1) + uint64(s[i])
}
return
}

// IgnoreUTF8BOM consumes UTF-8 encoded BOM character if present in the file.
func IgnoreUTF8BOM(f *os.File) error {
bom := make([]byte, 3)
Expand Down

0 comments on commit 0dab521

Please sign in to comment.