Signed-off-by: arraykeys@gmail.com <arraykeys@gmail.com>

This commit is contained in:
arraykeys@gmail.com
2018-01-26 11:03:34 +08:00
parent 2fc750532d
commit 5f0a341d22
7 changed files with 104 additions and 26 deletions

View File

@ -17,6 +17,7 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- SSH中转,HTTP(S),SOCKS5代理支持SSH中转,上级Linux服务器不需要任何服务端,本地一个proxy即可开心上网. - SSH中转,HTTP(S),SOCKS5代理支持SSH中转,上级Linux服务器不需要任何服务端,本地一个proxy即可开心上网.
- [KCP](https://github.com/xtaci/kcp-go)协议支持,HTTP(S),SOCKS5代理支持KCP协议传输数据,降低延迟,提升浏览体验. - [KCP](https://github.com/xtaci/kcp-go)协议支持,HTTP(S),SOCKS5代理支持KCP协议传输数据,降低延迟,提升浏览体验.
- 集成外部APIHTTP(S),SOCKS5代理认证功能可以与外部HTTP API集成可以方便的通过外部系统控制代理用户 - 集成外部APIHTTP(S),SOCKS5代理认证功能可以与外部HTTP API集成可以方便的通过外部系统控制代理用户
- 透明HTTP(S)代理,支持直接把域名解析到proxy监听的ip,然后proxy就会帮你代理访问需要访问的HTTP(S)网站.如果配合iptables,在网关直接把出去的80,443方向的流量转发到proxy,就能实现无感知的智能路由器代理.
### Why need these? ### Why need these?
- 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.   - 当由于某某原因,我们不能访问我们在其它地方的服务,我们可以通过多个相连的proxy节点建立起一个安全的隧道访问我们的服务.  
@ -69,7 +70,9 @@ Proxy是golang实现的高性能http,https,websocket,tcp,udp,socks5代理服务
- [1.7.1 用户名和密码的方式](#171-ssh用户名和密码的方式) - [1.7.1 用户名和密码的方式](#171-ssh用户名和密码的方式)
- [1.7.2 用户名和密钥的方式](#172-ssh用户名和密钥的方式) - [1.7.2 用户名和密钥的方式](#172-ssh用户名和密钥的方式)
- [1.8 KCP协议传输](#18kcp协议传输) - [1.8 KCP协议传输](#18kcp协议传输)
- [1.9 查看帮助](#19查看帮助) - [1.9 HTTP(S)透明代理(域名解析)](#19https透明代理域名解析)
- [1.10 HTTP(S)透明代理(iptables转发)](#110https透明代理iptables转发)
- [1.11 查看帮助](#111查看帮助)
- [2. TCP代理](#2tcp代理) - [2. TCP代理](#2tcp代理)
- [2.1 普通一级TCP代理](#21普通一级tcp代理) - [2.1 普通一级TCP代理](#21普通一级tcp代理)
- [2.2 普通二级TCP代理](#22普通二级tcp代理) - [2.2 普通二级TCP代理](#22普通二级tcp代理)
@ -122,7 +125,7 @@ curl -L https://raw.githubusercontent.com/snail007/goproxy/master/install_auto.s
下载地址:https://github.com/snail007/goproxy/releases 下载地址:https://github.com/snail007/goproxy/releases
```shell ```shell
cd /root/proxy/ cd /root/proxy/
wget https://github.com/snail007/goproxy/releases/download/v4.1/proxy-linux-amd64.tar.gz wget https://github.com/snail007/goproxy/releases/download/v4.2/proxy-linux-amd64.tar.gz
``` ```
#### **2.下载自动安装脚本** #### **2.下载自动安装脚本**
```shell ```shell
@ -266,6 +269,66 @@ KCP协议需要-B参数设置一个密码用于加密解密数据
`./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword` `./proxy http -t tcp -p ":8080" -T kcp -P "22.22.22.22:38080" -B mypassword`
那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输. 那么访问本地的8080端口就是访问VPS上面的代理端口38080,数据通过kcp协议传输.
#### **1.9 HTTP(S)透明代理(域名解析)**
proxy不仅支持在其他软件里面通过设置代理的方式,为其他软件提供代理服务,而且支持直接把请求的网站域名解析到proxy监听的ip上,然后proxy监听80和443端口,那么proxy就会自动为你代理访问需要访问的HTTP(S)网站.
使用方式:
在"最后一级proxy代理"的机器上,因为proxy要伪装成所有网站,网站默认的端口HTTP是80,HTTPS是443,让proxy监听80和443端口即可.参数-p多个地址用逗号分割.
`./proxy http -t tcp -p :80,:443`
这个命令就在机器上启动了一个proxy代理,同时监听80和443端口,既可以当作普通的代理使用,也可以直接把需要代理的域名解析到这个机器的IP上.
如果有上级代理那么参照上面教程设置上级即可,使用方式完全一样.
`./proxy http -t tcp -p :80,:443 -T tls -P "2.2.2.2:33080" -C proxy.crt -K proxy.key`
注意:
proxy所在的服务器的DNS解析结果不能受到自定义的解析影响,不然就死循环了.
#### **1.10 HTTP(S)透明代理(iptables转发)**
该模式需要具有一定的网络基础,相关概念不懂的请自行搜索解决.
假设proxy现在在路由器上运行,启动命令如下:
`./proxy http -t tcp -p :33080 -T tls -P "2.2.2.2:33090" -C proxy.crt -K proxy.key`
然后添加iptables规则,下面是参考规则:
```shell
#上级proxy服务端服务器IP地址:
proxy_server_ip=2.2.2.2
#路由器运行proxy监听的端口:
proxy_local_port=33080
#下面的就不用修改了
#create a new chain named PROXY
iptables -t nat -N PROXY
# Ignore your PROXY server's addresses
# It's very IMPORTANT, just be careful.
iptables -t nat -A PROXY -d $proxy_server_ip -j RETURN
# Ignore LANs IP address
iptables -t nat -A PROXY -d 0.0.0.0/8 -j RETURN
iptables -t nat -A PROXY -d 10.0.0.0/8 -j RETURN
iptables -t nat -A PROXY -d 127.0.0.0/8 -j RETURN
iptables -t nat -A PROXY -d 169.254.0.0/16 -j RETURN
iptables -t nat -A PROXY -d 172.16.0.0/12 -j RETURN
iptables -t nat -A PROXY -d 192.168.0.0/16 -j RETURN
iptables -t nat -A PROXY -d 224.0.0.0/4 -j RETURN
iptables -t nat -A PROXY -d 240.0.0.0/4 -j RETURN
# Anything to port 80 443 should be redirected to PROXY's local port
iptables -t nat -A PROXY -p tcp --dport 80 -j REDIRECT --to-ports $proxy_local_port
iptables -t nat -A PROXY -p tcp --dport 443 -j REDIRECT --to-ports $proxy_local_port
# Apply the rules to nat client
iptables -t nat -A PREROUTING -p tcp -j PROXY
# Apply the rules to localhost
iptables -t nat -A OUTPUT -p tcp -j PROXY
```
- 清空整个链 iptables -F 链名比如iptables -t nat -F SHADOWSOCKS
- 删除指定的用户自定义链 iptables -X 链名 比如 iptables -t nat -X SHADOWSOCKS
- 从所选链中删除规则 iptables -D 链名 规则详情 比如 iptables -t nat -D SHADOWSOCKS -d 223.223.192.0/255.255.240.0 -j RETURN
#### **1.9.查看帮助** #### **1.9.查看帮助**
`./proxy help http` `./proxy help http`

View File

@ -64,7 +64,7 @@ func initConfig() (err error) {
httpArgs.Auth = http.Flag("auth", "http basic auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings() httpArgs.Auth = http.Flag("auth", "http basic auth username and password, mutiple user repeat -a ,such as: -a user1:pass1 -a user2:pass2").Short('a').Strings()
httpArgs.PoolSize = http.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int() httpArgs.PoolSize = http.Flag("pool-size", "conn pool size , which connect to parent proxy, zero: means turn off pool").Short('L').Default("0").Int()
httpArgs.CheckParentInterval = http.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int() httpArgs.CheckParentInterval = http.Flag("check-parent-interval", "check if proxy is okay every interval seconds,zero: means no check").Short('I').Default("3").Int()
httpArgs.Local = http.Flag("local", "local ip:port to listen").Short('p').Default(":33080").String() httpArgs.Local = http.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()
httpArgs.SSHUser = http.Flag("ssh-user", "user for ssh").Short('u').Default("").String() httpArgs.SSHUser = http.Flag("ssh-user", "user for ssh").Short('u').Default("").String()
httpArgs.SSHKeyFile = http.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String() httpArgs.SSHKeyFile = http.Flag("ssh-key", "private key file for ssh").Short('S').Default("").String()
httpArgs.SSHKeyFileSalt = http.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String() httpArgs.SSHKeyFileSalt = http.Flag("ssh-keysalt", "salt of ssh private key").Short('s').Default("").String()

View File

@ -5,7 +5,7 @@ if [ -e /tmp/proxy ]; then
fi fi
mkdir /tmp/proxy mkdir /tmp/proxy
cd /tmp/proxy cd /tmp/proxy
wget https://github.com/snail007/goproxy/releases/download/v4.1/proxy-linux-amd64.tar.gz wget https://github.com/snail007/goproxy/releases/download/v4.2/proxy-linux-amd64.tar.gz
# #install proxy # #install proxy
tar zxvf proxy-linux-amd64.tar.gz tar zxvf proxy-linux-amd64.tar.gz

View File

@ -8,7 +8,7 @@ import (
"syscall" "syscall"
) )
const APP_VERSION = "4.1" const APP_VERSION = "4.2"
func main() { func main() {
err := initConfig() err := initConfig()

View File

@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
VER="4.1" VER="4.2"
RELEASE="release-${VER}" RELEASE="release-${VER}"
rm -rf .cert rm -rf .cert
mkdir .cert mkdir .cert

View File

@ -9,6 +9,7 @@ import (
"proxy/utils" "proxy/utils"
"runtime/debug" "runtime/debug"
"strconv" "strconv"
"strings"
"time" "time"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
@ -115,20 +116,24 @@ func (s *HTTP) Start(args interface{}) (err error) {
s.InitOutConnPool() s.InitOutConnPool()
} }
s.InitService() s.InitService()
host, port, _ := net.SplitHostPort(*s.cfg.Local) for _, addr := range strings.Split(*s.cfg.Local, ",") {
p, _ := strconv.Atoi(port) if addr != "" {
sc := utils.NewServerChannel(host, p) host, port, _ := net.SplitHostPort(addr)
if *s.cfg.LocalType == TYPE_TCP { p, _ := strconv.Atoi(port)
err = sc.ListenTCP(s.callback) sc := utils.NewServerChannel(host, p)
} else if *s.cfg.LocalType == TYPE_TLS { if *s.cfg.LocalType == TYPE_TCP {
err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback) err = sc.ListenTCP(s.callback)
} else if *s.cfg.LocalType == TYPE_KCP { } else if *s.cfg.LocalType == TYPE_TLS {
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback) err = sc.ListenTls(s.cfg.CertBytes, s.cfg.KeyBytes, s.callback)
} else if *s.cfg.LocalType == TYPE_KCP {
err = sc.ListenKCP(*s.cfg.KCPMethod, *s.cfg.KCPKey, s.callback)
}
if err != nil {
return
}
log.Printf("%s http(s) proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
}
} }
if err != nil {
return
}
log.Printf("%s http(s) proxy on %s", *s.cfg.LocalType, (*sc.Listener).Addr())
return return
} }

View File

@ -11,6 +11,7 @@ import (
"log" "log"
"net" "net"
"net/url" "net/url"
"proxy/utils/sni"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -306,13 +307,22 @@ func NewHTTPRequest(inConn *net.Conn, bufSize int, isBasicAuth bool, basicAuth *
return return
} }
req.HeadBuf = buf[:len] req.HeadBuf = buf[:len]
index := bytes.IndexByte(req.HeadBuf, '\n') //try sni
if index == -1 { serverName, err0 := sni.ServerNameFromBytes(req.HeadBuf)
err = fmt.Errorf("http decoder data line err:%s", SubStr(string(req.HeadBuf), 0, 50)) if err0 == nil {
CloseConn(inConn) //sni success
return req.Method = "SNI"
req.hostOrURL = "https://" + serverName + ":443"
} else {
//sni fail , try http
index := bytes.IndexByte(req.HeadBuf, '\n')
if index == -1 {
err = fmt.Errorf("http decoder data line err:%s", SubStr(string(req.HeadBuf), 0, 50))
CloseConn(inConn)
return
}
fmt.Sscanf(string(req.HeadBuf[:index]), "%s%s", &req.Method, &req.hostOrURL)
} }
fmt.Sscanf(string(req.HeadBuf[:index]), "%s%s", &req.Method, &req.hostOrURL)
if req.Method == "" || req.hostOrURL == "" { if req.Method == "" || req.hostOrURL == "" {
err = fmt.Errorf("http decoder data err:%s", SubStr(string(req.HeadBuf), 0, 50)) err = fmt.Errorf("http decoder data err:%s", SubStr(string(req.HeadBuf), 0, 50))
CloseConn(inConn) CloseConn(inConn)