Skip to content

Commit

Permalink
Merge branch 'develop', version 0.9.6
Browse files Browse the repository at this point in the history
  • Loading branch information
cyfdecyf committed Jun 7, 2015
2 parents 05a3701 + fde02a8 commit 7f8245a
Show file tree
Hide file tree
Showing 22 changed files with 302 additions and 296 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG
@@ -1,3 +1,10 @@
0.9.6 (2015-06-07)
* Reload config by sending SIGUSR1 on Unix system
* Load blocked/direct/stat file from same directory as rc file by default
* Allow user to specify blocked/direct/stat file path
* Detect arm without vfp in install script.
* Fix estimate timeout bug

0.9.5 (2015-05-12)
* Support new encryption method "chacha20" and "salsa20"
* Avoid biased parent proxy selection for hash load balacing
Expand Down
8 changes: 4 additions & 4 deletions README-en.md
Expand Up @@ -2,7 +2,7 @@

COW is a HTTP proxy to simplify bypassing the great firewall. It tries to automatically identify blocked websites and only use parent proxy for those sites.

Current version: 0.9.5 [CHANGELOG](CHANGELOG)
Current version: 0.9.6 [CHANGELOG](CHANGELOG)
[![Build Status](https://travis-ci.org/cyfdecyf/cow.png?branch=master)](https://travis-ci.org/cyfdecyf/cow)

## Features
Expand Down Expand Up @@ -51,8 +51,8 @@ Command line options can override options in the configuration file For more det

In ideal situation, you don't need to specify which sites are blocked and which are not, but COW hasen't reached that goal. So you may need to manually specify this if COW made the wrong judgement.

- `~/.cow/blocked` for blocked sites
- `~/.cow/direct` for directly accessible sites
- `<dir containing rc file>/blocked` for blocked sites
- `<dir containing rc file>/direct` for directly accessible sites
- One line for each domain
- `google.com` means `*.google.com`
- You can use domains like `google.com.hk`
Expand All @@ -61,7 +61,7 @@ In ideal situation, you don't need to specify which sites are blocked and which

## Visited site recording

COW records all visited hosts and visit count in `~/.cow/stat`, which is a json file.
COW records all visited hosts and visit count in `stat` (which is a json file) under the same directory with config file.

- **For unknown site, first try direct access, use parent proxy upon failure. After 2 minutes, try direct access again**
- Builtin [common blocked site](site_blocked.go) in order to reduce time to discover blockage and the use parent proxy
Expand Down
9 changes: 5 additions & 4 deletions README.md
Expand Up @@ -4,7 +4,7 @@ COW 是一个简化穿墙的 HTTP 代理服务器。它能自动检测被墙网

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

当前版本:0.9.5 [CHANGELOG](CHANGELOG)
当前版本:0.9.6 [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 @@ -80,7 +80,8 @@ PAC url 为 `http://<listen address>/pac`,也可将浏览器的 HTTP/HTTPS 代

**一般情况下无需手工指定被墙和直连网站,该功能只是是为了处理特殊情况和性能优化。**

`~/.cow/blocked``~/.cow/direct` 可指定被墙和直连网站(`direct` 中的 host 会添加到 PAC):
配置文件所在目录下的 `blocked``direct` 可指定被墙和直连网站(`direct` 中的 host 会添加到 PAC)。
Windows 下文件名为 `blocked.txt``direct.txt`

- 每行一个域名或者主机名(COW 会先检查主机名是否在列表中,再检查域名)
- 二级域名如 `google.com` 相当于 `*.google.com`
Expand All @@ -91,7 +92,7 @@ PAC url 为 `http://<listen address>/pac`,也可将浏览器的 HTTP/HTTPS 代

## 访问网站记录

COW `~/.cow/stat` json 文件中记录经常访问网站被墙和直连访问的次数。
COW 在配置文件所在目录下的 `stat` json 文件中记录经常访问网站被墙和直连访问的次数。

- **对未知网站,先尝试直接连接,失败后使用二级代理重试请求,2 分钟后再尝试直接**
- 内置[常见被墙网站](site_blocked.go),减少检测被墙所需时间(可手工添加)
Expand Down Expand Up @@ -125,10 +126,10 @@ COW 默认配置下检测到被墙后,过两分钟再次尝试直连也是为

贡献代码:

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

Bug reporter:

Expand Down
99 changes: 49 additions & 50 deletions config.go
Expand Up @@ -16,7 +16,7 @@ import (
)

const (
version = "0.9.5"
version = "0.9.6"
defaultListenAddr = "127.0.0.1:7777"
defaultEstimateTarget = "example.com"
)
Expand All @@ -40,10 +40,10 @@ var defaultTunnelAllowedPort = []string{
}

type Config struct {
RcFile string // config file
LogFile string
AlwaysProxy bool
LoadBalance LoadBalanceMode
RcFile string // config file
LogFile string // path for log file
AlwaysProxy bool // whether we should alwyas use parent proxy
LoadBalance LoadBalanceMode // select load balance mode

TunnelAllowedPort map[string]bool // allowed ports to create tunnel

Expand All @@ -64,6 +64,11 @@ type Config struct {

HttpErrorCode int

dir string // directory containing config file
StatFile string // Path for stat file
BlockedFile string // blocked sites specified by user
DirectFile string // direct sites specified by user

// not configurable in config file
PrintVer bool
EstimateTimeout bool // Whether to run estimateTimeout().
Expand All @@ -76,24 +81,15 @@ type Config struct {
var config Config
var configNeedUpgrade bool // whether should upgrade config file

var configPath struct {
dir string // directory containing config file and blocked site list
alwaysBlocked string // blocked sites specified by user
alwaysDirect string // direct sites specified by user
stat string // site visit statistics
}

func printVersion() {
fmt.Println("cow version", version)
}

func init() {
initConfigDir()
// fmt.Println("home dir:", homeDir)

configPath.alwaysBlocked = path.Join(configPath.dir, alwaysBlockedFname)
configPath.alwaysDirect = path.Join(configPath.dir, alwaysDirectFname)
configPath.stat = path.Join(configPath.dir, statFname)
func initConfig(rcFile string) {
config.dir = path.Dir(rcFile)
config.BlockedFile = path.Join(config.dir, blockedFname)
config.DirectFile = path.Join(config.dir, directFname)
config.StatFile = path.Join(config.dir, statFname)

config.DetectSSLErr = false
config.AlwaysProxy = false
Expand All @@ -117,7 +113,7 @@ func parseCmdLineConfig() *Config {
var c Config
var listenAddr string

flag.StringVar(&c.RcFile, "rc", path.Join(configPath.dir, rcFname), "configuration file")
flag.StringVar(&c.RcFile, "rc", "", "config file, defaults to $HOME/.cow/rc on Unix, ./rc.txt on Windows")
// Specifying listen default value to StringVar would override config file options
flag.StringVar(&listenAddr, "listen", "", "listen address, disables listen in config")
flag.IntVar(&c.Core, "core", 2, "number of cores to use")
Expand All @@ -126,6 +122,17 @@ func parseCmdLineConfig() *Config {
flag.BoolVar(&c.EstimateTimeout, "estimate", true, "enable/disable estimate timeout")

flag.Parse()

if c.RcFile == "" {
c.RcFile = getDefaultRcFile()
} else {
c.RcFile = expandTilde(c.RcFile)
}
if err := isFileExists(c.RcFile); err != nil {
Fatal("fail to get config file:", err)
}
initConfig(c.RcFile)

if listenAddr != "" {
configParser{}.ParseListen(listenAddr)
cmdHasListenAddr = true // must come after parse
Expand Down Expand Up @@ -346,7 +353,7 @@ func (p configParser) ParseListen(val string) {
}

func (p configParser) ParseLogFile(val string) {
config.LogFile = val
config.LogFile = expandTilde(val)
}

func (p configParser) ParseAddrInPAC(val string) {
Expand Down Expand Up @@ -450,6 +457,24 @@ func (p configParser) ParseLoadBalance(val string) {
}
}

func (p configParser) ParseStatFile(val string) {
config.StatFile = expandTilde(val)
}

func (p configParser) ParseBlockedFile(val string) {
config.BlockedFile = expandTilde(val)
if err := isFileExists(config.BlockedFile); err != nil {
Fatal("blocked file:", err)
}
}

func (p configParser) ParseDirectFile(val string) {
config.DirectFile = expandTilde(val)
if err := isFileExists(config.DirectFile); err != nil {
Fatal("direct file:", err)
}
}

var shadow struct {
parent *shadowsocksParent
passwd string
Expand Down Expand Up @@ -527,12 +552,9 @@ func (p configParser) ParseUserPasswd(val string) {
}

func (p configParser) ParseUserPasswdFile(val string) {
exist, err := isFileExists(val)
err := isFileExists(val)
if err != nil {
Fatal("userPasswdFile error:", err)
}
if !exist {
Fatal("userPasswdFile", val, "does not exist")
Fatal("userPasswdFile:", err)
}
config.UserPasswdFile = val
}
Expand Down Expand Up @@ -575,12 +597,7 @@ func parseConfig(rc string, override *Config) {
// fmt.Println("rcFile:", path)
f, err := os.Open(expandTilde(rc))
if err != nil {
if os.IsNotExist(err) {
fmt.Printf("Config file %s not found, using default options\n", rc)
} else {
fmt.Println("Error opening config file:", err)
}
return
Fatal("Error opening config file:", err)
}

IgnoreUTF8BOM(f)
Expand Down Expand Up @@ -730,21 +747,3 @@ func checkConfig() {
listenProxy = []Proxy{newHttpProxy(defaultListenAddr, "")}
}
}

func mkConfigDir() (err error) {
if configPath.dir == "" {
return os.ErrNotExist
}
exists, err := isDirExists(configPath.dir)
if err != nil {
errl.Printf("Error checking config directory: %v\n", err)
return
}
if exists {
return
}
if err = os.Mkdir(configPath.dir, 0755); err != nil {
errl.Printf("Error create config directory %s: %v\n", configPath.dir, err)
}
return
}
1 change: 1 addition & 0 deletions config_test.go
Expand Up @@ -24,6 +24,7 @@ func TestParseListen(t *testing.T) {
}

func TestTunnelAllowedPort(t *testing.T) {
initConfig("")
parser := configParser{}
parser.ParseTunnelAllowedPort("1, 2, 3, 4, 5")
parser.ParseTunnelAllowedPort("6")
Expand Down
13 changes: 6 additions & 7 deletions config_unix.go
Expand Up @@ -7,15 +7,14 @@ import (
)

const (
rcFname = "rc"
alwaysBlockedFname = "blocked"
alwaysDirectFname = "direct"
statFname = "stat"
rcFname = "rc"
blockedFname = "blocked"
directFname = "direct"
statFname = "stat"

newLine = "\n"
)

func initConfigDir() {
home := getUserHomeDir()
configPath.dir = path.Join(home, ".cow")
func getDefaultRcFile() string {
return path.Join(path.Join(getUserHomeDir(), ".cow", rcFname))
}
12 changes: 6 additions & 6 deletions config_windows.go
Expand Up @@ -6,16 +6,16 @@ import (
)

const (
rcFname = "rc.txt"
alwaysBlockedFname = "blocked.txt"
alwaysDirectFname = "direct.txt"
statFname = "stat.txt"
rcFname = "rc.txt"
blockedFname = "blocked.txt"
directFname = "direct.txt"
statFname = "stat.txt"

newLine = "\r\n"
)

func initConfigDir() {
func getDefaultRcFile() string {
// On windows, put the configuration file in the same directory of cow executable
// This is not a reliable way to detect binary directory, but it works for double click and run
configPath.dir = path.Dir(os.Args[0])
return path.Join(path.Dir(os.Args[0]), rcFname)
}
6 changes: 6 additions & 0 deletions doc/sample-config/rc
Expand Up @@ -148,3 +148,9 @@ listen = http://127.0.0.1:7777
# (Chrome 遇到 SSL 错误会直接关闭连接,而不是让用户选择是否继续)
# 可能将可直连网站误判为被墙网站,当 GFW 进行 SSL 中间人攻击时可以考虑使用
#detectSSLErr = false

# 修改 stat/blocked/direct 文件路径,如不指定,默认在配置文件所在目录下
# 执行 cow 的用户需要有对 stat 文件所在目录的写权限才能更新 stat 文件
#statFile = <dir to rc file>/stat
#blockedFile = <dir to rc file>/blocked
#directFile = <dir to rc file>/direct
8 changes: 8 additions & 0 deletions doc/sample-config/rc-en
Expand Up @@ -173,3 +173,11 @@ listen = http://127.0.0.1:7777
# This detection is no reliable, may mistaken normal sites as blocked.
# Only consider this option when GFW is making middle man attack.
#detectSSLErr = false

# Change the stat/blocked/direct file position, defaults to files under directory
# containing rc file.
# The cow user must write access to directory containing the stat file in order
# to update stat.
#statFile = <dir to rc file>/stat
#blockedFile = <dir to rc file>/blocked
#directFile = <dir to rc file>/direct

0 comments on commit 7f8245a

Please sign in to comment.