mirror of
https://github.com/ehang-io/nps.git
synced 2025-07-03 13:10:42 +00:00
客户端服务端分离
This commit is contained in:
parent
dcd21f211d
commit
1f61b99387
144
README.md
144
README.md
@ -11,19 +11,17 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
|
|||||||

|

|
||||||
1. web管理模式,可配置多条tcp、udp隧道,多个域名代理等等----> [web管理模式](#web管理模式)
|
1. web管理模式,可配置多条tcp、udp隧道,多个域名代理等等----> [web管理模式](#web管理模式)
|
||||||
|
|
||||||
2. 内网多站点配合代理。----> [http反向代理请求](#http代理请求)
|
|
||||||
|
|
||||||
3. 想在外网通过ssh连接内网的机器,做云服务器到内网服务器端口的映射,或者做微信公众号开发、小程序开发等---->[tcp隧道模式](#tcp隧道模式)
|
2. 想在外网通过ssh连接内网的机器,做云服务器到内网服务器端口的映射,或者做微信公众号开发、小程序开发等---->[tcp隧道模式](#tcp隧道模式)
|
||||||
|
|
||||||
4. 在非内网环境下使用内网dns,或者需要通过udp访问内网机器等---->[udp隧道模式](#udp隧道模式)
|
3. 在非内网环境下使用内网dns,或者需要通过udp访问内网机器等---->[udp隧道模式](#udp隧道模式)
|
||||||
|
|
||||||
5. 在外网使用HTTP代理访问内网站点---->[http代理模式](#http代理模式)
|
4. 在外网使用HTTP代理访问内网站点---->[http代理模式](#http代理模式)
|
||||||
|
|
||||||
6. 搭建一个内网穿透ss,在外网如同使用内网vpn一样访问内网资源或者设备----> [socks5代理模式](#socks5代理模式)
|
5. 搭建一个内网穿透ss,在外网如同使用内网vpn一样访问内网资源或者设备----> [socks5代理模式](#socks5代理模式)
|
||||||
|
|
||||||
## 特点
|
## 特点
|
||||||
- [x] 支持snappy压缩,减小传输过程流量消耗
|
- [x] 支持snappy压缩,减小传输过程流量消耗
|
||||||
- [x] 支持多站点配置,兼容多个内网网站,可处理相互之间的跳转包含关系
|
|
||||||
- [x] 断线自动重连
|
- [x] 断线自动重连
|
||||||
- [x] 支持多路传输,提高并发
|
- [x] 支持多路传输,提高并发
|
||||||
- [x] 跨站自动匹配替换
|
- [x] 跨站自动匹配替换
|
||||||
@ -44,13 +42,12 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
|
|||||||
2. [web管理模式](#web管理模式)(多隧道时推荐)
|
2. [web管理模式](#web管理模式)(多隧道时推荐)
|
||||||
3. [tcp隧道模式](#tcp隧道模式)
|
3. [tcp隧道模式](#tcp隧道模式)
|
||||||
4. [udp隧道模式](#udp隧道模式)
|
4. [udp隧道模式](#udp隧道模式)
|
||||||
5. [http反向代理请求](#http代理请求)
|
5. [socks5代理模式](#socks5代理模式)
|
||||||
6. [socks5代理模式](#socks5代理模式)
|
6. [http代理模式](#http代理模式)
|
||||||
7. [http代理模式](#http代理模式)
|
7. [数据压缩支持](#数据压缩支持)
|
||||||
8. [数据压缩支持](#数据压缩支持)
|
8. [站点密码保护](#站点保护)
|
||||||
9. [站点密码保护](#站点保护)
|
9. [加密传输](#加密传输)
|
||||||
10. [加密传输](#加密传输)
|
10. [TCP多路复用](#多路复用)
|
||||||
11. [TCP多路复用](#多路复用)
|
|
||||||
11. [配置文件说明](#配置文件)
|
11. [配置文件说明](#配置文件)
|
||||||
|
|
||||||
## 安装
|
## 安装
|
||||||
@ -58,13 +55,14 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
|
|||||||
1. release安装
|
1. release安装
|
||||||
> https://github.com/cnlh/easyProxy/releases
|
> https://github.com/cnlh/easyProxy/releases
|
||||||
|
|
||||||
下载对应的系统版本即可,服务端和客户端共用一个程序,go语言开发,无需任何第三方依赖
|
下载对应的系统版本即可,服务端和客户端是单独的,go语言开发,无需任何第三方依赖
|
||||||
|
|
||||||
2. 源码安装
|
2. 源码安装
|
||||||
- 安装源码
|
- 安装源码
|
||||||
> go get github.com/cnlh/easyProxy
|
> go get github.com/cnlh/easyProxy
|
||||||
- 编译
|
- 编译
|
||||||
> go build
|
> go build cmd/proxy_server.go
|
||||||
|
> go build cmd/proxy_client.go
|
||||||
|
|
||||||
## web管理模式
|
## web管理模式
|
||||||
|
|
||||||
@ -72,6 +70,9 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
|
|||||||
### 介绍
|
### 介绍
|
||||||
|
|
||||||
可在网页上配置和管理各个tcp、udp隧道、内网站点代理等等,功能极为强大,操作也非常方便。
|
可在网页上配置和管理各个tcp、udp隧道、内网站点代理等等,功能极为强大,操作也非常方便。
|
||||||
|
|
||||||
|
**提示:使用web模式时,服务端执行文件必须在项目根目录,否则无法正确加载配置文件**
|
||||||
|
|
||||||
### 使用
|
### 使用
|
||||||
|
|
||||||
**有两种模式:**
|
**有两种模式:**
|
||||||
@ -218,116 +219,7 @@ target | 目标地址,格式如上
|
|||||||
./easyProxy -server=ip:port -vkey=DKibZF5TXvic1g3kY
|
./easyProxy -server=ip:port -vkey=DKibZF5TXvic1g3kY
|
||||||
```
|
```
|
||||||
|
|
||||||
## http代理请求
|
|
||||||
|
|
||||||
### 场景及原理
|
|
||||||
|
|
||||||
较为适用于http,也就是web站点的穿透,服务端与客户端之间建立连接,服务端收到http请求后,将请求发送到客户端,客户端再执行这个请求,并将结果返回给服务端,服务端收到后再返回。
|
|
||||||
|
|
||||||
<html>
|
|
||||||
<span style="color:red">特点:支持同时代理多个站点,不同站点之间有联系还可以实现匹配替换</span>
|
|
||||||
</html>
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
**最终效果**:
|
|
||||||
- 访问a.server.com和访问10.1.50.203的80端口相同
|
|
||||||
- 访问b.server.com和访问10.1.50.202的80端口相同
|
|
||||||
- 访问c.server.com和访问10.1.50.201的80端口相同
|
|
||||||
### 使用
|
|
||||||
- 服务端
|
|
||||||
|
|
||||||
```
|
|
||||||
./easyProxy -mode=httpServer -vkey=DKibZF5TXvic1g3kY -tcpport=8284 -httpport=8024
|
|
||||||
```
|
|
||||||
|
|
||||||
名称 | 含义
|
|
||||||
---|---
|
|
||||||
mode | 运行模式
|
|
||||||
vkey | 验证密钥
|
|
||||||
tcpport | 服务端与客户端通信端口
|
|
||||||
httpport | 代理的http端口(与nginx配合使用)
|
|
||||||
|
|
||||||
- 客户端
|
|
||||||
|
|
||||||
```
|
|
||||||
建立配置文件 config.json
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
./easyProxy -server=ip:port -config=config.json -vkey=DKibZF5TXvic1g3kY
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
名称 | 含义
|
|
||||||
---|---
|
|
||||||
config | 配置文件路径
|
|
||||||
### 配置文件config.json
|
|
||||||
|
|
||||||
```
|
|
||||||
{
|
|
||||||
"SiteList": [
|
|
||||||
{
|
|
||||||
"host": "a.ourcauc.com",
|
|
||||||
"url": "10.1.50.203",
|
|
||||||
"port": 80
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"host": "b.ourcauc.com",
|
|
||||||
"url": "10.1.50.202",
|
|
||||||
"port": 80
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"host": "c.ourcauc.com",
|
|
||||||
"url": "10.1.50.203",
|
|
||||||
"port": 80
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Replace": 0
|
|
||||||
}
|
|
||||||
```
|
|
||||||
名称 | 含义
|
|
||||||
---|---
|
|
||||||
SiteList | 本地解析的域名列表
|
|
||||||
host | 域名地址
|
|
||||||
url | 内网代理的地址
|
|
||||||
port | 内网代理的地址对应的端口
|
|
||||||
Replace | 是否自动匹配替换[(查看场景)](https://github.com/cnlh/easyProxy/issues/1)
|
|
||||||
|
|
||||||
|
|
||||||
### nginx代理配置示例
|
|
||||||
```
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
server_name a.ourcauc.com b.ourcauc.com c.ourcauc.com ;
|
|
||||||
location / {
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header X-Nginx-Proxy true;
|
|
||||||
proxy_set_header Connection "";
|
|
||||||
proxy_pass http://127.0.0.1:8024;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
## 域名配置示例
|
|
||||||
> -a A 123.206.77.88
|
|
||||||
|
|
||||||
> -b A 123.206.77.88
|
|
||||||
|
|
||||||
> -c A 123.206.77.88
|
|
||||||
|
|
||||||
### 跨站自动匹配替换说明
|
|
||||||
|
|
||||||
例如,访问:a.ourcauc.com,该页面里面有一个超链接为10.1.50.202:80,将根据配置文件自动该将url替换为b.ourcauc.com,以达到跨站也可访问的效果,但需要提前在配置文件中配置这些站点。
|
|
||||||
|
|
||||||
如需开启,请加配置文件Replace值设置为1
|
|
||||||
>注意:开启可能导致不应该被替换的内容被替换,请谨慎开启
|
|
||||||
|
|
||||||
### 二级域名示范
|
|
||||||
|
|
||||||
[二级域名](https://github.com/cnlh/easyProxy/wiki/%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B)
|
|
||||||
|
|
||||||
|
|
||||||
## socks5代理模式
|
## socks5代理模式
|
||||||
@ -422,9 +314,9 @@ httpport | http代理连接端口
|
|||||||
- 所有模式均支持数据压缩,可以与加密同时使用
|
- 所有模式均支持数据压缩,可以与加密同时使用
|
||||||
|
|
||||||
|
|
||||||
- 在server端加上参数 -compress=snappy(或在web中设置),例如在TCP隧道模式
|
- 在server端加上参数 -compress=snappy(或在web管理中设置)
|
||||||
```
|
```
|
||||||
./easyProxy -mode=tunnelServer -vkey=DKibZF5TXvic1g3kY -tcpport=8284 -httpport=8024 -target=10.1.50.203:80 -compress=snappy
|
-compress=snappy
|
||||||
```
|
```
|
||||||
|
|
||||||
## 加密传输
|
## 加密传输
|
||||||
|
241
bridge/bridge.go
Executable file
241
bridge/bridge.go
Executable file
@ -0,0 +1,241 @@
|
|||||||
|
package bridge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/cnlh/easyProxy/utils"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type list struct {
|
||||||
|
connList chan *utils.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *list) Add(c *utils.Conn) {
|
||||||
|
l.connList <- c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *list) Pop() *utils.Conn {
|
||||||
|
return <-l.connList
|
||||||
|
}
|
||||||
|
func (l *list) Len() int {
|
||||||
|
return len(l.connList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newList() *list {
|
||||||
|
l := new(list)
|
||||||
|
l.connList = make(chan *utils.Conn, 1000)
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tunnel struct {
|
||||||
|
TunnelPort int //通信隧道端口
|
||||||
|
listener *net.TCPListener //server端监听
|
||||||
|
SignalList map[string]*list //通信
|
||||||
|
TunnelList map[string]*list //隧道
|
||||||
|
RunList map[string]interface{} //运行中的任务
|
||||||
|
lock sync.Mutex
|
||||||
|
tunnelLock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTunnel(tunnelPort int, runList map[string]interface{}) *Tunnel {
|
||||||
|
t := new(Tunnel)
|
||||||
|
t.TunnelPort = tunnelPort
|
||||||
|
t.SignalList = make(map[string]*list)
|
||||||
|
t.TunnelList = make(map[string]*list)
|
||||||
|
t.RunList = runList
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Tunnel) StartTunnel() error {
|
||||||
|
var err error
|
||||||
|
s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.TunnelPort, ""})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go s.tunnelProcess()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//tcp server
|
||||||
|
func (s *Tunnel) tunnelProcess() error {
|
||||||
|
var err error
|
||||||
|
for {
|
||||||
|
conn, err := s.listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go s.cliProcess(utils.NewConn(conn))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//验证失败,返回错误验证flag,并且关闭连接
|
||||||
|
func (s *Tunnel) verifyError(c *utils.Conn) {
|
||||||
|
c.Conn.Write([]byte(utils.VERIFY_EER))
|
||||||
|
c.Conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Tunnel) cliProcess(c *utils.Conn) error {
|
||||||
|
c.Conn.(*net.TCPConn).SetReadDeadline(time.Now().Add(time.Duration(5) * time.Second))
|
||||||
|
vval := make([]byte, 32)
|
||||||
|
if _, err := c.Conn.Read(vval); err != nil {
|
||||||
|
log.Println("客户端读超时。客户端地址为::", c.Conn.RemoteAddr())
|
||||||
|
c.Conn.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !s.verify(string(vval)) {
|
||||||
|
log.Println("当前客户端连接校验错误,关闭此客户端:", c.Conn.RemoteAddr())
|
||||||
|
s.verifyError(c)
|
||||||
|
return errors.New("验证错误")
|
||||||
|
}
|
||||||
|
log.Println("客户端连接成功: ", c.Conn.RemoteAddr())
|
||||||
|
c.Conn.(*net.TCPConn).SetReadDeadline(time.Time{})
|
||||||
|
//做一个判断 添加到对应的channel里面以供使用
|
||||||
|
if flag, err := c.ReadFlag(); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
return s.typeDeal(flag, c, string(vval))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//tcp连接类型区分
|
||||||
|
func (s *Tunnel) typeDeal(typeVal string, c *utils.Conn, cFlag string) error {
|
||||||
|
switch typeVal {
|
||||||
|
case utils.WORK_MAIN:
|
||||||
|
s.addList(s.SignalList, c, cFlag)
|
||||||
|
case utils.WORK_CHAN:
|
||||||
|
s.addList(s.TunnelList, c, cFlag)
|
||||||
|
default:
|
||||||
|
return errors.New("无法识别")
|
||||||
|
}
|
||||||
|
c.SetAlive()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//加到对应的list中
|
||||||
|
func (s *Tunnel) addList(m map[string]*list, c *utils.Conn, cFlag string) {
|
||||||
|
s.lock.Lock()
|
||||||
|
if v, ok := m[cFlag]; ok {
|
||||||
|
v.Add(c)
|
||||||
|
} else {
|
||||||
|
l := newList()
|
||||||
|
l.Add(c)
|
||||||
|
m[cFlag] = l
|
||||||
|
}
|
||||||
|
s.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
//新建隧道
|
||||||
|
func (s *Tunnel) newChan(cFlag string) error {
|
||||||
|
if err := s.wait(s.SignalList, cFlag); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
retry:
|
||||||
|
connPass := s.SignalList[cFlag].Pop()
|
||||||
|
_, err := connPass.Conn.Write([]byte("chan"))
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
goto retry
|
||||||
|
}
|
||||||
|
s.SignalList[cFlag].Add(connPass)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//得到一个tcp隧道
|
||||||
|
func (s *Tunnel) GetTunnel(cFlag string, en, de int, crypt, mux bool) (c *utils.Conn, err error) {
|
||||||
|
s.tunnelLock.Lock()
|
||||||
|
if v, ok := s.TunnelList[cFlag]; !ok || v.Len() < 3 { //新建通道
|
||||||
|
go s.newChan(cFlag)
|
||||||
|
}
|
||||||
|
retry:
|
||||||
|
if err = s.wait(s.TunnelList, cFlag); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c = s.TunnelList[cFlag].Pop()
|
||||||
|
if _, err = c.WriteTest(); err != nil {
|
||||||
|
c.Close()
|
||||||
|
goto retry
|
||||||
|
}
|
||||||
|
c.WriteConnInfo(en, de, crypt, mux)
|
||||||
|
s.tunnelLock.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//得到一个通信通道
|
||||||
|
func (s *Tunnel) GetSignal(cFlag string) (err error, conn *utils.Conn) {
|
||||||
|
if v, ok := s.SignalList[cFlag]; !ok || v.Len() == 0 {
|
||||||
|
err = errors.New("客户端未连接")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn = s.SignalList[cFlag].Pop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//重回slice 复用
|
||||||
|
func (s *Tunnel) ReturnSignal(conn *utils.Conn, cFlag string) {
|
||||||
|
if v, ok := s.SignalList[cFlag]; ok {
|
||||||
|
v.Add(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//重回slice 复用
|
||||||
|
func (s *Tunnel) ReturnTunnel(conn *utils.Conn, cFlag string) {
|
||||||
|
if v, ok := s.TunnelList[cFlag]; ok {
|
||||||
|
utils.FlushConn(conn.Conn)
|
||||||
|
v.Add(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//删除通信通道
|
||||||
|
func (s *Tunnel) DelClientSignal(cFlag string) {
|
||||||
|
s.delClient(cFlag, s.SignalList)
|
||||||
|
}
|
||||||
|
|
||||||
|
//删除隧道
|
||||||
|
func (s *Tunnel) DelClientTunnel(cFlag string) {
|
||||||
|
s.delClient(cFlag, s.TunnelList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Tunnel) delClient(cFlag string, l map[string]*list) {
|
||||||
|
if t := l[utils.Getverifyval(cFlag)]; t != nil {
|
||||||
|
for {
|
||||||
|
if t.Len() <= 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
t.Pop().Close()
|
||||||
|
}
|
||||||
|
delete(l, utils.Getverifyval(cFlag))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//等待
|
||||||
|
func (s *Tunnel) wait(m map[string]*list, cFlag string) error {
|
||||||
|
ticker := time.NewTicker(time.Millisecond * 100)
|
||||||
|
stop := time.After(time.Second * 10)
|
||||||
|
loop:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
if _, ok := m[cFlag]; ok {
|
||||||
|
ticker.Stop()
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
case <-stop:
|
||||||
|
return errors.New("client key: " + cFlag + ",err: get client conn timeout")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Tunnel) verify(vKeyMd5 string) bool {
|
||||||
|
for k := range s.RunList {
|
||||||
|
if utils.Getverifyval(k) == vKeyMd5 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
package lib
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"github.com/cnlh/easyProxy/utils"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
@ -28,54 +27,49 @@ func NewRPClient(svraddr string, tcpNum int, vKey string) *TRPClient {
|
|||||||
//start
|
//start
|
||||||
func (s *TRPClient) Start() error {
|
func (s *TRPClient) Start() error {
|
||||||
for i := 0; i < s.tcpNum; i++ {
|
for i := 0; i < s.tcpNum; i++ {
|
||||||
go s.newConn()
|
go s.NewConn()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//新建
|
//新建
|
||||||
func (s *TRPClient) newConn() error {
|
func (s *TRPClient) NewConn() error {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
conn, err := net.Dial("tcp", s.svrAddr)
|
conn, err := net.Dial("tcp", s.svrAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("连接服务端失败,五秒后将重连")
|
log.Println("连接服务端失败,五秒后将重连")
|
||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 5)
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
go s.newConn()
|
go s.NewConn()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.Unlock()
|
s.Unlock()
|
||||||
return s.process(NewConn(conn))
|
return s.process(utils.NewConn(conn))
|
||||||
}
|
}
|
||||||
|
|
||||||
//处理
|
//处理
|
||||||
func (s *TRPClient) process(c *Conn) error {
|
func (s *TRPClient) process(c *utils.Conn) error {
|
||||||
c.SetAlive()
|
c.SetAlive()
|
||||||
if _, err := c.Write([]byte(getverifyval(s.vKey))); err != nil {
|
if _, err := c.Write([]byte(utils.Getverifyval(s.vKey))); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.wMain()
|
c.WriteMain()
|
||||||
for {
|
for {
|
||||||
flags, err := c.ReadFlag()
|
flags, err := c.ReadFlag()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("服务端断开,五秒后将重连", err)
|
log.Println("服务端断开,五秒后将重连", err)
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
go s.newConn()
|
go s.NewConn()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
switch flags {
|
switch flags {
|
||||||
case VERIFY_EER:
|
case utils.VERIFY_EER:
|
||||||
log.Fatalln("vkey:", s.vKey, "不正确,服务端拒绝连接,请检查")
|
log.Fatalln("vkey:", s.vKey, "不正确,服务端拒绝连接,请检查")
|
||||||
case RES_SIGN: //代理请求模式
|
case utils.WORK_CHAN: //隧道模式,每次开启10个,加快连接速度
|
||||||
if err := s.dealHttp(c); err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case WORK_CHAN: //隧道模式,每次开启10个,加快连接速度
|
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
go s.dealChan()
|
go s.dealChan()
|
||||||
}
|
}
|
||||||
case RES_MSG:
|
case utils.RES_MSG:
|
||||||
log.Println("服务端返回错误。")
|
log.Println("服务端返回错误。")
|
||||||
default:
|
default:
|
||||||
log.Println("无法解析该错误。", flags)
|
log.Println("无法解析该错误。", flags)
|
||||||
@ -94,15 +88,15 @@ func (s *TRPClient) dealChan() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
//验证
|
//验证
|
||||||
if _, err := conn.Write([]byte(getverifyval(s.vKey))); err != nil {
|
if _, err := conn.Write([]byte(utils.Getverifyval(s.vKey))); err != nil {
|
||||||
log.Println("connect to ", s.svrAddr, "error:", err)
|
log.Println("connect to ", s.svrAddr, "error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//默认长连接保持
|
//默认长连接保持
|
||||||
c := NewConn(conn)
|
c := utils.NewConn(conn)
|
||||||
c.SetAlive()
|
c.SetAlive()
|
||||||
//写标志
|
//写标志
|
||||||
c.wChan()
|
c.WriteChan()
|
||||||
re:
|
re:
|
||||||
//获取连接的host type(tcp or udp)
|
//获取连接的host type(tcp or udp)
|
||||||
typeStr, host, en, de, crypt, mux, err := c.GetHostFromConn()
|
typeStr, host, en, de, crypt, mux, err := c.GetHostFromConn()
|
||||||
@ -111,51 +105,24 @@ re:
|
|||||||
c.Close()
|
c.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//与目标建立连接,超时时间为3
|
Process(c, typeStr, host, en, de, crypt, mux)
|
||||||
server, err := net.DialTimeout(typeStr, host, time.Second*3)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("connect to ", host, "error:", err, mux)
|
|
||||||
c.wFail()
|
|
||||||
goto end
|
|
||||||
}
|
|
||||||
c.wSuccess()
|
|
||||||
go relay(server, c.conn, de, crypt, mux)
|
|
||||||
relay(c.conn, server, en, crypt, mux)
|
|
||||||
end:
|
|
||||||
if mux {
|
if mux {
|
||||||
FlushConn(conn)
|
utils.FlushConn(conn)
|
||||||
goto re
|
goto re
|
||||||
} else {
|
} else {
|
||||||
c.Close()
|
c.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//http模式处理
|
func Process(c *utils.Conn, typeStr, host string, en, de int, crypt, mux bool) {
|
||||||
func (s *TRPClient) dealHttp(c *Conn) error {
|
//与目标建立连接,超时时间为3
|
||||||
buf := make([]byte, 1024*32)
|
server, err := net.DialTimeout(typeStr, host, time.Second*3)
|
||||||
en, de, crypt, _ := c.GetConnInfoFromConn()
|
|
||||||
n, err := c.ReadFrom(buf, de, crypt)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.wError()
|
log.Println("connect to ", host, "error:", err, mux)
|
||||||
return err
|
c.WriteFail()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
req, err := DecodeRequest(buf[:n])
|
c.WriteSuccess()
|
||||||
if err != nil {
|
go utils.Relay(server, c.Conn, de, crypt, mux)
|
||||||
c.wError()
|
utils.Relay(c.Conn, server, en, crypt, mux)
|
||||||
return err
|
|
||||||
}
|
|
||||||
respBytes, err := GetEncodeResponse(req)
|
|
||||||
if err != nil {
|
|
||||||
c.wError()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.wSign()
|
|
||||||
n, err = c.WriteTo(respBytes, en, crypt)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if n != len(respBytes) {
|
|
||||||
return errors.New(fmt.Sprintf("发送数据长度错误,已经发送:%dbyte,总字节长:%dbyte\n", n, len(respBytes)))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
27
cmd/proxy_client.go
Normal file
27
cmd/proxy_client.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"github.com/cnlh/easyProxy/client"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
serverAddr = flag.String("server", "", "服务器地址ip:端口")
|
||||||
|
verifyKey = flag.String("vkey", "", "验证密钥")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
//go func() {
|
||||||
|
// http.ListenAndServe("0.0.0.0:8899", nil)
|
||||||
|
//}()
|
||||||
|
stop := make(chan int)
|
||||||
|
for _, v := range strings.Split(*verifyKey, ",") {
|
||||||
|
log.Println("客户端启动,连接:", *serverAddr, " 验证令牌:", v)
|
||||||
|
go client.NewRPClient(*serverAddr, 1, v).Start()
|
||||||
|
}
|
||||||
|
<-stop
|
||||||
|
}
|
47
cmd/proxy_server.go
Normal file
47
cmd/proxy_server.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"github.com/cnlh/easyProxy/server"
|
||||||
|
"github.com/cnlh/easyProxy/utils"
|
||||||
|
_ "github.com/cnlh/easyProxy/web/routers"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
configPath = flag.String("config", "config.json", "配置文件路径")
|
||||||
|
TcpPort = flag.Int("tcpport", 8284, "客户端与服务端通信端口")
|
||||||
|
httpPort = flag.Int("httpport", 8024, "对外监听的端口")
|
||||||
|
rpMode = flag.String("mode", "client", "启动模式")
|
||||||
|
tunnelTarget = flag.String("target", "10.1.50.203:80", "远程目标")
|
||||||
|
VerifyKey = flag.String("vkey", "", "验证密钥")
|
||||||
|
u = flag.String("u", "", "验证用户名(socks5和web)")
|
||||||
|
p = flag.String("p", "", "验证密码(socks5和web)")
|
||||||
|
compress = flag.String("compress", "", "数据压缩方式(snappy)")
|
||||||
|
crypt = flag.String("crypt", "false", "是否加密(true|false)")
|
||||||
|
mux = flag.String("mux", "false", "是否TCP多路复用(true|false)")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
server.VerifyKey = *VerifyKey
|
||||||
|
log.Println("服务端启动,监听tcp服务端端口:", *TcpPort)
|
||||||
|
cnf := server.ServerConfig{
|
||||||
|
TcpPort: *httpPort,
|
||||||
|
Mode: *rpMode,
|
||||||
|
Target: *tunnelTarget,
|
||||||
|
VerifyKey: *VerifyKey,
|
||||||
|
U: *u,
|
||||||
|
P: *p,
|
||||||
|
Compress: *compress,
|
||||||
|
Start: 0,
|
||||||
|
IsRun: 0,
|
||||||
|
ClientStatus: 0,
|
||||||
|
Crypt: utils.GetBoolByStr(*crypt),
|
||||||
|
Mux: utils.GetBoolByStr(*mux),
|
||||||
|
CompressEncode: 0,
|
||||||
|
CompressDecode: 0,
|
||||||
|
}
|
||||||
|
cnf.CompressDecode, cnf.CompressEncode = utils.GetCompressType(cnf.Compress)
|
||||||
|
server.StartNewServer(*TcpPort, &cnf)
|
||||||
|
}
|
@ -4,7 +4,7 @@ appname = easyProxy
|
|||||||
httpport = 8080
|
httpport = 8080
|
||||||
|
|
||||||
#启动模式dev|pro
|
#启动模式dev|pro
|
||||||
runmode = pro
|
runmode = dev
|
||||||
|
|
||||||
#web管理密码
|
#web管理密码
|
||||||
password=123
|
password=123
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
b.proxy.com,127.0.0.1:82,o2430bnq22jgnmcl
|
b.proxy.com,127.0.0.1:82,o2430bnq22jgnmcl
|
||||||
b.o.com,127.0.0.1:88,ts08z6vk5nc72fs8
|
b.o.com,127.0.0.1:88,ts08z6vk5nc72fs8
|
||||||
a.o.com,127.0.0.1:88,ts08z6vk5nc72fs8
|
a.o.com,127.0.0.1:88,7n7bxc2bm1fyjfab
|
||||||
|
|
@ -1,3 +1,5 @@
|
|||||||
8001,tunnelServer,127.0.0.1:88,jq5i7n0sjs1h0jje,aaa,bbb,,1,0,0,0,1
|
8001,tunnelServer,127.0.0.1:88,jq5i7n0sjs1h0jje,aaa,bbb,,1,0,0,0,1
|
||||||
0,hostServer,,ts08z6vk5nc72fs8,aaac,bbb,snappy,1,0,1,2,3
|
|
||||||
0,hostServer,,7n7bxc2bm1fyjfab,ab,b,,1,1,1,0,1
|
0,hostServer,,7n7bxc2bm1fyjfab,ab,b,,1,1,1,0,1
|
||||||
|
0,hostServer,,ts08z6vk5nc72fs8,aaa,bbb,snappy,1,0,1,2,3
|
||||||
|
8002,tunnelServer,127.0.0.1:88,2nxo93wvotb9g75s,,,,1,0,0,0,1
|
||||||
|
8025,socks5Server,,2p3qs71oym3zx52w,,,,1,0,0,0,1
|
||||||
|
|
228
lib/bridge.go
228
lib/bridge.go
@ -1,228 +0,0 @@
|
|||||||
package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type list struct {
|
|
||||||
connList chan *Conn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *list) Add(c *Conn) {
|
|
||||||
l.connList <- c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *list) Pop() *Conn {
|
|
||||||
return <-l.connList
|
|
||||||
}
|
|
||||||
func (l *list) Len() int {
|
|
||||||
return len(l.connList)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newList() *list {
|
|
||||||
l := new(list)
|
|
||||||
l.connList = make(chan *Conn, 1000)
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tunnel struct {
|
|
||||||
tunnelPort int //通信隧道端口
|
|
||||||
listener *net.TCPListener //server端监听
|
|
||||||
signalList map[string]*list //通信
|
|
||||||
tunnelList map[string]*list //隧道
|
|
||||||
lock sync.Mutex
|
|
||||||
tunnelLock sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTunnel(tunnelPort int) *Tunnel {
|
|
||||||
t := new(Tunnel)
|
|
||||||
t.tunnelPort = tunnelPort
|
|
||||||
t.signalList = make(map[string]*list)
|
|
||||||
t.tunnelList = make(map[string]*list)
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Tunnel) StartTunnel() error {
|
|
||||||
var err error
|
|
||||||
s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.tunnelPort, ""})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
go s.tunnelProcess()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//tcp server
|
|
||||||
func (s *Tunnel) tunnelProcess() error {
|
|
||||||
var err error
|
|
||||||
for {
|
|
||||||
conn, err := s.listener.Accept()
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
go s.cliProcess(NewConn(conn))
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
//验证失败,返回错误验证flag,并且关闭连接
|
|
||||||
func (s *Tunnel) verifyError(c *Conn) {
|
|
||||||
c.conn.Write([]byte(VERIFY_EER))
|
|
||||||
c.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Tunnel) cliProcess(c *Conn) error {
|
|
||||||
c.conn.(*net.TCPConn).SetReadDeadline(time.Now().Add(time.Duration(5) * time.Second))
|
|
||||||
vval := make([]byte, 32)
|
|
||||||
if _, err := c.conn.Read(vval); err != nil {
|
|
||||||
log.Println("客户端读超时。客户端地址为::", c.conn.RemoteAddr())
|
|
||||||
c.conn.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !verify(string(vval)) {
|
|
||||||
log.Println("当前客户端连接校验错误,关闭此客户端:", c.conn.RemoteAddr())
|
|
||||||
s.verifyError(c)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.conn.(*net.TCPConn).SetReadDeadline(time.Time{})
|
|
||||||
//做一个判断 添加到对应的channel里面以供使用
|
|
||||||
if flag, err := c.ReadFlag(); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
return s.typeDeal(flag, c, string(vval))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//tcp连接类型区分
|
|
||||||
func (s *Tunnel) typeDeal(typeVal string, c *Conn, cFlag string) error {
|
|
||||||
switch typeVal {
|
|
||||||
case WORK_MAIN:
|
|
||||||
s.addList(s.signalList, c, cFlag)
|
|
||||||
case WORK_CHAN:
|
|
||||||
s.addList(s.tunnelList, c, cFlag)
|
|
||||||
default:
|
|
||||||
return errors.New("无法识别")
|
|
||||||
}
|
|
||||||
c.SetAlive()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//加到对应的list中
|
|
||||||
func (s *Tunnel) addList(m map[string]*list, c *Conn, cFlag string) {
|
|
||||||
s.lock.Lock()
|
|
||||||
if v, ok := m[cFlag]; ok {
|
|
||||||
v.Add(c)
|
|
||||||
} else {
|
|
||||||
l := newList()
|
|
||||||
l.Add(c)
|
|
||||||
m[cFlag] = l
|
|
||||||
}
|
|
||||||
s.lock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
//新建隧道
|
|
||||||
func (s *Tunnel) newChan(cFlag string) error {
|
|
||||||
if err := s.wait(s.signalList, cFlag); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
retry:
|
|
||||||
connPass := s.signalList[cFlag].Pop()
|
|
||||||
_, err := connPass.conn.Write([]byte("chan"))
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
goto retry
|
|
||||||
}
|
|
||||||
s.signalList[cFlag].Add(connPass)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//得到一个tcp隧道
|
|
||||||
func (s *Tunnel) GetTunnel(cFlag string, en, de int, crypt, mux bool) (c *Conn, err error) {
|
|
||||||
s.tunnelLock.Lock()
|
|
||||||
if v, ok := s.tunnelList[cFlag]; !ok || v.Len() < 3 { //新建通道
|
|
||||||
go s.newChan(cFlag)
|
|
||||||
}
|
|
||||||
retry:
|
|
||||||
if err = s.wait(s.tunnelList, cFlag); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c = s.tunnelList[cFlag].Pop()
|
|
||||||
if _, err = c.wTest(); err != nil {
|
|
||||||
c.Close()
|
|
||||||
goto retry
|
|
||||||
}
|
|
||||||
c.WriteConnInfo(en, de, crypt, mux)
|
|
||||||
s.tunnelLock.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//得到一个通信通道
|
|
||||||
func (s *Tunnel) GetSignal(cFlag string) (err error, conn *Conn) {
|
|
||||||
if v, ok := s.signalList[cFlag]; !ok || v.Len() == 0 {
|
|
||||||
err = errors.New("客户端未连接")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
conn = s.signalList[cFlag].Pop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//重回slice 复用
|
|
||||||
func (s *Tunnel) ReturnSignal(conn *Conn, cFlag string) {
|
|
||||||
if v, ok := s.signalList[cFlag]; ok {
|
|
||||||
v.Add(conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//重回slice 复用
|
|
||||||
func (s *Tunnel) ReturnTunnel(conn *Conn, cFlag string) {
|
|
||||||
if v, ok := s.tunnelList[cFlag]; ok {
|
|
||||||
FlushConn(conn.conn)
|
|
||||||
v.Add(conn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//删除通信通道
|
|
||||||
func (s *Tunnel) DelClientSignal(cFlag string) {
|
|
||||||
s.delClient(cFlag, s.signalList)
|
|
||||||
}
|
|
||||||
|
|
||||||
//删除隧道
|
|
||||||
func (s *Tunnel) DelClientTunnel(cFlag string) {
|
|
||||||
s.delClient(cFlag, s.tunnelList)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Tunnel) delClient(cFlag string, l map[string]*list) {
|
|
||||||
if t := l[getverifyval(cFlag)]; t != nil {
|
|
||||||
for {
|
|
||||||
if t.Len() <= 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
t.Pop().Close()
|
|
||||||
}
|
|
||||||
delete(l, getverifyval(cFlag))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//等待
|
|
||||||
func (s *Tunnel) wait(m map[string]*list, cFlag string) error {
|
|
||||||
ticker := time.NewTicker(time.Millisecond * 100)
|
|
||||||
stop := time.After(time.Second * 10)
|
|
||||||
loop:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
if _, ok := m[cFlag]; ok {
|
|
||||||
ticker.Stop()
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
case <-stop:
|
|
||||||
return errors.New("client key: " + cFlag + ",err: get client conn timeout")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
201
lib/init.go
201
lib/init.go
@ -1,201 +0,0 @@
|
|||||||
package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"flag"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
_ "net/http/pprof"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
configPath = flag.String("config", "config.json", "配置文件路径")
|
|
||||||
TcpPort = flag.Int("tcpport", 8284, "客户端与服务端通信端口")
|
|
||||||
httpPort = flag.Int("httpport", 8024, "对外监听的端口")
|
|
||||||
rpMode = flag.String("mode", "client", "启动模式")
|
|
||||||
tunnelTarget = flag.String("target", "10.1.50.203:80", "远程目标")
|
|
||||||
verifyKey = flag.String("vkey", "", "验证密钥")
|
|
||||||
u = flag.String("u", "", "验证用户名(socks5和web)")
|
|
||||||
p = flag.String("p", "", "验证密码(socks5和web)")
|
|
||||||
compress = flag.String("compress", "", "数据压缩方式(snappy)")
|
|
||||||
serverAddr = flag.String("server", "", "服务器地址ip:端口")
|
|
||||||
crypt = flag.String("crypt", "false", "是否加密(true|false)")
|
|
||||||
mux = flag.String("mux", "false", "是否TCP多路复用(true|false)")
|
|
||||||
config Config
|
|
||||||
err error
|
|
||||||
RunList map[string]interface{} //运行中的任务
|
|
||||||
bridge *Tunnel
|
|
||||||
CsvDb *Csv
|
|
||||||
)
|
|
||||||
|
|
||||||
const cryptKey = "1234567812345678"
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
RunList = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitClient() {
|
|
||||||
flag.Parse()
|
|
||||||
if *rpMode == "client" {
|
|
||||||
go func() {
|
|
||||||
http.ListenAndServe("0.0.0.0:8899", nil)
|
|
||||||
}()
|
|
||||||
JsonParse := NewJsonStruct()
|
|
||||||
if config, err = JsonParse.Load(*configPath); err != nil {
|
|
||||||
log.Println("配置文件加载失败")
|
|
||||||
}
|
|
||||||
stop := make(chan int)
|
|
||||||
for _, v := range strings.Split(*verifyKey, ",") {
|
|
||||||
log.Println("客户端启动,连接:", *serverAddr, " 验证令牌:", v)
|
|
||||||
go NewRPClient(*serverAddr, 1, v).Start()
|
|
||||||
}
|
|
||||||
<-stop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func InitMode() {
|
|
||||||
flag.Parse()
|
|
||||||
if *rpMode == "client" {
|
|
||||||
go func() {
|
|
||||||
http.ListenAndServe("0.0.0.0:8899", nil)
|
|
||||||
}()
|
|
||||||
JsonParse := NewJsonStruct()
|
|
||||||
if config, err = JsonParse.Load(*configPath); err != nil {
|
|
||||||
log.Println("配置文件加载失败")
|
|
||||||
}
|
|
||||||
stop := make(chan int)
|
|
||||||
for _, v := range strings.Split(*verifyKey, ",") {
|
|
||||||
log.Println("客户端启动,连接:", *serverAddr, " 验证令牌:", v)
|
|
||||||
go NewRPClient(*serverAddr, 1, v).Start()
|
|
||||||
}
|
|
||||||
<-stop
|
|
||||||
} else {
|
|
||||||
bridge = newTunnel(*TcpPort)
|
|
||||||
if err := bridge.StartTunnel(); err != nil {
|
|
||||||
log.Fatalln("服务端开启失败", err)
|
|
||||||
}
|
|
||||||
log.Println("服务端启动,监听tcp服务端端口:", *TcpPort)
|
|
||||||
cnf := ServerConfig{
|
|
||||||
TcpPort: *httpPort,
|
|
||||||
Mode: *rpMode,
|
|
||||||
Target: *tunnelTarget,
|
|
||||||
VerifyKey: *verifyKey,
|
|
||||||
U: *u,
|
|
||||||
P: *p,
|
|
||||||
Compress: *compress,
|
|
||||||
Start: 0,
|
|
||||||
IsRun: 0,
|
|
||||||
ClientStatus: 0,
|
|
||||||
Crypt: GetBoolByStr(*crypt),
|
|
||||||
Mux: GetBoolByStr(*mux),
|
|
||||||
CompressEncode: 0,
|
|
||||||
CompressDecode: 0,
|
|
||||||
}
|
|
||||||
cnf.CompressDecode, cnf.CompressEncode = getCompressType(cnf.Compress)
|
|
||||||
if svr := newMode(bridge, &cnf);
|
|
||||||
svr != nil {
|
|
||||||
reflect.ValueOf(svr).MethodByName("Start").Call(nil)
|
|
||||||
} else {
|
|
||||||
log.Fatalln("启动模式不正确")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//从csv文件中恢复任务
|
|
||||||
func InitFromCsv() {
|
|
||||||
for _, v := range CsvDb.Tasks {
|
|
||||||
if v.Start == 1 {
|
|
||||||
log.Println(""+
|
|
||||||
"启动模式:", v.Mode, "监听端口:", v.TcpPort, "客户端令牌:", v.VerifyKey)
|
|
||||||
AddTask(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMode(bridge *Tunnel, config *ServerConfig) interface{} {
|
|
||||||
switch config.Mode {
|
|
||||||
case "httpServer":
|
|
||||||
return NewHttpModeServer(bridge, config)
|
|
||||||
case "tunnelServer":
|
|
||||||
return NewTunnelModeServer(ProcessTunnel, bridge, config)
|
|
||||||
case "socks5Server":
|
|
||||||
return NewSock5ModeServer(bridge, config)
|
|
||||||
case "httpProxyServer":
|
|
||||||
return NewTunnelModeServer(ProcessHttp, bridge, config)
|
|
||||||
case "udpServer":
|
|
||||||
return NewUdpModeServer(bridge, config)
|
|
||||||
case "webServer":
|
|
||||||
InitCsvDb()
|
|
||||||
return NewWebServer(bridge)
|
|
||||||
case "hostServer":
|
|
||||||
return NewHostServer(config)
|
|
||||||
case "httpHostServer":
|
|
||||||
return NewTunnelModeServer(ProcessHost, bridge, config)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func StopServer(cFlag string) error {
|
|
||||||
if v, ok := RunList[cFlag]; ok {
|
|
||||||
reflect.ValueOf(v).MethodByName("Close").Call(nil)
|
|
||||||
delete(RunList, cFlag)
|
|
||||||
if *verifyKey == "" { //多客户端模式关闭相关隧道
|
|
||||||
bridge.DelClientSignal(cFlag)
|
|
||||||
bridge.DelClientTunnel(cFlag)
|
|
||||||
}
|
|
||||||
if t, err := CsvDb.GetTask(cFlag); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
t.Start = 0
|
|
||||||
CsvDb.UpdateTask(t)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.New("未在运行中")
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddTask(t *ServerConfig) error {
|
|
||||||
t.CompressDecode, t.CompressEncode = getCompressType(t.Compress)
|
|
||||||
if svr := newMode(bridge, t); svr != nil {
|
|
||||||
RunList[t.VerifyKey] = svr
|
|
||||||
go func() {
|
|
||||||
err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
|
|
||||||
if err.Interface() != nil {
|
|
||||||
log.Println("客户端", t.VerifyKey, "启动失败,错误:", err)
|
|
||||||
delete(RunList, t.VerifyKey)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
} else {
|
|
||||||
return errors.New("启动模式不正确")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func StartTask(vKey string) error {
|
|
||||||
if t, err := CsvDb.GetTask(vKey); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
AddTask(t)
|
|
||||||
t.Start = 1
|
|
||||||
CsvDb.UpdateTask(t)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DelTask(vKey string) error {
|
|
||||||
if err := StopServer(vKey); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return CsvDb.DelTask(vKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitCsvDb() *Csv {
|
|
||||||
var once sync.Once
|
|
||||||
once.Do(func() {
|
|
||||||
CsvDb = NewCsv( bridge, RunList)
|
|
||||||
CsvDb.Init()
|
|
||||||
})
|
|
||||||
return CsvDb
|
|
||||||
}
|
|
326
lib/tcp.go
326
lib/tcp.go
@ -1,326 +0,0 @@
|
|||||||
package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/astaxie/beego"
|
|
||||||
"github.com/astaxie/beego/session"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var GlobalHostSessions *session.Manager
|
|
||||||
|
|
||||||
const (
|
|
||||||
VERIFY_EER = "vkey"
|
|
||||||
WORK_MAIN = "main"
|
|
||||||
WORK_CHAN = "chan"
|
|
||||||
RES_SIGN = "sign"
|
|
||||||
RES_MSG = "msg0"
|
|
||||||
CONN_SUCCESS = "sucs"
|
|
||||||
CONN_ERROR = "fail"
|
|
||||||
TEST_FLAG = "tst"
|
|
||||||
CONN_TCP = "tcp"
|
|
||||||
CONN_UDP = "udp"
|
|
||||||
Unauthorized_BYTES = `HTTP/1.1 401 Unauthorized
|
|
||||||
Content-Type: text/plain; charset=utf-8
|
|
||||||
WWW-Authenticate: Basic realm="easyProxy"
|
|
||||||
|
|
||||||
401 Unauthorized`
|
|
||||||
)
|
|
||||||
|
|
||||||
type process func(c *Conn, s *TunnelModeServer) error
|
|
||||||
|
|
||||||
type HttpModeServer struct {
|
|
||||||
bridge *Tunnel
|
|
||||||
config *ServerConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
//http
|
|
||||||
func NewHttpModeServer(bridge *Tunnel, cnf *ServerConfig) *HttpModeServer {
|
|
||||||
s := new(HttpModeServer)
|
|
||||||
s.bridge = bridge
|
|
||||||
s.config = cnf
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
//开始
|
|
||||||
func (s *HttpModeServer) Start() {
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
retry:
|
|
||||||
u := beego.AppConfig.String("basic.user")
|
|
||||||
p := beego.AppConfig.String("basic.password")
|
|
||||||
if u != "" && p != "" && !checkAuth(r, u, p) {
|
|
||||||
w.Header().Set("WWW-Authenticate", `Basic realm="easyProxy""`)
|
|
||||||
w.WriteHeader(401)
|
|
||||||
w.Write([]byte("401 Unauthorized\n"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err, conn := s.bridge.GetSignal(getverifyval(s.config.VerifyKey))
|
|
||||||
if err != nil {
|
|
||||||
BadRequest(w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := s.writeRequest(r, conn); err != nil {
|
|
||||||
log.Println("write request to client error:", err)
|
|
||||||
conn.Close()
|
|
||||||
goto retry
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = s.writeResponse(w, conn)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("write response error:", err)
|
|
||||||
conn.Close()
|
|
||||||
goto retry
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.bridge.ReturnSignal(conn, getverifyval(s.config.VerifyKey))
|
|
||||||
})
|
|
||||||
log.Fatalln(http.ListenAndServe(fmt.Sprintf(":%d", s.config.TcpPort), nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
//req转为bytes发送给client端
|
|
||||||
func (s *HttpModeServer) writeRequest(r *http.Request, conn *Conn) error {
|
|
||||||
raw, err := EncodeRequest(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
conn.wSign()
|
|
||||||
conn.WriteConnInfo(s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
|
|
||||||
c, err := conn.WriteTo(raw, s.config.CompressEncode, s.config.Crypt)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if c != len(raw) {
|
|
||||||
return errors.New("写出长度与字节长度不一致。")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//从client读取出Response
|
|
||||||
func (s *HttpModeServer) writeResponse(w http.ResponseWriter, c *Conn) error {
|
|
||||||
flags, err := c.ReadFlag()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch flags {
|
|
||||||
case RES_SIGN:
|
|
||||||
buf := make([]byte, 1024*1024*32)
|
|
||||||
n, err := c.ReadFrom(buf, s.config.CompressDecode, s.config.Crypt)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
resp, err := DecodeResponse(buf[:n])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
bodyBytes, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for k, v := range resp.Header {
|
|
||||||
for _, v2 := range v {
|
|
||||||
w.Header().Set(k, v2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.WriteHeader(resp.StatusCode)
|
|
||||||
w.Write(bodyBytes)
|
|
||||||
case RES_MSG:
|
|
||||||
BadRequest(w)
|
|
||||||
return errors.New("客户端请求出错")
|
|
||||||
default:
|
|
||||||
BadRequest(w)
|
|
||||||
return errors.New("无法解析此错误")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type TunnelModeServer struct {
|
|
||||||
process process
|
|
||||||
bridge *Tunnel
|
|
||||||
config *ServerConfig
|
|
||||||
listener *net.TCPListener
|
|
||||||
}
|
|
||||||
|
|
||||||
//tcp|http|host
|
|
||||||
func NewTunnelModeServer(process process, bridge *Tunnel, cnf *ServerConfig) *TunnelModeServer {
|
|
||||||
s := new(TunnelModeServer)
|
|
||||||
s.bridge = bridge
|
|
||||||
s.process = process
|
|
||||||
s.config = cnf
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
//开始
|
|
||||||
func (s *TunnelModeServer) Start() error {
|
|
||||||
s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.config.TcpPort, ""})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for {
|
|
||||||
conn, err := s.listener.AcceptTCP()
|
|
||||||
if err != nil {
|
|
||||||
if strings.Contains(err.Error(), "use of closed network connection") {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
log.Println(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
go s.process(NewConn(conn), s)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//权限认证
|
|
||||||
func (s *TunnelModeServer) auth(r *http.Request, c *Conn, u, p string) error {
|
|
||||||
if u != "" && p != "" && !checkAuth(r, u, p) {
|
|
||||||
c.Write([]byte(Unauthorized_BYTES))
|
|
||||||
c.Close()
|
|
||||||
return errors.New("401 Unauthorized")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//与客户端建立通道
|
|
||||||
func (s *TunnelModeServer) dealClient(c *Conn, cnf *ServerConfig, addr string, method string, rb []byte) error {
|
|
||||||
link, err := s.bridge.GetTunnel(getverifyval(cnf.VerifyKey), cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, cnf.Mux)
|
|
||||||
defer func() {
|
|
||||||
if cnf.Mux {
|
|
||||||
s.bridge.ReturnTunnel(link, getverifyval(cnf.VerifyKey))
|
|
||||||
} else {
|
|
||||||
c.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
c.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err := link.WriteHost(CONN_TCP, addr); err != nil {
|
|
||||||
c.Close()
|
|
||||||
link.Close()
|
|
||||||
log.Println(err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if flag, err := link.ReadFlag(); err == nil {
|
|
||||||
if flag == CONN_SUCCESS {
|
|
||||||
if method == "CONNECT" {
|
|
||||||
fmt.Fprint(c, "HTTP/1.1 200 Connection established\r\n")
|
|
||||||
} else {
|
|
||||||
link.WriteTo(rb, cnf.CompressEncode, cnf.Crypt)
|
|
||||||
}
|
|
||||||
go relay(link.conn, c.conn, cnf.CompressEncode, cnf.Crypt, cnf.Mux)
|
|
||||||
relay(c.conn, link.conn, cnf.CompressDecode, cnf.Crypt, cnf.Mux)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//close
|
|
||||||
func (s *TunnelModeServer) Close() error {
|
|
||||||
return s.listener.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
//tcp隧道模式
|
|
||||||
func ProcessTunnel(c *Conn, s *TunnelModeServer) error {
|
|
||||||
method, _, rb, err, r := c.GetHost()
|
|
||||||
if err == nil {
|
|
||||||
if err := s.auth(r, c, s.config.U, s.config.P); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s.dealClient(c, s.config, s.config.Target, method, rb)
|
|
||||||
}
|
|
||||||
|
|
||||||
//http代理模式
|
|
||||||
func ProcessHttp(c *Conn, s *TunnelModeServer) error {
|
|
||||||
method, addr, rb, err, r := c.GetHost()
|
|
||||||
if err != nil {
|
|
||||||
c.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := s.auth(r, c, s.config.U, s.config.P); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
//TODO效率问题
|
|
||||||
return s.dealClient(c, s.config, addr, method, rb)
|
|
||||||
}
|
|
||||||
|
|
||||||
//多客户端域名代理
|
|
||||||
func ProcessHost(c *Conn, s *TunnelModeServer) error {
|
|
||||||
method, addr, rb, err, r := c.GetHost()
|
|
||||||
if err != nil {
|
|
||||||
c.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
host, task, err := getKeyByHost(addr)
|
|
||||||
if err := s.auth(r, c, task.U, task.P); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
c.Close()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return s.dealClient(c, task, host.Target, method, rb)
|
|
||||||
}
|
|
||||||
|
|
||||||
//web管理方式
|
|
||||||
type WebServer struct {
|
|
||||||
bridge *Tunnel
|
|
||||||
}
|
|
||||||
|
|
||||||
//开始
|
|
||||||
func (s *WebServer) Start() {
|
|
||||||
InitFromCsv()
|
|
||||||
p, _ := beego.AppConfig.Int("hostPort")
|
|
||||||
t := &ServerConfig{
|
|
||||||
TcpPort: p,
|
|
||||||
Mode: "httpHostServer",
|
|
||||||
Target: "",
|
|
||||||
VerifyKey: "",
|
|
||||||
U: "",
|
|
||||||
P: "",
|
|
||||||
Compress: "",
|
|
||||||
Start: 1,
|
|
||||||
IsRun: 0,
|
|
||||||
ClientStatus: 0,
|
|
||||||
}
|
|
||||||
AddTask(t)
|
|
||||||
beego.BConfig.WebConfig.Session.SessionOn = true
|
|
||||||
log.Println("web管理启动,访问端口为", beego.AppConfig.String("httpport"))
|
|
||||||
beego.SetViewsPath(beego.AppPath + "/views/")
|
|
||||||
beego.SetStaticPath("/static/", beego.AppPath+"/static/")
|
|
||||||
beego.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
//new
|
|
||||||
func NewWebServer(bridge *Tunnel) *WebServer {
|
|
||||||
s := new(WebServer)
|
|
||||||
s.bridge = bridge
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
//host
|
|
||||||
type HostServer struct {
|
|
||||||
config *ServerConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
//开始
|
|
||||||
func (s *HostServer) Start() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO:host模式的客户端,无需指定和监听端口等
|
|
||||||
func NewHostServer(cnf *ServerConfig) *HostServer {
|
|
||||||
s := new(HostServer)
|
|
||||||
s.config = cnf
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
//close
|
|
||||||
func (s *HostServer) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
330
lib/util.go
330
lib/util.go
@ -1,330 +0,0 @@
|
|||||||
package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httputil"
|
|
||||||
"net/url"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
disabledRedirect = errors.New("disabled redirect.")
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
COMPRESS_NONE_ENCODE = iota
|
|
||||||
COMPRESS_NONE_DECODE
|
|
||||||
COMPRESS_SNAPY_ENCODE
|
|
||||||
COMPRESS_SNAPY_DECODE
|
|
||||||
IO_EOF = "PROXYEOF"
|
|
||||||
)
|
|
||||||
|
|
||||||
//error
|
|
||||||
func BadRequest(w http.ResponseWriter) {
|
|
||||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
//发送请求并转为bytes
|
|
||||||
func GetEncodeResponse(req *http.Request) ([]byte, error) {
|
|
||||||
var respBytes []byte
|
|
||||||
client := new(http.Client)
|
|
||||||
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
|
||||||
return disabledRedirect
|
|
||||||
}
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
disRedirect := err != nil && strings.Contains(err.Error(), disabledRedirect.Error())
|
|
||||||
if err != nil && !disRedirect {
|
|
||||||
return respBytes, err
|
|
||||||
}
|
|
||||||
if !disRedirect {
|
|
||||||
defer resp.Body.Close()
|
|
||||||
} else {
|
|
||||||
resp.Body = nil
|
|
||||||
resp.ContentLength = 0
|
|
||||||
}
|
|
||||||
respBytes, err = EncodeResponse(resp)
|
|
||||||
return respBytes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将request转为bytes
|
|
||||||
func EncodeRequest(r *http.Request) ([]byte, error) {
|
|
||||||
raw := bytes.NewBuffer([]byte{})
|
|
||||||
reqBytes, err := httputil.DumpRequest(r, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
binary.Write(raw, binary.LittleEndian, bool(r.URL.Scheme == "https"))
|
|
||||||
binary.Write(raw, binary.LittleEndian, reqBytes)
|
|
||||||
return raw.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将字节转为request
|
|
||||||
func DecodeRequest(data []byte) (*http.Request, error) {
|
|
||||||
req, err := http.ReadRequest(bufio.NewReader(bytes.NewReader(data[1:])))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
str := strings.Split(req.Host, ":")
|
|
||||||
req.Host, err = getHost(str[0])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
scheme := "http"
|
|
||||||
if data[0] == 1 {
|
|
||||||
scheme = "https"
|
|
||||||
}
|
|
||||||
req.URL, _ = url.Parse(fmt.Sprintf("%s://%s%s", scheme, req.Host, req.RequestURI))
|
|
||||||
req.RequestURI = ""
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将response转为字节
|
|
||||||
func EncodeResponse(r *http.Response) ([]byte, error) {
|
|
||||||
respBytes, err := httputil.DumpResponse(r, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if config.Replace == 1 {
|
|
||||||
respBytes = replaceHost(respBytes)
|
|
||||||
}
|
|
||||||
return respBytes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将字节转为response
|
|
||||||
func DecodeResponse(data []byte) (*http.Response, error) {
|
|
||||||
resp, err := http.ReadResponse(bufio.NewReader(bytes.NewReader(data)), nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据host地址从配置是文件中查找对应目标
|
|
||||||
func getHost(str string) (string, error) {
|
|
||||||
for _, v := range config.SiteList {
|
|
||||||
if v.Host == str {
|
|
||||||
return v.Url + ":" + strconv.Itoa(v.Port), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", errors.New("没有找到解析的的host!")
|
|
||||||
}
|
|
||||||
|
|
||||||
//替换
|
|
||||||
func replaceHost(resp []byte) []byte {
|
|
||||||
str := string(resp)
|
|
||||||
for _, v := range config.SiteList {
|
|
||||||
str = strings.Replace(str, v.Url+":"+strconv.Itoa(v.Port), v.Host, -1)
|
|
||||||
str = strings.Replace(str, v.Url, v.Host, -1)
|
|
||||||
}
|
|
||||||
return []byte(str)
|
|
||||||
}
|
|
||||||
|
|
||||||
//copy
|
|
||||||
func relay(in, out net.Conn, compressType int, crypt, mux bool) {
|
|
||||||
switch compressType {
|
|
||||||
case COMPRESS_SNAPY_ENCODE:
|
|
||||||
copyBuffer(NewSnappyConn(in, crypt), out)
|
|
||||||
if mux {
|
|
||||||
out.Close()
|
|
||||||
NewSnappyConn(in, crypt).Write([]byte(IO_EOF))
|
|
||||||
}
|
|
||||||
case COMPRESS_SNAPY_DECODE:
|
|
||||||
copyBuffer(in, NewSnappyConn(out, crypt))
|
|
||||||
if mux {
|
|
||||||
in.Close()
|
|
||||||
}
|
|
||||||
case COMPRESS_NONE_ENCODE:
|
|
||||||
copyBuffer(NewCryptConn(in, crypt), out)
|
|
||||||
if mux {
|
|
||||||
out.Close()
|
|
||||||
NewCryptConn(in, crypt).Write([]byte(IO_EOF))
|
|
||||||
}
|
|
||||||
case COMPRESS_NONE_DECODE:
|
|
||||||
copyBuffer(in, NewCryptConn(out, crypt))
|
|
||||||
if mux {
|
|
||||||
in.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !mux {
|
|
||||||
in.Close()
|
|
||||||
out.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//判断压缩方式
|
|
||||||
func getCompressType(compress string) (int, int) {
|
|
||||||
switch compress {
|
|
||||||
case "":
|
|
||||||
return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE
|
|
||||||
case "snappy":
|
|
||||||
return COMPRESS_SNAPY_DECODE, COMPRESS_SNAPY_ENCODE
|
|
||||||
default:
|
|
||||||
log.Fatalln("数据压缩格式错误")
|
|
||||||
}
|
|
||||||
return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE
|
|
||||||
}
|
|
||||||
|
|
||||||
//简单的一个校验值
|
|
||||||
func getverifyval(vkey string) string {
|
|
||||||
//单客户端模式
|
|
||||||
if *verifyKey != "" {
|
|
||||||
return Md5(*verifyKey)
|
|
||||||
}
|
|
||||||
return Md5(vkey)
|
|
||||||
}
|
|
||||||
|
|
||||||
//验证
|
|
||||||
func verify(verifyKeyMd5 string) bool {
|
|
||||||
if *verifyKey != "" && getverifyval(*verifyKey) == verifyKeyMd5 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if *verifyKey == "" {
|
|
||||||
for k := range RunList {
|
|
||||||
if getverifyval(k) == verifyKeyMd5 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
//get key by host from x
|
|
||||||
func getKeyByHost(host string) (h *HostList, t *ServerConfig, err error) {
|
|
||||||
for _, v := range CsvDb.Hosts {
|
|
||||||
if strings.Contains(host, v.Host) {
|
|
||||||
h = v
|
|
||||||
t, err = CsvDb.GetTask(v.Vkey)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err = errors.New("未找到host对应的内网目标")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//通过host获取对应的ip地址
|
|
||||||
func Gethostbyname(hostname string) string {
|
|
||||||
if !DomainCheck(hostname) {
|
|
||||||
return hostname
|
|
||||||
}
|
|
||||||
ips, _ := net.LookupIP(hostname)
|
|
||||||
if ips != nil {
|
|
||||||
for _, v := range ips {
|
|
||||||
if v.To4() != nil {
|
|
||||||
return v.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
//检查是否是域名
|
|
||||||
func DomainCheck(domain string) bool {
|
|
||||||
var match bool
|
|
||||||
IsLine := "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}(/)"
|
|
||||||
NotLine := "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}"
|
|
||||||
match, _ = regexp.MatchString(IsLine, domain)
|
|
||||||
if !match {
|
|
||||||
match, _ = regexp.MatchString(NotLine, domain)
|
|
||||||
}
|
|
||||||
return match
|
|
||||||
}
|
|
||||||
|
|
||||||
//检查basic认证
|
|
||||||
func checkAuth(r *http.Request, user, passwd string) bool {
|
|
||||||
s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
|
|
||||||
if len(s) != 2 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := base64.StdEncoding.DecodeString(s[1])
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
pair := strings.SplitN(string(b), ":", 2)
|
|
||||||
if len(pair) != 2 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return pair[0] == user && pair[1] == passwd
|
|
||||||
}
|
|
||||||
|
|
||||||
//get bool by str
|
|
||||||
func GetBoolByStr(s string) bool {
|
|
||||||
switch s {
|
|
||||||
case "1", "true":
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
//get str by bool
|
|
||||||
func GetStrByBool(b bool) string {
|
|
||||||
if b {
|
|
||||||
return "1"
|
|
||||||
}
|
|
||||||
return "0"
|
|
||||||
}
|
|
||||||
func GetIntNoerrByStr(str string) int {
|
|
||||||
i, _ := strconv.Atoi(str)
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
var bufPool = sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
return make([]byte, 65535)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
// io.copy的优化版,读取buffer长度原为32*1024,与snappy不同,导致读取出的内容存在差异,不利于解密,特此修改
|
|
||||||
func copyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
|
|
||||||
//TODO 回收问题
|
|
||||||
buf := bufPool.Get().([]byte)
|
|
||||||
for {
|
|
||||||
nr, er := src.Read(buf)
|
|
||||||
if nr > 0 {
|
|
||||||
nw, ew := dst.Write(buf[0:nr])
|
|
||||||
if nw > 0 {
|
|
||||||
written += int64(nw)
|
|
||||||
}
|
|
||||||
if ew != nil {
|
|
||||||
err = ew
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if nr != nw {
|
|
||||||
err = io.ErrShortWrite
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if er != nil {
|
|
||||||
if er != io.EOF {
|
|
||||||
err = er
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return written, err
|
|
||||||
}
|
|
||||||
|
|
||||||
//连接重置 清空缓存区
|
|
||||||
func FlushConn(c net.Conn) {
|
|
||||||
c.SetReadDeadline(time.Now().Add(time.Second * 3))
|
|
||||||
buf := bufPool.Get().([]byte)
|
|
||||||
for {
|
|
||||||
if _, err := c.Read(buf); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.SetReadDeadline(time.Time{})
|
|
||||||
}
|
|
10
main.go
10
main.go
@ -1,10 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/cnlh/easyProxy/lib"
|
|
||||||
_ "github.com/cnlh/easyProxy/routers"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
lib.InitMode()
|
|
||||||
}
|
|
@ -1,11 +1,10 @@
|
|||||||
package lib
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"io/ioutil"
|
"github.com/cnlh/easyProxy/utils"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -34,9 +33,8 @@ type HostList struct {
|
|||||||
Target string //目标
|
Target string //目标
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCsv(bridge *Tunnel, runList map[string]interface{}) *Csv {
|
func NewCsv(runList map[string]interface{}) *Csv {
|
||||||
c := new(Csv)
|
c := new(Csv)
|
||||||
c.Bridge = bridge
|
|
||||||
c.RunList = runList
|
c.RunList = runList
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
@ -44,7 +42,6 @@ func NewCsv(bridge *Tunnel, runList map[string]interface{}) *Csv {
|
|||||||
type Csv struct {
|
type Csv struct {
|
||||||
Tasks []*ServerConfig
|
Tasks []*ServerConfig
|
||||||
Path string
|
Path string
|
||||||
Bridge *Tunnel
|
|
||||||
RunList map[string]interface{}
|
RunList map[string]interface{}
|
||||||
Hosts []*HostList //域名列表
|
Hosts []*HostList //域名列表
|
||||||
}
|
}
|
||||||
@ -72,8 +69,8 @@ func (s *Csv) StoreTasksToCsv() {
|
|||||||
task.P,
|
task.P,
|
||||||
task.Compress,
|
task.Compress,
|
||||||
strconv.Itoa(task.Start),
|
strconv.Itoa(task.Start),
|
||||||
GetStrByBool(task.Crypt),
|
utils.GetStrByBool(task.Crypt),
|
||||||
GetStrByBool(task.Mux),
|
utils.GetStrByBool(task.Mux),
|
||||||
strconv.Itoa(task.CompressEncode),
|
strconv.Itoa(task.CompressEncode),
|
||||||
strconv.Itoa(task.CompressDecode),
|
strconv.Itoa(task.CompressDecode),
|
||||||
}
|
}
|
||||||
@ -118,10 +115,10 @@ func (s *Csv) LoadTaskFromCsv() {
|
|||||||
P: item[5],
|
P: item[5],
|
||||||
Compress: item[6],
|
Compress: item[6],
|
||||||
Start: Start,
|
Start: Start,
|
||||||
Crypt: GetBoolByStr(item[8]),
|
Crypt: utils.GetBoolByStr(item[8]),
|
||||||
Mux: GetBoolByStr(item[9]),
|
Mux: utils.GetBoolByStr(item[9]),
|
||||||
CompressEncode: GetIntNoerrByStr(item[10]),
|
CompressEncode: utils.GetIntNoerrByStr(item[10]),
|
||||||
CompressDecode: GetIntNoerrByStr(item[11]),
|
CompressDecode: utils.GetIntNoerrByStr(item[11]),
|
||||||
}
|
}
|
||||||
tasks = append(tasks, post)
|
tasks = append(tasks, post)
|
||||||
}
|
}
|
||||||
@ -130,7 +127,7 @@ func (s *Csv) LoadTaskFromCsv() {
|
|||||||
|
|
||||||
func (s *Csv) StoreHostToCsv() {
|
func (s *Csv) StoreHostToCsv() {
|
||||||
// 创建文件
|
// 创建文件
|
||||||
csvFile, err := os.Create(s.Path + "hosts.csv")
|
csvFile, err := os.Create(beego.AppPath + "/conf/hosts.csv")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -186,38 +183,6 @@ func (s *Csv) LoadHostFromCsv() {
|
|||||||
s.Hosts = hosts
|
s.Hosts = hosts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Csv) GetServerConfig(start, length int, typeVal string) ([]*ServerConfig, int) {
|
|
||||||
list := make([]*ServerConfig, 0)
|
|
||||||
var cnt int
|
|
||||||
for _, v := range s.Tasks {
|
|
||||||
if v.Mode != typeVal {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cnt++
|
|
||||||
if start--; start < 0 {
|
|
||||||
if length--; length > 0 {
|
|
||||||
if _, ok := s.RunList[v.VerifyKey]; ok {
|
|
||||||
v.IsRun = 1
|
|
||||||
} else {
|
|
||||||
v.IsRun = 0
|
|
||||||
}
|
|
||||||
if s, ok := s.Bridge.signalList[getverifyval(v.VerifyKey)]; ok {
|
|
||||||
if s.Len() > 0 {
|
|
||||||
v.ClientStatus = 1
|
|
||||||
} else {
|
|
||||||
v.ClientStatus = 0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
v.ClientStatus = 0
|
|
||||||
}
|
|
||||||
list = append(list, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return list, cnt
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Csv) NewTask(t *ServerConfig) {
|
func (s *Csv) NewTask(t *ServerConfig) {
|
||||||
s.Tasks = append(s.Tasks, t)
|
s.Tasks = append(s.Tasks, t)
|
||||||
s.StoreTasksToCsv()
|
s.StoreTasksToCsv()
|
||||||
@ -232,7 +197,6 @@ func (s *Csv) UpdateTask(t *ServerConfig) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//TODO:待测试
|
|
||||||
return errors.New("不存在")
|
return errors.New("不存在")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,31 +261,3 @@ func (s *Csv) GetHostList(start, length int, vKey string) ([]*HostList, int) {
|
|||||||
}
|
}
|
||||||
return list, cnt
|
return list, cnt
|
||||||
}
|
}
|
||||||
|
|
||||||
type Site struct {
|
|
||||||
Host string
|
|
||||||
Url string
|
|
||||||
Port int
|
|
||||||
}
|
|
||||||
type Config struct {
|
|
||||||
SiteList []Site
|
|
||||||
Replace int
|
|
||||||
}
|
|
||||||
type JsonStruct struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewJsonStruct() *JsonStruct {
|
|
||||||
return &JsonStruct{}
|
|
||||||
}
|
|
||||||
func (jst *JsonStruct) Load(filename string) (Config, error) {
|
|
||||||
data, err := ioutil.ReadFile(filename)
|
|
||||||
config := Config{}
|
|
||||||
if err != nil {
|
|
||||||
return config, errors.New("配置文件打开错误")
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(data, &config)
|
|
||||||
if err != nil {
|
|
||||||
return config, errors.New("配置文件解析错误")
|
|
||||||
}
|
|
||||||
return config, nil
|
|
||||||
}
|
|
209
server/server.go
Normal file
209
server/server.go
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/cnlh/easyProxy/bridge"
|
||||||
|
"github.com/cnlh/easyProxy/utils"
|
||||||
|
"log"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Bridge *bridge.Tunnel
|
||||||
|
RunList map[string]interface{} //运行中的任务
|
||||||
|
CsvDb *Csv
|
||||||
|
VerifyKey string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RunList = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
//从csv文件中恢复任务
|
||||||
|
func InitFromCsv() {
|
||||||
|
for _, v := range CsvDb.Tasks {
|
||||||
|
if v.Start == 1 {
|
||||||
|
log.Println("启动模式:", v.Mode, "监听端口:", v.TcpPort, "客户端令牌:", v.VerifyKey)
|
||||||
|
AddTask(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//start a new server
|
||||||
|
func StartNewServer(bridgePort int, cnf *ServerConfig) {
|
||||||
|
Bridge = bridge.NewTunnel(bridgePort, RunList)
|
||||||
|
if err := Bridge.StartTunnel(); err != nil {
|
||||||
|
log.Fatalln("服务端开启失败", err)
|
||||||
|
}
|
||||||
|
if svr := NewMode(Bridge, cnf); svr != nil {
|
||||||
|
RunList[cnf.VerifyKey] = svr
|
||||||
|
err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
|
||||||
|
if err.Interface() != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Fatalln("启动模式不正确")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//new a server by mode name
|
||||||
|
func NewMode(Bridge *bridge.Tunnel, config *ServerConfig) interface{} {
|
||||||
|
switch config.Mode {
|
||||||
|
case "tunnelServer":
|
||||||
|
return NewTunnelModeServer(ProcessTunnel, Bridge, config)
|
||||||
|
case "socks5Server":
|
||||||
|
return NewSock5ModeServer(Bridge, config)
|
||||||
|
case "httpProxyServer":
|
||||||
|
return NewTunnelModeServer(ProcessHttp, Bridge, config)
|
||||||
|
case "udpServer":
|
||||||
|
return NewUdpModeServer(Bridge, config)
|
||||||
|
case "webServer":
|
||||||
|
InitCsvDb()
|
||||||
|
InitFromCsv()
|
||||||
|
//p, _ := beego.AppConfig.Int("hostPort")
|
||||||
|
t := &ServerConfig{
|
||||||
|
TcpPort: 8088,
|
||||||
|
Mode: "httpHostServer",
|
||||||
|
Target: "",
|
||||||
|
VerifyKey: "",
|
||||||
|
U: "",
|
||||||
|
P: "",
|
||||||
|
Compress: "",
|
||||||
|
Start: 1,
|
||||||
|
IsRun: 0,
|
||||||
|
ClientStatus: 0,
|
||||||
|
}
|
||||||
|
AddTask(t)
|
||||||
|
return NewWebServer(Bridge)
|
||||||
|
case "hostServer":
|
||||||
|
return NewHostServer(config)
|
||||||
|
case "httpHostServer":
|
||||||
|
return NewTunnelModeServer(ProcessHost, Bridge, config)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//stop server
|
||||||
|
func StopServer(cFlag string) error {
|
||||||
|
if v, ok := RunList[cFlag]; ok {
|
||||||
|
reflect.ValueOf(v).MethodByName("Close").Call(nil)
|
||||||
|
delete(RunList, cFlag)
|
||||||
|
if VerifyKey == "" { //多客户端模式关闭相关隧道
|
||||||
|
Bridge.DelClientSignal(cFlag)
|
||||||
|
Bridge.DelClientTunnel(cFlag)
|
||||||
|
}
|
||||||
|
if t, err := CsvDb.GetTask(cFlag); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
t.Start = 0
|
||||||
|
CsvDb.UpdateTask(t)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("未在运行中")
|
||||||
|
}
|
||||||
|
|
||||||
|
//add task
|
||||||
|
func AddTask(t *ServerConfig) error {
|
||||||
|
t.CompressDecode, t.CompressEncode = utils.GetCompressType(t.Compress)
|
||||||
|
if svr := NewMode(Bridge, t); svr != nil {
|
||||||
|
RunList[t.VerifyKey] = svr
|
||||||
|
go func() {
|
||||||
|
err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
|
||||||
|
if err.Interface() != nil {
|
||||||
|
log.Println("客户端", t.VerifyKey, "启动失败,错误:", err)
|
||||||
|
delete(RunList, t.VerifyKey)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
return errors.New("启动模式不正确")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//start task
|
||||||
|
func StartTask(vKey string) error {
|
||||||
|
if t, err := CsvDb.GetTask(vKey); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
AddTask(t)
|
||||||
|
t.Start = 1
|
||||||
|
CsvDb.UpdateTask(t)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//delete task
|
||||||
|
func DelTask(vKey string) error {
|
||||||
|
if err := StopServer(vKey); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return CsvDb.DelTask(vKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
//init csv from file
|
||||||
|
func InitCsvDb() *Csv {
|
||||||
|
var once sync.Once
|
||||||
|
once.Do(func() {
|
||||||
|
CsvDb = NewCsv(RunList)
|
||||||
|
CsvDb.Init()
|
||||||
|
})
|
||||||
|
return CsvDb
|
||||||
|
}
|
||||||
|
|
||||||
|
//get key by host from x
|
||||||
|
func GetKeyByHost(host string) (h *HostList, t *ServerConfig, err error) {
|
||||||
|
for _, v := range CsvDb.Hosts {
|
||||||
|
if strings.Contains(host, v.Host) {
|
||||||
|
h = v
|
||||||
|
t, err = CsvDb.GetTask(v.Vkey)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = errors.New("未找到host对应的内网目标")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//get task list by page num
|
||||||
|
func GetServerConfig(start, length int, typeVal string) ([]*ServerConfig, int) {
|
||||||
|
list := make([]*ServerConfig, 0)
|
||||||
|
var cnt int
|
||||||
|
for _, v := range CsvDb.Tasks {
|
||||||
|
if v.Mode != typeVal {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cnt++
|
||||||
|
if start--; start < 0 {
|
||||||
|
if length--; length > 0 {
|
||||||
|
if _, ok := RunList[v.VerifyKey]; ok {
|
||||||
|
v.IsRun = 1
|
||||||
|
} else {
|
||||||
|
v.IsRun = 0
|
||||||
|
}
|
||||||
|
if s, ok := Bridge.SignalList[getverifyval(v.VerifyKey)]; ok {
|
||||||
|
if s.Len() > 0 {
|
||||||
|
v.ClientStatus = 1
|
||||||
|
} else {
|
||||||
|
v.ClientStatus = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v.ClientStatus = 0
|
||||||
|
}
|
||||||
|
list = append(list, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return list, cnt
|
||||||
|
}
|
||||||
|
|
||||||
|
//get verify value
|
||||||
|
//when mode is webServer and vKey is not none
|
||||||
|
func getverifyval(vkey string) string {
|
||||||
|
if VerifyKey != "" {
|
||||||
|
return utils.Md5(VerifyKey)
|
||||||
|
}
|
||||||
|
return utils.Md5(vkey)
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
package lib
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/cnlh/easyProxy/bridge"
|
||||||
|
"github.com/cnlh/easyProxy/utils"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@ -44,7 +46,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Sock5ModeServer struct {
|
type Sock5ModeServer struct {
|
||||||
bridge *Tunnel
|
bridge *bridge.Tunnel
|
||||||
isVerify bool
|
isVerify bool
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
config *ServerConfig
|
config *ServerConfig
|
||||||
@ -105,7 +107,7 @@ func (s *Sock5ModeServer) sendReply(c net.Conn, rep uint8) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//do conn
|
//do conn
|
||||||
func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *Conn, err error) {
|
func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *utils.Conn, err error) {
|
||||||
addrType := make([]byte, 1)
|
addrType := make([]byte, 1)
|
||||||
c.Read(addrType)
|
c.Read(addrType)
|
||||||
var host string
|
var host string
|
||||||
@ -142,14 +144,14 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *Conn,
|
|||||||
s.sendReply(c, succeeded)
|
s.sendReply(c, succeeded)
|
||||||
var ltype string
|
var ltype string
|
||||||
if command == associateMethod {
|
if command == associateMethod {
|
||||||
ltype = CONN_UDP
|
ltype = utils.CONN_UDP
|
||||||
} else {
|
} else {
|
||||||
ltype = CONN_TCP
|
ltype = utils.CONN_TCP
|
||||||
}
|
}
|
||||||
_, err = client.WriteHost(ltype, addr)
|
_, err = client.WriteHost(ltype, addr)
|
||||||
var flag string
|
var flag string
|
||||||
if flag, err = client.ReadFlag(); err == nil {
|
if flag, err = client.ReadFlag(); err == nil {
|
||||||
if flag != CONN_SUCCESS {
|
if flag != utils.CONN_SUCCESS {
|
||||||
err = errors.New("conn failed")
|
err = errors.New("conn failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,8 +169,8 @@ func (s *Sock5ModeServer) handleConnect(c net.Conn) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c.Close()
|
c.Close()
|
||||||
} else {
|
} else {
|
||||||
go relay(proxyConn.conn, c, s.config.CompressEncode, s.config.Crypt, s.config.Mux)
|
go utils.Relay(proxyConn.Conn, c, s.config.CompressEncode, s.config.Crypt, s.config.Mux)
|
||||||
relay(c, proxyConn.conn, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
|
utils.Relay(c, proxyConn.Conn, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,13 +207,13 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c.Close()
|
c.Close()
|
||||||
} else {
|
} else {
|
||||||
go relay(proxyConn.conn, c, s.config.CompressEncode, s.config.Crypt, s.config.Mux)
|
go utils.Relay(proxyConn.Conn, c, s.config.CompressEncode, s.config.Crypt, s.config.Mux)
|
||||||
relay(c, proxyConn.conn, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
|
utils.Relay(c, proxyConn.Conn, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//new conn
|
//new conn
|
||||||
func (s *Sock5ModeServer) handleNewConn(c net.Conn) {
|
func (s *Sock5ModeServer) handleConn(c net.Conn) {
|
||||||
buf := make([]byte, 2)
|
buf := make([]byte, 2)
|
||||||
if _, err := io.ReadFull(c, buf); err != nil {
|
if _, err := io.ReadFull(c, buf); err != nil {
|
||||||
log.Println("negotiation err", err)
|
log.Println("negotiation err", err)
|
||||||
@ -285,6 +287,7 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error {
|
|||||||
|
|
||||||
//start
|
//start
|
||||||
func (s *Sock5ModeServer) Start() error {
|
func (s *Sock5ModeServer) Start() error {
|
||||||
|
var err error
|
||||||
s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.config.TcpPort))
|
s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.config.TcpPort))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -297,7 +300,7 @@ func (s *Sock5ModeServer) Start() error {
|
|||||||
}
|
}
|
||||||
log.Fatal("accept error: ", err)
|
log.Fatal("accept error: ", err)
|
||||||
}
|
}
|
||||||
go s.handleNewConn(conn)
|
go s.handleConn(conn)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -308,7 +311,7 @@ func (s *Sock5ModeServer) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//new
|
//new
|
||||||
func NewSock5ModeServer(bridge *Tunnel, cnf *ServerConfig) *Sock5ModeServer {
|
func NewSock5ModeServer(bridge *bridge.Tunnel, cnf *ServerConfig) *Sock5ModeServer {
|
||||||
s := new(Sock5ModeServer)
|
s := new(Sock5ModeServer)
|
||||||
s.bridge = bridge
|
s.bridge = bridge
|
||||||
s.config = cnf
|
s.config = cnf
|
191
server/tcp.go
Executable file
191
server/tcp.go
Executable file
@ -0,0 +1,191 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/astaxie/beego"
|
||||||
|
"github.com/cnlh/easyProxy/bridge"
|
||||||
|
"github.com/cnlh/easyProxy/utils"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type process func(c *utils.Conn, s *TunnelModeServer) error
|
||||||
|
|
||||||
|
type TunnelModeServer struct {
|
||||||
|
process process
|
||||||
|
bridge *bridge.Tunnel
|
||||||
|
config *ServerConfig
|
||||||
|
listener *net.TCPListener
|
||||||
|
}
|
||||||
|
|
||||||
|
//tcp|http|host
|
||||||
|
func NewTunnelModeServer(process process, bridge *bridge.Tunnel, cnf *ServerConfig) *TunnelModeServer {
|
||||||
|
s := new(TunnelModeServer)
|
||||||
|
s.bridge = bridge
|
||||||
|
s.process = process
|
||||||
|
s.config = cnf
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
//开始
|
||||||
|
func (s *TunnelModeServer) Start() error {
|
||||||
|
var err error
|
||||||
|
s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.config.TcpPort, ""})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
conn, err := s.listener.AcceptTCP()
|
||||||
|
if err != nil {
|
||||||
|
if strings.Contains(err.Error(), "use of closed network connection") {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Println(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go s.process(utils.NewConn(conn), s)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//权限认证
|
||||||
|
func (s *TunnelModeServer) auth(r *http.Request, c *utils.Conn, u, p string) error {
|
||||||
|
if u != "" && p != "" && !utils.CheckAuth(r, u, p) {
|
||||||
|
c.Write([]byte(utils.Unauthorized_BYTES))
|
||||||
|
c.Close()
|
||||||
|
return errors.New("401 Unauthorized")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//与客户端建立通道
|
||||||
|
func (s *TunnelModeServer) dealClient(c *utils.Conn, cnf *ServerConfig, addr string, method string, rb []byte) error {
|
||||||
|
link, err := s.bridge.GetTunnel(getverifyval(cnf.VerifyKey), cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, cnf.Mux)
|
||||||
|
defer func() {
|
||||||
|
if cnf.Mux {
|
||||||
|
s.bridge.ReturnTunnel(link, getverifyval(cnf.VerifyKey))
|
||||||
|
} else {
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
c.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := link.WriteHost(utils.CONN_TCP, addr); err != nil {
|
||||||
|
c.Close()
|
||||||
|
link.Close()
|
||||||
|
log.Println(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if flag, err := link.ReadFlag(); err == nil {
|
||||||
|
if flag == utils.CONN_SUCCESS {
|
||||||
|
if method == "CONNECT" {
|
||||||
|
fmt.Fprint(c, "HTTP/1.1 200 Connection established\r\n")
|
||||||
|
} else {
|
||||||
|
link.WriteTo(rb, cnf.CompressEncode, cnf.Crypt)
|
||||||
|
}
|
||||||
|
go utils.Relay(link.Conn, c.Conn, cnf.CompressEncode, cnf.Crypt, cnf.Mux)
|
||||||
|
utils.Relay(c.Conn, link.Conn, cnf.CompressDecode, cnf.Crypt, cnf.Mux)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//close
|
||||||
|
func (s *TunnelModeServer) Close() error {
|
||||||
|
return s.listener.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
//tcp隧道模式
|
||||||
|
func ProcessTunnel(c *utils.Conn, s *TunnelModeServer) error {
|
||||||
|
method, _, rb, err, r := c.GetHost()
|
||||||
|
if err == nil {
|
||||||
|
if err := s.auth(r, c, s.config.U, s.config.P); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.dealClient(c, s.config, s.config.Target, method, rb)
|
||||||
|
}
|
||||||
|
|
||||||
|
//http代理模式
|
||||||
|
func ProcessHttp(c *utils.Conn, s *TunnelModeServer) error {
|
||||||
|
method, addr, rb, err, r := c.GetHost()
|
||||||
|
if err != nil {
|
||||||
|
c.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.auth(r, c, s.config.U, s.config.P); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//TODO效率问题
|
||||||
|
return s.dealClient(c, s.config, addr, method, rb)
|
||||||
|
}
|
||||||
|
|
||||||
|
//多客户端域名代理
|
||||||
|
func ProcessHost(c *utils.Conn, s *TunnelModeServer) error {
|
||||||
|
method, addr, rb, err, r := c.GetHost()
|
||||||
|
if err != nil {
|
||||||
|
c.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
host, task, err := GetKeyByHost(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := s.auth(r, c, task.U, task.P); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
c.Close()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return s.dealClient(c, task, host.Target, method, rb)
|
||||||
|
}
|
||||||
|
|
||||||
|
//web管理方式
|
||||||
|
type WebServer struct {
|
||||||
|
bridge *bridge.Tunnel
|
||||||
|
}
|
||||||
|
|
||||||
|
//开始
|
||||||
|
func (s *WebServer) Start() {
|
||||||
|
beego.BConfig.WebConfig.Session.SessionOn = true
|
||||||
|
log.Println("web管理启动,访问端口为", beego.AppConfig.String("httpport"))
|
||||||
|
beego.SetViewsPath(beego.AppPath + "/web/views")
|
||||||
|
beego.SetStaticPath("/static/", "/web/static")
|
||||||
|
beego.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
//new
|
||||||
|
func NewWebServer(bridge *bridge.Tunnel) *WebServer {
|
||||||
|
s := new(WebServer)
|
||||||
|
s.bridge = bridge
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
//host
|
||||||
|
type HostServer struct {
|
||||||
|
config *ServerConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
//开始
|
||||||
|
func (s *HostServer) Start() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHostServer(cnf *ServerConfig) *HostServer {
|
||||||
|
s := new(HostServer)
|
||||||
|
s.config = cnf
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
//close
|
||||||
|
func (s *HostServer) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package lib
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/cnlh/easyProxy/bridge"
|
||||||
|
"github.com/cnlh/easyProxy/utils"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@ -8,22 +10,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type UdpModeServer struct {
|
type UdpModeServer struct {
|
||||||
bridge *Tunnel
|
bridge *bridge.Tunnel
|
||||||
listener *net.UDPConn
|
listener *net.UDPConn
|
||||||
udpMap map[string]*Conn
|
udpMap map[string]*utils.Conn
|
||||||
config *ServerConfig
|
config *ServerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUdpModeServer(bridge *Tunnel, cnf *ServerConfig) *UdpModeServer {
|
func NewUdpModeServer(bridge *bridge.Tunnel, cnf *ServerConfig) *UdpModeServer {
|
||||||
s := new(UdpModeServer)
|
s := new(UdpModeServer)
|
||||||
s.bridge = bridge
|
s.bridge = bridge
|
||||||
s.udpMap = make(map[string]*Conn)
|
s.udpMap = make(map[string]*utils.Conn)
|
||||||
s.config = cnf
|
s.config = cnf
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
//开始
|
//开始
|
||||||
func (s *UdpModeServer) Start() error {
|
func (s *UdpModeServer) Start() error {
|
||||||
|
var err error
|
||||||
s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.config.TcpPort, ""})
|
s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.config.TcpPort, ""})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -49,7 +52,7 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, err := conn.WriteHost(CONN_UDP, s.config.Target); err != nil {
|
if _, err := conn.WriteHost(utils.CONN_UDP, s.config.Target); err != nil {
|
||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -61,7 +64,7 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
|
|||||||
conn.Close()
|
conn.Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if flag == CONN_SUCCESS {
|
if flag == utils.CONN_SUCCESS {
|
||||||
conn.WriteTo(data, s.config.CompressEncode, s.config.Crypt)
|
conn.WriteTo(data, s.config.CompressEncode, s.config.Crypt)
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
//conn.conn.SetReadDeadline(time.Now().Add(time.Duration(time.Second * 3)))
|
//conn.conn.SetReadDeadline(time.Now().Add(time.Duration(time.Second * 3)))
|
||||||
@ -71,7 +74,7 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.listener.WriteToUDP(buf[:n], addr)
|
s.listener.WriteToUDP(buf[:n], addr)
|
||||||
conn.WriteTo([]byte(IO_EOF), s.config.CompressEncode, s.config.Crypt)
|
conn.WriteTo([]byte(utils.IO_EOF), s.config.CompressEncode, s.config.Crypt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package lib
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
@ -16,6 +16,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const cryptKey = "1234567812345678"
|
||||||
|
|
||||||
type CryptConn struct {
|
type CryptConn struct {
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
crypt bool
|
crypt bool
|
||||||
@ -126,13 +128,13 @@ func (s *SnappyConn) Read(b []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
conn net.Conn
|
Conn net.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
//new conn
|
//new conn
|
||||||
func NewConn(conn net.Conn) *Conn {
|
func NewConn(conn net.Conn) *Conn {
|
||||||
c := new(Conn)
|
c := new(Conn)
|
||||||
c.conn = conn
|
c.Conn = conn
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,6 +162,7 @@ func (s *Conn) GetLen() (int, error) {
|
|||||||
//写入长度+内容 粘包
|
//写入长度+内容 粘包
|
||||||
func (s *Conn) WriteLen(buf []byte) (int, error) {
|
func (s *Conn) WriteLen(buf []byte) (int, error) {
|
||||||
var b []byte
|
var b []byte
|
||||||
|
var err error
|
||||||
if b, err = GetLenBytes(buf); err != nil {
|
if b, err = GetLenBytes(buf); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -209,7 +212,7 @@ func (s *Conn) WriteHost(ltype string, host string) (int, error) {
|
|||||||
|
|
||||||
//设置连接为长连接
|
//设置连接为长连接
|
||||||
func (s *Conn) SetAlive() {
|
func (s *Conn) SetAlive() {
|
||||||
conn := s.conn.(*net.TCPConn)
|
conn := s.Conn.(*net.TCPConn)
|
||||||
conn.SetReadDeadline(time.Time{})
|
conn.SetReadDeadline(time.Time{})
|
||||||
conn.SetKeepAlive(true)
|
conn.SetKeepAlive(true)
|
||||||
conn.SetKeepAlivePeriod(time.Duration(2 * time.Second))
|
conn.SetKeepAlivePeriod(time.Duration(2 * time.Second))
|
||||||
@ -247,17 +250,17 @@ func (s *Conn) GetHost() (method, address string, rb []byte, err error, r *http.
|
|||||||
//单独读(加密|压缩)
|
//单独读(加密|压缩)
|
||||||
func (s *Conn) ReadFrom(b []byte, compress int, crypt bool) (int, error) {
|
func (s *Conn) ReadFrom(b []byte, compress int, crypt bool) (int, error) {
|
||||||
if COMPRESS_SNAPY_DECODE == compress {
|
if COMPRESS_SNAPY_DECODE == compress {
|
||||||
return NewSnappyConn(s.conn, crypt).Read(b)
|
return NewSnappyConn(s.Conn, crypt).Read(b)
|
||||||
}
|
}
|
||||||
return NewCryptConn(s.conn, crypt).Read(b)
|
return NewCryptConn(s.Conn, crypt).Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
//单独写(加密|压缩)
|
//单独写(加密|压缩)
|
||||||
func (s *Conn) WriteTo(b []byte, compress int, crypt bool) (n int, err error) {
|
func (s *Conn) WriteTo(b []byte, compress int, crypt bool) (n int, err error) {
|
||||||
if COMPRESS_SNAPY_ENCODE == compress {
|
if COMPRESS_SNAPY_ENCODE == compress {
|
||||||
return NewSnappyConn(s.conn, crypt).Write(b)
|
return NewSnappyConn(s.Conn, crypt).Write(b)
|
||||||
}
|
}
|
||||||
return NewCryptConn(s.conn, crypt).Write(b)
|
return NewCryptConn(s.Conn, crypt).Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
//写压缩方式,加密
|
//写压缩方式,加密
|
||||||
@ -268,7 +271,6 @@ func (s *Conn) WriteConnInfo(en, de int, crypt, mux bool) {
|
|||||||
//获取压缩方式,是否加密
|
//获取压缩方式,是否加密
|
||||||
func (s *Conn) GetConnInfoFromConn() (en, de int, crypt, mux bool) {
|
func (s *Conn) GetConnInfoFromConn() (en, de int, crypt, mux bool) {
|
||||||
buf, err := s.ReadLen(4)
|
buf, err := s.ReadLen(4)
|
||||||
//TODO:错误处理
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -281,51 +283,51 @@ func (s *Conn) GetConnInfoFromConn() (en, de int, crypt, mux bool) {
|
|||||||
|
|
||||||
//close
|
//close
|
||||||
func (s *Conn) Close() error {
|
func (s *Conn) Close() error {
|
||||||
return s.conn.Close()
|
return s.Conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
//write
|
//write
|
||||||
func (s *Conn) Write(b []byte) (int, error) {
|
func (s *Conn) Write(b []byte) (int, error) {
|
||||||
return s.conn.Write(b)
|
return s.Conn.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
//read
|
//read
|
||||||
func (s *Conn) Read(b []byte) (int, error) {
|
func (s *Conn) Read(b []byte) (int, error) {
|
||||||
return s.conn.Read(b)
|
return s.Conn.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
//write error
|
//write error
|
||||||
func (s *Conn) wError() (int, error) {
|
func (s *Conn) WriteError() (int, error) {
|
||||||
return s.Write([]byte(RES_MSG))
|
return s.Write([]byte(RES_MSG))
|
||||||
}
|
}
|
||||||
|
|
||||||
//write sign flag
|
//write sign flag
|
||||||
func (s *Conn) wSign() (int, error) {
|
func (s *Conn) WriteSign() (int, error) {
|
||||||
return s.Write([]byte(RES_SIGN))
|
return s.Write([]byte(RES_SIGN))
|
||||||
}
|
}
|
||||||
|
|
||||||
//write main
|
//write main
|
||||||
func (s *Conn) wMain() (int, error) {
|
func (s *Conn) WriteMain() (int, error) {
|
||||||
return s.Write([]byte(WORK_MAIN))
|
return s.Write([]byte(WORK_MAIN))
|
||||||
}
|
}
|
||||||
|
|
||||||
//write chan
|
//write chan
|
||||||
func (s *Conn) wChan() (int, error) {
|
func (s *Conn) WriteChan() (int, error) {
|
||||||
return s.Write([]byte(WORK_CHAN))
|
return s.Write([]byte(WORK_CHAN))
|
||||||
}
|
}
|
||||||
|
|
||||||
//write test
|
//write test
|
||||||
func (s *Conn) wTest() (int, error) {
|
func (s *Conn) WriteTest() (int, error) {
|
||||||
return s.Write([]byte(TEST_FLAG))
|
return s.Write([]byte(TEST_FLAG))
|
||||||
}
|
}
|
||||||
|
|
||||||
//write test
|
//write test
|
||||||
func (s *Conn) wSuccess() (int, error) {
|
func (s *Conn) WriteSuccess() (int, error) {
|
||||||
return s.Write([]byte(CONN_SUCCESS))
|
return s.Write([]byte(CONN_SUCCESS))
|
||||||
}
|
}
|
||||||
|
|
||||||
//write test
|
//write test
|
||||||
func (s *Conn) wFail() (int, error) {
|
func (s *Conn) WriteFail() (int, error) {
|
||||||
return s.Write([]byte(CONN_ERROR))
|
return s.Write([]byte(CONN_ERROR))
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package lib
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -6,7 +6,7 @@ import (
|
|||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"github.com/pkg/errors"
|
"errors"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
204
utils/util.go
Executable file
204
utils/util.go
Executable file
@ -0,0 +1,204 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
COMPRESS_NONE_ENCODE = iota
|
||||||
|
COMPRESS_NONE_DECODE
|
||||||
|
COMPRESS_SNAPY_ENCODE
|
||||||
|
COMPRESS_SNAPY_DECODE
|
||||||
|
VERIFY_EER = "vkey"
|
||||||
|
WORK_MAIN = "main"
|
||||||
|
WORK_CHAN = "chan"
|
||||||
|
RES_SIGN = "sign"
|
||||||
|
RES_MSG = "msg0"
|
||||||
|
CONN_SUCCESS = "sucs"
|
||||||
|
CONN_ERROR = "fail"
|
||||||
|
TEST_FLAG = "tst"
|
||||||
|
CONN_TCP = "tcp"
|
||||||
|
CONN_UDP = "udp"
|
||||||
|
Unauthorized_BYTES = `HTTP/1.1 401 Unauthorized
|
||||||
|
Content-Type: text/plain; charset=utf-8
|
||||||
|
WWW-Authenticate: Basic realm="easyProxy"
|
||||||
|
|
||||||
|
401 Unauthorized`
|
||||||
|
IO_EOF = "PROXYEOF"
|
||||||
|
)
|
||||||
|
|
||||||
|
//copy
|
||||||
|
func Relay(in, out net.Conn, compressType int, crypt, mux bool) {
|
||||||
|
switch compressType {
|
||||||
|
case COMPRESS_SNAPY_ENCODE:
|
||||||
|
copyBuffer(NewSnappyConn(in, crypt), out)
|
||||||
|
if mux {
|
||||||
|
out.Close()
|
||||||
|
NewSnappyConn(in, crypt).Write([]byte(IO_EOF))
|
||||||
|
}
|
||||||
|
case COMPRESS_SNAPY_DECODE:
|
||||||
|
copyBuffer(in, NewSnappyConn(out, crypt))
|
||||||
|
if mux {
|
||||||
|
in.Close()
|
||||||
|
}
|
||||||
|
case COMPRESS_NONE_ENCODE:
|
||||||
|
copyBuffer(NewCryptConn(in, crypt), out)
|
||||||
|
if mux {
|
||||||
|
out.Close()
|
||||||
|
NewCryptConn(in, crypt).Write([]byte(IO_EOF))
|
||||||
|
}
|
||||||
|
case COMPRESS_NONE_DECODE:
|
||||||
|
copyBuffer(in, NewCryptConn(out, crypt))
|
||||||
|
if mux {
|
||||||
|
in.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !mux {
|
||||||
|
in.Close()
|
||||||
|
out.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断压缩方式
|
||||||
|
func GetCompressType(compress string) (int, int) {
|
||||||
|
switch compress {
|
||||||
|
case "":
|
||||||
|
return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE
|
||||||
|
case "snappy":
|
||||||
|
return COMPRESS_SNAPY_DECODE, COMPRESS_SNAPY_ENCODE
|
||||||
|
default:
|
||||||
|
log.Fatalln("数据压缩格式错误")
|
||||||
|
}
|
||||||
|
return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE
|
||||||
|
}
|
||||||
|
|
||||||
|
//通过host获取对应的ip地址
|
||||||
|
func Gethostbyname(hostname string) string {
|
||||||
|
if !DomainCheck(hostname) {
|
||||||
|
return hostname
|
||||||
|
}
|
||||||
|
ips, _ := net.LookupIP(hostname)
|
||||||
|
if ips != nil {
|
||||||
|
for _, v := range ips {
|
||||||
|
if v.To4() != nil {
|
||||||
|
return v.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
//检查是否是域名
|
||||||
|
func DomainCheck(domain string) bool {
|
||||||
|
var match bool
|
||||||
|
IsLine := "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}(/)"
|
||||||
|
NotLine := "^((http://)|(https://))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}"
|
||||||
|
match, _ = regexp.MatchString(IsLine, domain)
|
||||||
|
if !match {
|
||||||
|
match, _ = regexp.MatchString(NotLine, domain)
|
||||||
|
}
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
|
||||||
|
//检查basic认证
|
||||||
|
func CheckAuth(r *http.Request, user, passwd string) bool {
|
||||||
|
s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
|
||||||
|
if len(s) != 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := base64.StdEncoding.DecodeString(s[1])
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
pair := strings.SplitN(string(b), ":", 2)
|
||||||
|
if len(pair) != 2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return pair[0] == user && pair[1] == passwd
|
||||||
|
}
|
||||||
|
|
||||||
|
//get bool by str
|
||||||
|
func GetBoolByStr(s string) bool {
|
||||||
|
switch s {
|
||||||
|
case "1", "true":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//get str by bool
|
||||||
|
func GetStrByBool(b bool) string {
|
||||||
|
if b {
|
||||||
|
return "1"
|
||||||
|
}
|
||||||
|
return "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
//int
|
||||||
|
func GetIntNoerrByStr(str string) int {
|
||||||
|
i, _ := strconv.Atoi(str)
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
var bufPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return make([]byte, 65535)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// io.copy的优化版,读取buffer长度原为32*1024,与snappy不同,导致读取出的内容存在差异,不利于解密,特此修改
|
||||||
|
func copyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
|
||||||
|
//TODO 回收问题
|
||||||
|
buf := bufPool.Get().([]byte)
|
||||||
|
for {
|
||||||
|
nr, er := src.Read(buf)
|
||||||
|
if nr > 0 {
|
||||||
|
nw, ew := dst.Write(buf[0:nr])
|
||||||
|
if nw > 0 {
|
||||||
|
written += int64(nw)
|
||||||
|
}
|
||||||
|
if ew != nil {
|
||||||
|
err = ew
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if nr != nw {
|
||||||
|
err = io.ErrShortWrite
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if er != nil {
|
||||||
|
if er != io.EOF {
|
||||||
|
err = er
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return written, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//连接重置 清空缓存区
|
||||||
|
func FlushConn(c net.Conn) {
|
||||||
|
c.SetReadDeadline(time.Now().Add(time.Second * 3))
|
||||||
|
buf := bufPool.Get().([]byte)
|
||||||
|
for {
|
||||||
|
if _, err := c.Read(buf); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.SetReadDeadline(time.Time{})
|
||||||
|
}
|
||||||
|
|
||||||
|
//简单的一个校验值
|
||||||
|
func Getverifyval(vkey string) string {
|
||||||
|
return Md5(vkey)
|
||||||
|
}
|
@ -2,7 +2,8 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/cnlh/easyProxy/lib"
|
"github.com/cnlh/easyProxy/server"
|
||||||
|
"github.com/cnlh/easyProxy/utils"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -33,8 +34,8 @@ func (s *BaseController) display(tpl ...string) {
|
|||||||
}
|
}
|
||||||
s.Data["menu"] = s.actionName
|
s.Data["menu"] = s.actionName
|
||||||
ip := s.Ctx.Request.Host
|
ip := s.Ctx.Request.Host
|
||||||
s.Data["ip"] = lib.Gethostbyname(ip[0:strings.LastIndex(ip, ":")])
|
s.Data["ip"] = utils.Gethostbyname(ip[0:strings.LastIndex(ip, ":")])
|
||||||
s.Data["p"] = *lib.TcpPort
|
s.Data["p"] = server.Bridge.TunnelPort
|
||||||
s.Data["proxyPort"] = beego.AppConfig.String("hostPort")
|
s.Data["proxyPort"] = beego.AppConfig.String("hostPort")
|
||||||
s.Layout = "public/layout.html"
|
s.Layout = "public/layout.html"
|
||||||
s.TplName = tplname
|
s.TplName = tplname
|
@ -1,7 +1,8 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/cnlh/easyProxy/lib"
|
"github.com/cnlh/easyProxy/server"
|
||||||
|
"github.com/cnlh/easyProxy/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IndexController struct {
|
type IndexController struct {
|
||||||
@ -27,7 +28,7 @@ func (s *IndexController) Udp() {
|
|||||||
|
|
||||||
func (s *IndexController) Socks5() {
|
func (s *IndexController) Socks5() {
|
||||||
s.SetInfo("socks5管理")
|
s.SetInfo("socks5管理")
|
||||||
s.SetType("sock5Server")
|
s.SetType("socks5Server")
|
||||||
s.display("index/list")
|
s.display("index/list")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +47,7 @@ func (s *IndexController) Host() {
|
|||||||
func (s *IndexController) GetServerConfig() {
|
func (s *IndexController) GetServerConfig() {
|
||||||
start, length := s.GetAjaxParams()
|
start, length := s.GetAjaxParams()
|
||||||
taskType := s.GetString("type")
|
taskType := s.GetString("type")
|
||||||
list, cnt := lib.CsvDb.GetServerConfig(start, length, taskType)
|
list, cnt := server.GetServerConfig(start, length, taskType)
|
||||||
s.AjaxTable(list, cnt, cnt)
|
s.AjaxTable(list, cnt, cnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,20 +57,20 @@ func (s *IndexController) Add() {
|
|||||||
s.SetInfo("新增")
|
s.SetInfo("新增")
|
||||||
s.display()
|
s.display()
|
||||||
} else {
|
} else {
|
||||||
t := &lib.ServerConfig{
|
t := &server.ServerConfig{
|
||||||
TcpPort: s.GetIntNoErr("port"),
|
TcpPort: s.GetIntNoErr("port"),
|
||||||
Mode: s.GetString("type"),
|
Mode: s.GetString("type"),
|
||||||
Target: s.GetString("target"),
|
Target: s.GetString("target"),
|
||||||
VerifyKey: lib.GetRandomString(16),
|
VerifyKey: utils.GetRandomString(16),
|
||||||
U: s.GetString("u"),
|
U: s.GetString("u"),
|
||||||
P: s.GetString("p"),
|
P: s.GetString("p"),
|
||||||
Compress: s.GetString("compress"),
|
Compress: s.GetString("compress"),
|
||||||
Crypt: lib.GetBoolByStr(s.GetString("crypt")),
|
Crypt: utils.GetBoolByStr(s.GetString("crypt")),
|
||||||
Mux: lib.GetBoolByStr(s.GetString("mux")),
|
Mux: utils.GetBoolByStr(s.GetString("mux")),
|
||||||
IsRun: 0,
|
IsRun: 0,
|
||||||
}
|
}
|
||||||
lib.CsvDb.NewTask(t)
|
server.CsvDb.NewTask(t)
|
||||||
if err := lib.AddTask(t); err != nil {
|
if err := server.AddTask(t); err != nil {
|
||||||
s.AjaxErr(err.Error())
|
s.AjaxErr(err.Error())
|
||||||
} else {
|
} else {
|
||||||
s.AjaxOk("添加成功")
|
s.AjaxOk("添加成功")
|
||||||
@ -80,7 +81,7 @@ func (s *IndexController) Add() {
|
|||||||
func (s *IndexController) Edit() {
|
func (s *IndexController) Edit() {
|
||||||
if s.Ctx.Request.Method == "GET" {
|
if s.Ctx.Request.Method == "GET" {
|
||||||
vKey := s.GetString("vKey")
|
vKey := s.GetString("vKey")
|
||||||
if t, err := lib.CsvDb.GetTask(vKey); err != nil {
|
if t, err := server.CsvDb.GetTask(vKey); err != nil {
|
||||||
s.error()
|
s.error()
|
||||||
} else {
|
} else {
|
||||||
s.Data["t"] = t
|
s.Data["t"] = t
|
||||||
@ -89,7 +90,7 @@ func (s *IndexController) Edit() {
|
|||||||
s.display()
|
s.display()
|
||||||
} else {
|
} else {
|
||||||
vKey := s.GetString("vKey")
|
vKey := s.GetString("vKey")
|
||||||
if t, err := lib.CsvDb.GetTask(vKey); err != nil {
|
if t, err := server.CsvDb.GetTask(vKey); err != nil {
|
||||||
s.error()
|
s.error()
|
||||||
} else {
|
} else {
|
||||||
t.TcpPort = s.GetIntNoErr("port")
|
t.TcpPort = s.GetIntNoErr("port")
|
||||||
@ -98,11 +99,11 @@ func (s *IndexController) Edit() {
|
|||||||
t.U = s.GetString("u")
|
t.U = s.GetString("u")
|
||||||
t.P = s.GetString("p")
|
t.P = s.GetString("p")
|
||||||
t.Compress = s.GetString("compress")
|
t.Compress = s.GetString("compress")
|
||||||
t.Crypt = lib.GetBoolByStr(s.GetString("crypt"))
|
t.Crypt = utils.GetBoolByStr(s.GetString("crypt"))
|
||||||
t.Mux = lib.GetBoolByStr(s.GetString("mux"))
|
t.Mux = utils.GetBoolByStr(s.GetString("mux"))
|
||||||
lib.CsvDb.UpdateTask(t)
|
server.CsvDb.UpdateTask(t)
|
||||||
lib.StopServer(t.VerifyKey)
|
server.StopServer(t.VerifyKey)
|
||||||
lib.StartTask(t.VerifyKey)
|
server.StartTask(t.VerifyKey)
|
||||||
}
|
}
|
||||||
s.AjaxOk("修改成功")
|
s.AjaxOk("修改成功")
|
||||||
}
|
}
|
||||||
@ -110,14 +111,14 @@ func (s *IndexController) Edit() {
|
|||||||
|
|
||||||
func (s *IndexController) Stop() {
|
func (s *IndexController) Stop() {
|
||||||
vKey := s.GetString("vKey")
|
vKey := s.GetString("vKey")
|
||||||
if err := lib.StopServer(vKey); err != nil {
|
if err := server.StopServer(vKey); err != nil {
|
||||||
s.AjaxErr("停止失败")
|
s.AjaxErr("停止失败")
|
||||||
}
|
}
|
||||||
s.AjaxOk("停止成功")
|
s.AjaxOk("停止成功")
|
||||||
}
|
}
|
||||||
func (s *IndexController) Del() {
|
func (s *IndexController) Del() {
|
||||||
vKey := s.GetString("vKey")
|
vKey := s.GetString("vKey")
|
||||||
if err := lib.DelTask(vKey); err != nil {
|
if err := server.DelTask(vKey); err != nil {
|
||||||
s.AjaxErr("删除失败")
|
s.AjaxErr("删除失败")
|
||||||
}
|
}
|
||||||
s.AjaxOk("删除成功")
|
s.AjaxOk("删除成功")
|
||||||
@ -125,7 +126,7 @@ func (s *IndexController) Del() {
|
|||||||
|
|
||||||
func (s *IndexController) Start() {
|
func (s *IndexController) Start() {
|
||||||
vKey := s.GetString("vKey")
|
vKey := s.GetString("vKey")
|
||||||
if err := lib.StartTask(vKey); err != nil {
|
if err := server.StartTask(vKey); err != nil {
|
||||||
s.AjaxErr("开启失败")
|
s.AjaxErr("开启失败")
|
||||||
}
|
}
|
||||||
s.AjaxOk("开启成功")
|
s.AjaxOk("开启成功")
|
||||||
@ -139,14 +140,14 @@ func (s *IndexController) HostList() {
|
|||||||
} else {
|
} else {
|
||||||
start, length := s.GetAjaxParams()
|
start, length := s.GetAjaxParams()
|
||||||
vkey := s.GetString("vkey")
|
vkey := s.GetString("vkey")
|
||||||
list, cnt := lib.CsvDb.GetHostList(start, length, vkey)
|
list, cnt := server.CsvDb.GetHostList(start, length, vkey)
|
||||||
s.AjaxTable(list, cnt, cnt)
|
s.AjaxTable(list, cnt, cnt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *IndexController) DelHost() {
|
func (s *IndexController) DelHost() {
|
||||||
host := s.GetString("host")
|
host := s.GetString("host")
|
||||||
if err := lib.CsvDb.DelHost(host); err != nil {
|
if err := server.CsvDb.DelHost(host); err != nil {
|
||||||
s.AjaxErr("删除失败")
|
s.AjaxErr("删除失败")
|
||||||
}
|
}
|
||||||
s.AjaxOk("删除成功")
|
s.AjaxOk("删除成功")
|
||||||
@ -158,12 +159,12 @@ func (s *IndexController) AddHost() {
|
|||||||
s.SetInfo("新增")
|
s.SetInfo("新增")
|
||||||
s.display("index/hadd")
|
s.display("index/hadd")
|
||||||
} else {
|
} else {
|
||||||
h := &lib.HostList{
|
h := &server.HostList{
|
||||||
Vkey: s.GetString("vkey"),
|
Vkey: s.GetString("vkey"),
|
||||||
Host: s.GetString("host"),
|
Host: s.GetString("host"),
|
||||||
Target: s.GetString("target"),
|
Target: s.GetString("target"),
|
||||||
}
|
}
|
||||||
lib.CsvDb.NewHost(h)
|
server.CsvDb.NewHost(h)
|
||||||
s.AjaxOk("添加成功")
|
s.AjaxOk("添加成功")
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,7 +2,7 @@ package routers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
"github.com/cnlh/easyProxy/controllers"
|
"github.com/cnlh/easyProxy/web/controllers"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 434 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@ -17,7 +17,7 @@
|
|||||||
<select class="form-control" name="type" id="type">
|
<select class="form-control" name="type" id="type">
|
||||||
<option {{if eq "tunnelServer" .type}}selected{{end}} value="tunnelServer">tcp隧道</option>
|
<option {{if eq "tunnelServer" .type}}selected{{end}} value="tunnelServer">tcp隧道</option>
|
||||||
<option {{if eq "udpServer" .type}}selected{{end}} value="udpServer">udp隧道</option>
|
<option {{if eq "udpServer" .type}}selected{{end}} value="udpServer">udp隧道</option>
|
||||||
<option {{if eq "sock5Server" .type}}selected{{end}} value="sock5Server">socks5代理</option>
|
<option {{if eq "socks5Server" .type}}selected{{end}} value="socks5Server">socks5代理</option>
|
||||||
<option {{if eq "httpProxyServer" .type}}selected{{end}} value="httpProxyServer">http代理
|
<option {{if eq "httpProxyServer" .type}}selected{{end}} value="httpProxyServer">http代理
|
||||||
<option {{if eq "hostServer" .type}}selected{{end}} value="hostServer">host客户端</option>
|
<option {{if eq "hostServer" .type}}selected{{end}} value="hostServer">host客户端</option>
|
||||||
</select>
|
</select>
|
||||||
@ -75,7 +75,7 @@
|
|||||||
arr["all"] = ["type", "port", "compress", "u", "p", "target"]
|
arr["all"] = ["type", "port", "compress", "u", "p", "target"]
|
||||||
arr["tunnelServer"] = ["type", "port", "target", "compress", "u", "p", "tcp隧道模式,提供一条tcp隧道,适用于ssh、远程桌面等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,访问公网服务器的设定端口,则相当于访问内网目标地址的目标端口"]
|
arr["tunnelServer"] = ["type", "port", "target", "compress", "u", "p", "tcp隧道模式,提供一条tcp隧道,适用于ssh、远程桌面等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,访问公网服务器的设定端口,则相当于访问内网目标地址的目标端口"]
|
||||||
arr["udpServer"] = ["type", "port", "target", "compress", "udp隧道模式,提供一条udp隧道,适用于dns、内网dns访问等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,访问公网服务器的设定端口,则相当于访问内网目标地址的udp目标端口"]
|
arr["udpServer"] = ["type", "port", "target", "compress", "udp隧道模式,提供一条udp隧道,适用于dns、内网dns访问等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,访问公网服务器的设定端口,则相当于访问内网目标地址的udp目标端口"]
|
||||||
arr["sock5Server"] = ["type", "port", "compress", "u", "p", "socks5代理模式,内网socks5代理,配合proxifer,可如同使用vpn一样访问内网设备或资源,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置socks5代理,即访问内网设备或者资源 "]
|
arr["socks5Server"] = ["type", "port", "compress", "u", "p", "socks5代理模式,内网socks5代理,配合proxifer,可如同使用vpn一样访问内网设备或资源,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置socks5代理,即访问内网设备或者资源 "]
|
||||||
arr["httpProxyServer"] = ["type", "port", "compress", "u", "p", " http代理模式,内网http代理,可访问内网网站,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置http代理,即访问内网站点"]
|
arr["httpProxyServer"] = ["type", "port", "compress", "u", "p", " http代理模式,内网http代理,可访问内网网站,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置http代理,即访问内网站点"]
|
||||||
arr["hostServer"] = ["type", "compress", "u", "p", "域名分发模式,使用域名代理内网服务,适用于小程序开发、公众号开发、站点演示等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,使用nginx将请求反向代理到本程序,再进行域名配置,即可解析"]
|
arr["hostServer"] = ["type", "compress", "u", "p", "域名分发模式,使用域名代理内网服务,适用于小程序开发、公众号开发、站点演示等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,使用nginx将请求反向代理到本程序,再进行域名配置,即可解析"]
|
||||||
|
|
@ -10,7 +10,7 @@
|
|||||||
<select class="form-control" name="type" id="type">
|
<select class="form-control" name="type" id="type">
|
||||||
<option {{if eq "tunnelServer" .t.Mode}}selected{{end}} value="tunnelServer">tcp隧道</option>
|
<option {{if eq "tunnelServer" .t.Mode}}selected{{end}} value="tunnelServer">tcp隧道</option>
|
||||||
<option {{if eq "udpServer" .t.Mode}}selected{{end}} value="udpServer">udp隧道</option>
|
<option {{if eq "udpServer" .t.Mode}}selected{{end}} value="udpServer">udp隧道</option>
|
||||||
<option {{if eq "sock5Server" .t.Mode}}selected{{end}} value="sock5Server">socks5代理</option>
|
<option {{if eq "socks5Server" .t.Mode}}selected{{end}} value="socks5Server">socks5代理</option>
|
||||||
<option {{if eq "httpProxyServer" .t.Mode}}selected{{end}} value="httpProxyServer">http代理
|
<option {{if eq "httpProxyServer" .t.Mode}}selected{{end}} value="httpProxyServer">http代理
|
||||||
<option {{if eq "hostServer" .t.Mode}}selected{{end}} value="hostServer">host客户端</option>
|
<option {{if eq "hostServer" .t.Mode}}selected{{end}} value="hostServer">host客户端</option>
|
||||||
</select>
|
</select>
|
||||||
@ -72,7 +72,7 @@
|
|||||||
arr["all"] = ["type", "port", "compress", "u", "p", "target"]
|
arr["all"] = ["type", "port", "compress", "u", "p", "target"]
|
||||||
arr["tunnelServer"] = ["type", "port", "target", "u", "p", "compress"]
|
arr["tunnelServer"] = ["type", "port", "target", "u", "p", "compress"]
|
||||||
arr["udpServer"] = ["type", "port", "target", "compress"]
|
arr["udpServer"] = ["type", "port", "target", "compress"]
|
||||||
arr["sock5Server"] = ["type", "port", "compress", "u", "p"]
|
arr["socks5Server"] = ["type", "port", "compress", "u", "p"]
|
||||||
arr["httpProxyServer"] = ["type", "port", "compress", "u", "p"]
|
arr["httpProxyServer"] = ["type", "port", "compress", "u", "p"]
|
||||||
arr["hostServer"] = ["type", "compress", "u", "p"]
|
arr["hostServer"] = ["type", "compress", "u", "p"]
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user