Skip to content

Commit

Permalink
add docker support
Browse files Browse the repository at this point in the history
Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>
  • Loading branch information
snail007 committed May 15, 2018
1 parent bffd589 commit 53df3b5
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 44 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ v4.8
1.优化了SPS连接HTTP上级的指令,避免了某些代理不响应的问题.
2.SPS功能增加了参数:
--disable-http:禁用http(s)代理
--disable-socks:禁用socks代理.
--disable-socks:禁用socks代理
默认都是false(开启).
3.重构了部分代码的日志部分,保证了日志按着预期输出.

Expand Down
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ This page is the v4.7 manual, and the other version of the manual can be checked
### Installation
- [Quick installation](#quick-installation)
- [Manual installation](#manual-installation)
- [Docker installation](#docker-installation)

### First use must read
- [Environmental Science](#environmental-science)
Expand Down Expand Up @@ -169,6 +170,36 @@ wget https://raw.githubusercontent.com/snail007/goproxy/master/install.sh
chmod +x install.sh
./install.sh
```

#### Docker installation

Dockerfile root of project uses multistage build and alpine project to comply with best practices. Uses golang 1.8.5 for building as noted in the project README.md and will be pretty small image. total extracted size will be 17.3MB for goproxy version 4.7.

The default build process builds the master branch (latest commits/ cutting edge), and it can be configured to build specific version, just edit Dockerfile before build, following builds release version 4.7:

```
ARG GOPROXY_VERSION=v4.7
```

To Run:
1. Clone the repository and cd into it.
```
sudo docker build .
```
2. Tag the image:
```
sudo docker tag <id from previous step> goproxy/goproxy:latest
```
3. Run!
Just put your arguments to proxy binary in the OPTS environmental variable (this is just a sample http proxy):
```
sudo docker run -d --restart=always --name goproxy -e OPTS="http -p :33080" -p 33080:33080 goproxy/goproxy:latest
```
4. View logs:
```
sudo docker logs -f goproxy
```


## **First use must be read**  

Expand Down Expand Up @@ -967,7 +998,7 @@ If you want to get a more detailed configuration and explanation of the KCP para
- HTTP (s) proxy support PAC?
- Welcome joining group feedback...

### How to contribute to the code?
### How to contribute to the code (Pull Request)?
First, you need to clone the project to your account, and then modify the code on the dev branch.
Finally, Pull Request to dev branch of goproxy project, and contribute code for efficiency.
PR needs to explain what changes have been made and why you change them.
Expand Down
34 changes: 32 additions & 2 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
### 安装
1. [快速安装](#自动安装)
1. [手动安装](#手动安装)
1. [Docker安装](#docker安装)

### 首次使用必看
- [环境](#首次使用必看-1)
Expand Down Expand Up @@ -168,7 +169,36 @@ wget https://raw.githubusercontent.com/snail007/goproxy/master/install.sh
chmod +x install.sh
./install.sh
```


#### Docker安装
项目根目录的Dockerfile文件用来构建,使用golang 1.8.5,构建基于goproxy v4.7,
全部大小17.3MB,默认情况下使用master分支,不过可以通过修改配置文件Dockerfile,指定构建的goproxy版本.

```
ARG GOPROXY_VERSION=v4.7
```

步骤:
1. 克隆仓库,然后cd进入仓库文件夹,执行:
```
sudo docker build .
```
2. 镜像打标签:
```
sudo docker tag <上一步的结果ID> goproxy/goproxy:latest
```
3. 运行
参数OPTS的值就是传递给proxy的所有参数
比如下面的例子启动了一个http服务:

```
sudo docker run -d --restart=always --name goproxy -e OPTS="http -p :33080" -p 33080:33080 goproxy/goproxy:latest
```
4. 查看日志:
```
sudo docker logs -f goproxy
```

## **首次使用必看**

### **环境**
Expand Down Expand Up @@ -1012,7 +1042,7 @@ fast3:`--nodelay=1 --interval=10 --resend=2 --nc=1`
- http(s)代理增加pac支持?
- 欢迎加群反馈...

### 如何贡献代码?
### 如何贡献代码(Pull Request)?
首先需要clone本项目到自己的帐号下面,然后在dev分支上面修改代码,
最后发Pull Request到goproxy项目的dev分支即可,为了高效贡献代码,
pr的时候需要说明做了什么变更,原因是什么.
Expand Down
4 changes: 3 additions & 1 deletion config.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func initConfig() (err error) {
spsArgs.ParentType = sps.Flag("parent-type", "parent protocol type <tls|tcp|kcp>").Short('T').Enum("tls", "tcp", "kcp")
spsArgs.LocalType = sps.Flag("local-type", "local protocol type <tls|tcp|kcp>").Default("tcp").Short('t').Enum("tls", "tcp", "kcp")
spsArgs.Local = sps.Flag("local", "local ip:port to listen,multiple address use comma split,such as: 0.0.0.0:80,0.0.0.0:443").Short('p').Default(":33080").String()
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks>").Short('S').Enum("http", "socks")
spsArgs.ParentServiceType = sps.Flag("parent-service-type", "parent service type <http|socks|ss>").Short('S').Enum("http", "socks", "ss")
spsArgs.DNSAddress = sps.Flag("dns-address", "if set this, proxy will use this dns for resolve doamin").Short('q').Default("").String()
spsArgs.DNSTTL = sps.Flag("dns-ttl", "caching seconds of dns query result").Short('e').Default("300").Int()
spsArgs.AuthFile = sps.Flag("auth-file", "http basic auth file,\"username:password\" each line in file").Short('F').String()
Expand All @@ -244,6 +244,8 @@ func initConfig() (err error) {
spsArgs.ParentCompress = sps.Flag("parent-compress", "auto compress/decompress data on parent connection").Short('M').Default("false").Bool()
spsArgs.SSMethod = sps.Flag("ss-method", "").Hidden().Short('h').Default("aes-256-cfb").String()
spsArgs.SSKey = sps.Flag("ss-key", "").Hidden().Short('j').Default("sspassword").String()
spsArgs.ParentSSMethod = sps.Flag("parent-ss-method", "").Hidden().Short('H').Default("aes-256-cfb").String()
spsArgs.ParentSSKey = sps.Flag("parent-ss-key", "").Hidden().Short('J').Default("sspassword").String()
spsArgs.DisableHTTP = sps.Flag("disable-http", "disable http(s) proxy").Default("false").Bool()
spsArgs.DisableSocks5 = sps.Flag("disable-socks", "disable socks proxy").Default("false").Bool()
spsArgs.DisableSS = sps.Flag("disable-ss", "").Hidden().Default("false").Bool()
Expand Down
2 changes: 2 additions & 0 deletions services/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ type SPSArgs struct {
ParentCompress *bool
SSMethod *string
SSKey *string
ParentSSMethod *string
ParentSSKey *string
DisableHTTP *bool
DisableSocks5 *bool
DisableSS *bool
Expand Down
7 changes: 6 additions & 1 deletion services/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,12 @@ func (s *HTTP) OutToTCP(useProxy bool, address string, inConn *net.Conn, req *ut
} else {
//https或者http,上级是代理,proxy需要转发
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = outConn.Write(req.HeadBuf)
//直连目标或上级非代理,清理HTTP头部的代理头信息
if !useProxy || *s.cfg.ParentType == "ssh" {
_, err = outConn.Write(utils.RemoveProxyHeaders(req.HeadBuf))
} else {
_, err = outConn.Write(req.HeadBuf)
}
outConn.SetDeadline(time.Time{})
if err != nil {
s.log.Printf("write to %s , err:%s", *s.cfg.Parent, err)
Expand Down
80 changes: 50 additions & 30 deletions services/sps.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ type SPS struct {
serverChannels []*utils.ServerChannel
userConns utils.ConcurrentMap
log *logger.Logger
cipher *ss.Cipher
localCipher *ss.Cipher
parentCipher *ss.Cipher
}

func NewSPS() Service {
Expand All @@ -48,6 +49,10 @@ func (s *SPS) CheckArgs() (err error) {
err = fmt.Errorf("parent type unkown,use -T <tls|tcp|kcp>")
return
}
if *s.cfg.ParentType == "ss" && (*s.cfg.ParentSSKey == "" || *s.cfg.ParentSSMethod == "") {
err = fmt.Errorf("ss parent need a ss key, set it by : -J <sskey>")
return
}
if *s.cfg.ParentType == TYPE_TLS || *s.cfg.LocalType == TYPE_TLS {
s.cfg.CertBytes, s.cfg.KeyBytes, err = utils.TlsBytes(*s.cfg.CertFile, *s.cfg.KeyFile)
if err != nil {
Expand All @@ -70,7 +75,14 @@ func (s *SPS) InitService() (err error) {
}
err = s.InitBasicAuth()
if *s.cfg.SSMethod != "" && *s.cfg.SSKey != "" {
s.cipher, err = ss.NewCipher(*s.cfg.SSMethod, *s.cfg.SSKey)
s.localCipher, err = ss.NewCipher(*s.cfg.SSMethod, *s.cfg.SSKey)
if err != nil {
s.log.Printf("error generating cipher : %s", err)
return
}
}
if *s.cfg.ParentServiceType == "ss" {
s.parentCipher, err = ss.NewCipher(*s.cfg.ParentSSMethod, *s.cfg.ParentSSKey)
if err != nil {
s.log.Printf("error generating cipher : %s", err)
return
Expand Down Expand Up @@ -111,10 +123,10 @@ func (s *SPS) StopService() {
}
}
for _, c := range s.userConns.Items() {
if _,ok:=c.(*net.Conn);ok{
if _, ok := c.(*net.Conn); ok {
(*c.(*net.Conn)).Close()
}
if _,ok:=c.(**net.Conn);ok{
if _, ok := c.(**net.Conn); ok {
(*(*c.(**net.Conn))).Close()
}
}
Expand Down Expand Up @@ -252,7 +264,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
//s.log.Printf("https reply: %s", request.Host)
} else {
//forwardBytes = bytes.TrimRight(request.HeadBuf,"\r\n")
forwardBytes = bytes.TrimRight(request.HeadBuf,"\r\n")
forwardBytes = request.HeadBuf
}
address = request.Host
var userpass string
Expand All @@ -273,7 +285,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
return
}
(*inConn).SetDeadline(time.Now().Add(time.Second * 5))
ssConn := ss.NewConn(*inConn, s.cipher.Copy())
ssConn := ss.NewConn(*inConn, s.localCipher.Copy())
address, err = ss.GetRequest(ssConn)
(*inConn).SetDeadline(time.Time{})
if err != nil {
Expand Down Expand Up @@ -309,20 +321,23 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
Password: *s.cfg.ParentKey,
})
}

if *s.cfg.ParentAuth != "" || *s.cfg.ParentSSKey != "" || s.IsBasicAuth() {
forwardBytes = utils.RemoveProxyHeaders(forwardBytes)
}

//ask parent for connect to target address
if *s.cfg.ParentServiceType == "http" {
//http parent
isHTTPS:=false
isHTTPS := false

pb := new(bytes.Buffer)
if len(forwardBytes) == 0 {
isHTTPS=true
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1", address)))
isHTTPS = true
pb.Write([]byte(fmt.Sprintf("CONNECT %s HTTP/1.1\r\n", address)))
}
pb.WriteString("\r\nProxy-Connection: Keep-Alive\r\n")
pb.WriteString("Proxy-Connection: Keep-Alive\r\n")

s.log.Printf("before bytes:%s",string(forwardBytes))

//Proxy-Authorization:\r\n
u := ""
if *s.cfg.ParentAuth != "" {
a := strings.Split(*s.cfg.ParentAuth, ":")
Expand All @@ -337,24 +352,18 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
}
}
if u != "" {
pb.Write([]byte(fmt.Sprintf("Proxy-Authorization:Basic %s\r\n", base64.StdEncoding.EncodeToString([]byte(u)))))
pb.Write([]byte(fmt.Sprintf("Proxy-Authorization: Basic %s\r\n", base64.StdEncoding.EncodeToString([]byte(u)))))
}

if isHTTPS{
if isHTTPS {
pb.Write([]byte("\r\n"))
}else{
//do remove some headers with forwardBytes
//forwardBytes

forwardBytes=bytes.Replace(forwardBytes,[]byte("\r\n"),[]byte(pb.Bytes()),1)
} else {
forwardBytes = utils.InsertProxyHeaders(forwardBytes, string(pb.Bytes()))
pb.Reset()
pb.Write(forwardBytes)
if !bytes.Contains(forwardBytes,[]byte("\r\n\r\n\r\n")){
pb.Write([]byte("\r\n\r\n"))
}
forwardBytes=nil
forwardBytes = nil
}

outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = outConn.Write(pb.Bytes())
outConn.SetDeadline(time.Time{})
Expand All @@ -365,10 +374,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
return
}

s.log.Printf("ishttps:%v",isHTTPS)
s.log.Printf("bytes:%s",string(pb.Bytes()))

if isHTTPS{
if isHTTPS {
reply := make([]byte, 1024)
outConn.SetDeadline(time.Now().Add(time.Millisecond * time.Duration(*s.cfg.Timeout)))
_, err = outConn.Read(reply)
Expand All @@ -381,7 +387,7 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
}
//s.log.Printf("reply: %s", string(reply[:n]))
}
} else {
} else if *s.cfg.ParentServiceType == "socks" {
s.log.Printf("connect %s", address)
//socks client
var clientConn *socks.ClientConn
Expand All @@ -402,11 +408,25 @@ func (s *SPS) OutToTCP(inConn *net.Conn) (err error) {
if err = clientConn.Handshake(); err != nil {
return
}
} else if *s.cfg.ParentServiceType == "ss" {
ra, e := ss.RawAddr(address)
if e != nil {
err = fmt.Errorf("build ss raw addr fail, err: %s", e)
return
}

outConn, err = ss.DialWithRawAddr(&outConn, ra, "", s.parentCipher.Copy())
if err != nil {
err = fmt.Errorf("dial ss parent fail, err : %s", err)
return
}
}

//forward client data to target,if necessary.
if len(forwardBytes) > 0 {
outConn.Write(forwardBytes)
}

//bind
inAddr := (*inConn).RemoteAddr().String()
outAddr := outConn.RemoteAddr().String()
Expand Down
27 changes: 27 additions & 0 deletions utils/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,33 @@ func IsSocks5(head []byte) bool {
}
return false
}
func RemoveProxyHeaders(head []byte) []byte {
newLines := [][]byte{}
var keys = map[string]bool{}
lines := bytes.Split(head, []byte("\r\n"))
IsBody := false
for _, line := range lines {
if len(line) == 0 || IsBody {
newLines = append(newLines, line)
IsBody = true
} else {
hline := bytes.SplitN(line, []byte(":"), 2)
if len(hline) != 2 {
continue
}
k := strings.ToUpper(string(hline[0]))
if _, ok := keys[k]; ok || strings.HasPrefix(k, "PROXY-") {
continue
}
keys[k] = true
newLines = append(newLines, line)
}
}
return bytes.Join(newLines, []byte("\r\n"))
}
func InsertProxyHeaders(head []byte, headers string) []byte {
return bytes.Replace(head, []byte("\r\n"), []byte("\r\n"+headers), 1)
}

// type sockaddr struct {
// family uint16
Expand Down
Loading

0 comments on commit 53df3b5

Please sign in to comment.