mirror of
https://github.com/ehang-io/nps.git
synced 2026-11-01 01:02:12 +08:00
客户端服务端分离
This commit is contained in:
1 parent
dcd21f211d
commit
1f61b99387
46 files changed
+1062
-1431
No files matched your search
@@ -11,19 +11,17 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
|
||||

|
||||
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] 支持多站点配置,兼容多个内网网站,可处理相互之间的跳转包含关系
|
||||
- [x] 断线自动重连
|
||||
- [x] 支持多路传输,提高并发
|
||||
- [x] 跨站自动匹配替换
|
||||
@@ -44,13 +42,12 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
|
||||
2. [web管理模式](#web管理模式)(多隧道时推荐)
|
||||
3. [tcp隧道模式](#tcp隧道模式)
|
||||
4. [udp隧道模式](#udp隧道模式)
|
||||
5. [http反向代理请求](#http代理请求)
|
||||
6. [socks5代理模式](#socks5代理模式)
|
||||
7. [http代理模式](#http代理模式)
|
||||
8. [数据压缩支持](#数据压缩支持)
|
||||
9. [站点密码保护](#站点保护)
|
||||
10. [加密传输](#加密传输)
|
||||
11. [TCP多路复用](#多路复用)
|
||||
5. [socks5代理模式](#socks5代理模式)
|
||||
6. [http代理模式](#http代理模式)
|
||||
7. [数据压缩支持](#数据压缩支持)
|
||||
8. [站点密码保护](#站点保护)
|
||||
9. [加密传输](#加密传输)
|
||||
10. [TCP多路复用](#多路复用)
|
||||
11. [配置文件说明](#配置文件)
|
||||
|
||||
## 安装
|
||||
@@ -58,13 +55,14 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
|
||||
1. release安装
|
||||
> https://github.com/cnlh/easyProxy/releases
|
||||
|
||||
下载对应的系统版本即可,服务端和客户端共用一个程序,go语言开发,无需任何第三方依赖
|
||||
下载对应的系统版本即可,服务端和客户端是单独的,go语言开发,无需任何第三方依赖
|
||||
|
||||
2. 源码安装
|
||||
- 安装源码
|
||||
> go get github.com/cnlh/easyProxy
|
||||
- 编译
|
||||
> go build
|
||||
> go build cmd/proxy_server.go
|
||||
> go build cmd/proxy_client.go
|
||||
|
||||
## web管理模式
|
||||
|
||||
@@ -72,6 +70,9 @@ easyProxy是一款轻量级、高性能、功能最为强大的**内网穿透**
|
||||
### 介绍
|
||||
|
||||
可在网页上配置和管理各个tcp、udp隧道、内网站点代理等等,功能极为强大,操作也非常方便。
|
||||
|
||||
**提示:使用web模式时,服务端执行文件必须在项目根目录,否则无法正确加载配置文件**
|
||||
|
||||
### 使用
|
||||
|
||||
**有两种模式:**
|
||||
@@ -218,116 +219,7 @@ target | 目标地址,格式如上
|
||||
./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代理模式
|
||||
@@ -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
|
||||
```
|
||||
|
||||
## 加密传输
|
||||
|
||||
Executable
+241
@@ -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 (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/cnlh/easyProxy/utils"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
@@ -28,54 +27,49 @@ func NewRPClient(svraddr string, tcpNum int, vKey string) *TRPClient {
|
||||
//start
|
||||
func (s *TRPClient) Start() error {
|
||||
for i := 0; i < s.tcpNum; i++ {
|
||||
go s.newConn()
|
||||
go s.NewConn()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//新建
|
||||
func (s *TRPClient) newConn() error {
|
||||
func (s *TRPClient) NewConn() error {
|
||||
s.Lock()
|
||||
conn, err := net.Dial("tcp", s.svrAddr)
|
||||
if err != nil {
|
||||
log.Println("连接服务端失败,五秒后将重连")
|
||||
time.Sleep(time.Second * 5)
|
||||
s.Unlock()
|
||||
go s.newConn()
|
||||
go s.NewConn()
|
||||
return err
|
||||
}
|
||||
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()
|
||||
if _, err := c.Write([]byte(getverifyval(s.vKey))); err != nil {
|
||||
if _, err := c.Write([]byte(utils.Getverifyval(s.vKey))); err != nil {
|
||||
return err
|
||||
}
|
||||
c.wMain()
|
||||
c.WriteMain()
|
||||
for {
|
||||
flags, err := c.ReadFlag()
|
||||
if err != nil {
|
||||
log.Println("服务端断开,五秒后将重连", err)
|
||||
time.Sleep(5 * time.Second)
|
||||
go s.newConn()
|
||||
go s.NewConn()
|
||||
break
|
||||
}
|
||||
switch flags {
|
||||
case VERIFY_EER:
|
||||
case utils.VERIFY_EER:
|
||||
log.Fatalln("vkey:", s.vKey, "不正确,服务端拒绝连接,请检查")
|
||||
case RES_SIGN: //代理请求模式
|
||||
if err := s.dealHttp(c); err != nil {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
case WORK_CHAN: //隧道模式,每次开启10个,加快连接速度
|
||||
case utils.WORK_CHAN: //隧道模式,每次开启10个,加快连接速度
|
||||
for i := 0; i < 5; i++ {
|
||||
go s.dealChan()
|
||||
}
|
||||
case RES_MSG:
|
||||
case utils.RES_MSG:
|
||||
log.Println("服务端返回错误。")
|
||||
default:
|
||||
log.Println("无法解析该错误。", flags)
|
||||
@@ -94,15 +88,15 @@ func (s *TRPClient) dealChan() {
|
||||
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)
|
||||
return
|
||||
}
|
||||
//默认长连接保持
|
||||
c := NewConn(conn)
|
||||
c := utils.NewConn(conn)
|
||||
c.SetAlive()
|
||||
//写标志
|
||||
c.wChan()
|
||||
c.WriteChan()
|
||||
re:
|
||||
//获取连接的host type(tcp or udp)
|
||||
typeStr, host, en, de, crypt, mux, err := c.GetHostFromConn()
|
||||
@@ -111,51 +105,24 @@ re:
|
||||
c.Close()
|
||||
return
|
||||
}
|
||||
//与目标建立连接,超时时间为3
|
||||
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:
|
||||
Process(c, typeStr, host, en, de, crypt, mux)
|
||||
if mux {
|
||||
FlushConn(conn)
|
||||
utils.FlushConn(conn)
|
||||
goto re
|
||||
} else {
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
//http模式处理
|
||||
func (s *TRPClient) dealHttp(c *Conn) error {
|
||||
buf := make([]byte, 1024*32)
|
||||
en, de, crypt, _ := c.GetConnInfoFromConn()
|
||||
n, err := c.ReadFrom(buf, de, crypt)
|
||||
func Process(c *utils.Conn, typeStr, host string, en, de int, crypt, mux bool) {
|
||||
//与目标建立连接,超时时间为3
|
||||
server, err := net.DialTimeout(typeStr, host, time.Second*3)
|
||||
if err != nil {
|
||||
c.wError()
|
||||
return err
|
||||
log.Println("connect to ", host, "error:", err, mux)
|
||||
c.WriteFail()
|
||||
return
|
||||
}
|
||||
req, err := DecodeRequest(buf[:n])
|
||||
if err != nil {
|
||||
c.wError()
|
||||
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
|
||||
c.WriteSuccess()
|
||||
go utils.Relay(server, c.Conn, de, crypt, mux)
|
||||
utils.Relay(c.Conn, server, en, crypt, mux)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
+1
-1
@@ -4,7 +4,7 @@ appname = easyProxy
|
||||
httpport = 8080
|
||||
|
||||
#启动模式dev|pro
|
||||
runmode = pro
|
||||
runmode = dev
|
||||
|
||||
#web管理密码
|
||||
password=123
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
b.proxy.com,127.0.0.1:82,o2430bnq22jgnmcl
|
||||
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
|
||||
|
+3
-1
@@ -1,3 +1,5 @@
|
||||
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,,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
@@ -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
@@ -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
@@ -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
@@ -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{})
|
||||
}
|
||||
@@ -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 (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/astaxie/beego"
|
||||
"io/ioutil"
|
||||
"github.com/cnlh/easyProxy/utils"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -34,9 +33,8 @@ type HostList struct {
|
||||
Target string //目标
|
||||
}
|
||||
|
||||
func NewCsv(bridge *Tunnel, runList map[string]interface{}) *Csv {
|
||||
func NewCsv(runList map[string]interface{}) *Csv {
|
||||
c := new(Csv)
|
||||
c.Bridge = bridge
|
||||
c.RunList = runList
|
||||
return c
|
||||
}
|
||||
@@ -44,7 +42,6 @@ func NewCsv(bridge *Tunnel, runList map[string]interface{}) *Csv {
|
||||
type Csv struct {
|
||||
Tasks []*ServerConfig
|
||||
Path string
|
||||
Bridge *Tunnel
|
||||
RunList map[string]interface{}
|
||||
Hosts []*HostList //域名列表
|
||||
}
|
||||
@@ -72,8 +69,8 @@ func (s *Csv) StoreTasksToCsv() {
|
||||
task.P,
|
||||
task.Compress,
|
||||
strconv.Itoa(task.Start),
|
||||
GetStrByBool(task.Crypt),
|
||||
GetStrByBool(task.Mux),
|
||||
utils.GetStrByBool(task.Crypt),
|
||||
utils.GetStrByBool(task.Mux),
|
||||
strconv.Itoa(task.CompressEncode),
|
||||
strconv.Itoa(task.CompressDecode),
|
||||
}
|
||||
@@ -118,10 +115,10 @@ func (s *Csv) LoadTaskFromCsv() {
|
||||
P: item[5],
|
||||
Compress: item[6],
|
||||
Start: Start,
|
||||
Crypt: GetBoolByStr(item[8]),
|
||||
Mux: GetBoolByStr(item[9]),
|
||||
CompressEncode: GetIntNoerrByStr(item[10]),
|
||||
CompressDecode: GetIntNoerrByStr(item[11]),
|
||||
Crypt: utils.GetBoolByStr(item[8]),
|
||||
Mux: utils.GetBoolByStr(item[9]),
|
||||
CompressEncode: utils.GetIntNoerrByStr(item[10]),
|
||||
CompressDecode: utils.GetIntNoerrByStr(item[11]),
|
||||
}
|
||||
tasks = append(tasks, post)
|
||||
}
|
||||
@@ -130,7 +127,7 @@ func (s *Csv) LoadTaskFromCsv() {
|
||||
|
||||
func (s *Csv) StoreHostToCsv() {
|
||||
// 创建文件
|
||||
csvFile, err := os.Create(s.Path + "hosts.csv")
|
||||
csvFile, err := os.Create(beego.AppPath + "/conf/hosts.csv")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -186,38 +183,6 @@ func (s *Csv) LoadHostFromCsv() {
|
||||
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) {
|
||||
s.Tasks = append(s.Tasks, t)
|
||||
s.StoreTasksToCsv()
|
||||
@@ -232,7 +197,6 @@ func (s *Csv) UpdateTask(t *ServerConfig) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
//TODO:待测试
|
||||
return errors.New("不存在")
|
||||
}
|
||||
|
||||
@@ -297,31 +261,3 @@ func (s *Csv) GetHostList(start, length int, vKey string) ([]*HostList, int) {
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -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 (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"github.com/cnlh/easyProxy/bridge"
|
||||
"github.com/cnlh/easyProxy/utils"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
@@ -44,7 +46,7 @@ const (
|
||||
)
|
||||
|
||||
type Sock5ModeServer struct {
|
||||
bridge *Tunnel
|
||||
bridge *bridge.Tunnel
|
||||
isVerify bool
|
||||
listener net.Listener
|
||||
config *ServerConfig
|
||||
@@ -105,7 +107,7 @@ func (s *Sock5ModeServer) sendReply(c net.Conn, rep uint8) {
|
||||
}
|
||||
|
||||
//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)
|
||||
c.Read(addrType)
|
||||
var host string
|
||||
@@ -142,14 +144,14 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *Conn,
|
||||
s.sendReply(c, succeeded)
|
||||
var ltype string
|
||||
if command == associateMethod {
|
||||
ltype = CONN_UDP
|
||||
ltype = utils.CONN_UDP
|
||||
} else {
|
||||
ltype = CONN_TCP
|
||||
ltype = utils.CONN_TCP
|
||||
}
|
||||
_, err = client.WriteHost(ltype, addr)
|
||||
var flag string
|
||||
if flag, err = client.ReadFlag(); err == nil {
|
||||
if flag != CONN_SUCCESS {
|
||||
if flag != utils.CONN_SUCCESS {
|
||||
err = errors.New("conn failed")
|
||||
}
|
||||
}
|
||||
@@ -167,8 +169,8 @@ func (s *Sock5ModeServer) handleConnect(c net.Conn) {
|
||||
if err != nil {
|
||||
c.Close()
|
||||
} else {
|
||||
go 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)
|
||||
go utils.Relay(proxyConn.Conn, c, s.config.CompressEncode, 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 {
|
||||
c.Close()
|
||||
} else {
|
||||
go 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)
|
||||
go utils.Relay(proxyConn.Conn, c, s.config.CompressEncode, s.config.Crypt, s.config.Mux)
|
||||
utils.Relay(c, proxyConn.Conn, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
|
||||
}
|
||||
}
|
||||
|
||||
//new conn
|
||||
func (s *Sock5ModeServer) handleNewConn(c net.Conn) {
|
||||
func (s *Sock5ModeServer) handleConn(c net.Conn) {
|
||||
buf := make([]byte, 2)
|
||||
if _, err := io.ReadFull(c, buf); err != nil {
|
||||
log.Println("negotiation err", err)
|
||||
@@ -285,6 +287,7 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error {
|
||||
|
||||
//start
|
||||
func (s *Sock5ModeServer) Start() error {
|
||||
var err error
|
||||
s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.config.TcpPort))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -297,7 +300,7 @@ func (s *Sock5ModeServer) Start() error {
|
||||
}
|
||||
log.Fatal("accept error: ", err)
|
||||
}
|
||||
go s.handleNewConn(conn)
|
||||
go s.handleConn(conn)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -308,7 +311,7 @@ func (s *Sock5ModeServer) Close() error {
|
||||
}
|
||||
|
||||
//new
|
||||
func NewSock5ModeServer(bridge *Tunnel, cnf *ServerConfig) *Sock5ModeServer {
|
||||
func NewSock5ModeServer(bridge *bridge.Tunnel, cnf *ServerConfig) *Sock5ModeServer {
|
||||
s := new(Sock5ModeServer)
|
||||
s.bridge = bridge
|
||||
s.config = cnf
|
||||
Executable
+191
@@ -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 (
|
||||
"github.com/cnlh/easyProxy/bridge"
|
||||
"github.com/cnlh/easyProxy/utils"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
@@ -8,22 +10,23 @@ import (
|
||||
)
|
||||
|
||||
type UdpModeServer struct {
|
||||
bridge *Tunnel
|
||||
bridge *bridge.Tunnel
|
||||
listener *net.UDPConn
|
||||
udpMap map[string]*Conn
|
||||
udpMap map[string]*utils.Conn
|
||||
config *ServerConfig
|
||||
}
|
||||
|
||||
func NewUdpModeServer(bridge *Tunnel, cnf *ServerConfig) *UdpModeServer {
|
||||
func NewUdpModeServer(bridge *bridge.Tunnel, cnf *ServerConfig) *UdpModeServer {
|
||||
s := new(UdpModeServer)
|
||||
s.bridge = bridge
|
||||
s.udpMap = make(map[string]*Conn)
|
||||
s.udpMap = make(map[string]*utils.Conn)
|
||||
s.config = cnf
|
||||
return s
|
||||
}
|
||||
|
||||
//开始
|
||||
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, ""})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -49,7 +52,7 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
|
||||
log.Println(err)
|
||||
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()
|
||||
return
|
||||
}
|
||||
@@ -61,7 +64,7 @@ func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
if flag == CONN_SUCCESS {
|
||||
if flag == utils.CONN_SUCCESS {
|
||||
conn.WriteTo(data, s.config.CompressEncode, s.config.Crypt)
|
||||
buf := make([]byte, 1024)
|
||||
//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
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
-19
@@ -1,4 +1,4 @@
|
||||
package lib
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
@@ -16,6 +16,8 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const cryptKey = "1234567812345678"
|
||||
|
||||
type CryptConn struct {
|
||||
conn net.Conn
|
||||
crypt bool
|
||||
@@ -126,13 +128,13 @@ func (s *SnappyConn) Read(b []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
type Conn struct {
|
||||
conn net.Conn
|
||||
Conn net.Conn
|
||||
}
|
||||
|
||||
//new conn
|
||||
func NewConn(conn net.Conn) *Conn {
|
||||
c := new(Conn)
|
||||
c.conn = conn
|
||||
c.Conn = conn
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -160,6 +162,7 @@ func (s *Conn) GetLen() (int, error) {
|
||||
//写入长度+内容 粘包
|
||||
func (s *Conn) WriteLen(buf []byte) (int, error) {
|
||||
var b []byte
|
||||
var err error
|
||||
if b, err = GetLenBytes(buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -209,7 +212,7 @@ func (s *Conn) WriteHost(ltype string, host string) (int, error) {
|
||||
|
||||
//设置连接为长连接
|
||||
func (s *Conn) SetAlive() {
|
||||
conn := s.conn.(*net.TCPConn)
|
||||
conn := s.Conn.(*net.TCPConn)
|
||||
conn.SetReadDeadline(time.Time{})
|
||||
conn.SetKeepAlive(true)
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
buf, err := s.ReadLen(4)
|
||||
//TODO:错误处理
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -281,51 +283,51 @@ func (s *Conn) GetConnInfoFromConn() (en, de int, crypt, mux bool) {
|
||||
|
||||
//close
|
||||
func (s *Conn) Close() error {
|
||||
return s.conn.Close()
|
||||
return s.Conn.Close()
|
||||
}
|
||||
|
||||
//write
|
||||
func (s *Conn) Write(b []byte) (int, error) {
|
||||
return s.conn.Write(b)
|
||||
return s.Conn.Write(b)
|
||||
}
|
||||
|
||||
//read
|
||||
func (s *Conn) Read(b []byte) (int, error) {
|
||||
return s.conn.Read(b)
|
||||
return s.Conn.Read(b)
|
||||
}
|
||||
|
||||
//write error
|
||||
func (s *Conn) wError() (int, error) {
|
||||
func (s *Conn) WriteError() (int, error) {
|
||||
return s.Write([]byte(RES_MSG))
|
||||
}
|
||||
|
||||
//write sign flag
|
||||
func (s *Conn) wSign() (int, error) {
|
||||
func (s *Conn) WriteSign() (int, error) {
|
||||
return s.Write([]byte(RES_SIGN))
|
||||
}
|
||||
|
||||
//write main
|
||||
func (s *Conn) wMain() (int, error) {
|
||||
func (s *Conn) WriteMain() (int, error) {
|
||||
return s.Write([]byte(WORK_MAIN))
|
||||
}
|
||||
|
||||
//write chan
|
||||
func (s *Conn) wChan() (int, error) {
|
||||
func (s *Conn) WriteChan() (int, error) {
|
||||
return s.Write([]byte(WORK_CHAN))
|
||||
}
|
||||
|
||||
//write test
|
||||
func (s *Conn) wTest() (int, error) {
|
||||
func (s *Conn) WriteTest() (int, error) {
|
||||
return s.Write([]byte(TEST_FLAG))
|
||||
}
|
||||
|
||||
//write test
|
||||
func (s *Conn) wSuccess() (int, error) {
|
||||
func (s *Conn) WriteSuccess() (int, error) {
|
||||
return s.Write([]byte(CONN_SUCCESS))
|
||||
}
|
||||
|
||||
//write test
|
||||
func (s *Conn) wFail() (int, error) {
|
||||
func (s *Conn) WriteFail() (int, error) {
|
||||
return s.Write([]byte(CONN_ERROR))
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package lib
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"github.com/pkg/errors"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
Executable
+204
@@ -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 (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/cnlh/easyProxy/lib"
|
||||
"github.com/cnlh/easyProxy/server"
|
||||
"github.com/cnlh/easyProxy/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -33,8 +34,8 @@ func (s *BaseController) display(tpl ...string) {
|
||||
}
|
||||
s.Data["menu"] = s.actionName
|
||||
ip := s.Ctx.Request.Host
|
||||
s.Data["ip"] = lib.Gethostbyname(ip[0:strings.LastIndex(ip, ":")])
|
||||
s.Data["p"] = *lib.TcpPort
|
||||
s.Data["ip"] = utils.Gethostbyname(ip[0:strings.LastIndex(ip, ":")])
|
||||
s.Data["p"] = server.Bridge.TunnelPort
|
||||
s.Data["proxyPort"] = beego.AppConfig.String("hostPort")
|
||||
s.Layout = "public/layout.html"
|
||||
s.TplName = tplname
|
||||
@@ -1,7 +1,8 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/cnlh/easyProxy/lib"
|
||||
"github.com/cnlh/easyProxy/server"
|
||||
"github.com/cnlh/easyProxy/utils"
|
||||
)
|
||||
|
||||
type IndexController struct {
|
||||
@@ -27,7 +28,7 @@ func (s *IndexController) Udp() {
|
||||
|
||||
func (s *IndexController) Socks5() {
|
||||
s.SetInfo("socks5管理")
|
||||
s.SetType("sock5Server")
|
||||
s.SetType("socks5Server")
|
||||
s.display("index/list")
|
||||
}
|
||||
|
||||
@@ -46,7 +47,7 @@ func (s *IndexController) Host() {
|
||||
func (s *IndexController) GetServerConfig() {
|
||||
start, length := s.GetAjaxParams()
|
||||
taskType := s.GetString("type")
|
||||
list, cnt := lib.CsvDb.GetServerConfig(start, length, taskType)
|
||||
list, cnt := server.GetServerConfig(start, length, taskType)
|
||||
s.AjaxTable(list, cnt, cnt)
|
||||
}
|
||||
|
||||
@@ -56,20 +57,20 @@ func (s *IndexController) Add() {
|
||||
s.SetInfo("新增")
|
||||
s.display()
|
||||
} else {
|
||||
t := &lib.ServerConfig{
|
||||
t := &server.ServerConfig{
|
||||
TcpPort: s.GetIntNoErr("port"),
|
||||
Mode: s.GetString("type"),
|
||||
Target: s.GetString("target"),
|
||||
VerifyKey: lib.GetRandomString(16),
|
||||
VerifyKey: utils.GetRandomString(16),
|
||||
U: s.GetString("u"),
|
||||
P: s.GetString("p"),
|
||||
Compress: s.GetString("compress"),
|
||||
Crypt: lib.GetBoolByStr(s.GetString("crypt")),
|
||||
Mux: lib.GetBoolByStr(s.GetString("mux")),
|
||||
Crypt: utils.GetBoolByStr(s.GetString("crypt")),
|
||||
Mux: utils.GetBoolByStr(s.GetString("mux")),
|
||||
IsRun: 0,
|
||||
}
|
||||
lib.CsvDb.NewTask(t)
|
||||
if err := lib.AddTask(t); err != nil {
|
||||
server.CsvDb.NewTask(t)
|
||||
if err := server.AddTask(t); err != nil {
|
||||
s.AjaxErr(err.Error())
|
||||
} else {
|
||||
s.AjaxOk("添加成功")
|
||||
@@ -80,7 +81,7 @@ func (s *IndexController) Add() {
|
||||
func (s *IndexController) Edit() {
|
||||
if s.Ctx.Request.Method == "GET" {
|
||||
vKey := s.GetString("vKey")
|
||||
if t, err := lib.CsvDb.GetTask(vKey); err != nil {
|
||||
if t, err := server.CsvDb.GetTask(vKey); err != nil {
|
||||
s.error()
|
||||
} else {
|
||||
s.Data["t"] = t
|
||||
@@ -89,7 +90,7 @@ func (s *IndexController) Edit() {
|
||||
s.display()
|
||||
} else {
|
||||
vKey := s.GetString("vKey")
|
||||
if t, err := lib.CsvDb.GetTask(vKey); err != nil {
|
||||
if t, err := server.CsvDb.GetTask(vKey); err != nil {
|
||||
s.error()
|
||||
} else {
|
||||
t.TcpPort = s.GetIntNoErr("port")
|
||||
@@ -98,11 +99,11 @@ func (s *IndexController) Edit() {
|
||||
t.U = s.GetString("u")
|
||||
t.P = s.GetString("p")
|
||||
t.Compress = s.GetString("compress")
|
||||
t.Crypt = lib.GetBoolByStr(s.GetString("crypt"))
|
||||
t.Mux = lib.GetBoolByStr(s.GetString("mux"))
|
||||
lib.CsvDb.UpdateTask(t)
|
||||
lib.StopServer(t.VerifyKey)
|
||||
lib.StartTask(t.VerifyKey)
|
||||
t.Crypt = utils.GetBoolByStr(s.GetString("crypt"))
|
||||
t.Mux = utils.GetBoolByStr(s.GetString("mux"))
|
||||
server.CsvDb.UpdateTask(t)
|
||||
server.StopServer(t.VerifyKey)
|
||||
server.StartTask(t.VerifyKey)
|
||||
}
|
||||
s.AjaxOk("修改成功")
|
||||
}
|
||||
@@ -110,14 +111,14 @@ func (s *IndexController) Edit() {
|
||||
|
||||
func (s *IndexController) Stop() {
|
||||
vKey := s.GetString("vKey")
|
||||
if err := lib.StopServer(vKey); err != nil {
|
||||
if err := server.StopServer(vKey); err != nil {
|
||||
s.AjaxErr("停止失败")
|
||||
}
|
||||
s.AjaxOk("停止成功")
|
||||
}
|
||||
func (s *IndexController) Del() {
|
||||
vKey := s.GetString("vKey")
|
||||
if err := lib.DelTask(vKey); err != nil {
|
||||
if err := server.DelTask(vKey); err != nil {
|
||||
s.AjaxErr("删除失败")
|
||||
}
|
||||
s.AjaxOk("删除成功")
|
||||
@@ -125,7 +126,7 @@ func (s *IndexController) Del() {
|
||||
|
||||
func (s *IndexController) Start() {
|
||||
vKey := s.GetString("vKey")
|
||||
if err := lib.StartTask(vKey); err != nil {
|
||||
if err := server.StartTask(vKey); err != nil {
|
||||
s.AjaxErr("开启失败")
|
||||
}
|
||||
s.AjaxOk("开启成功")
|
||||
@@ -139,14 +140,14 @@ func (s *IndexController) HostList() {
|
||||
} else {
|
||||
start, length := s.GetAjaxParams()
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *IndexController) DelHost() {
|
||||
host := s.GetString("host")
|
||||
if err := lib.CsvDb.DelHost(host); err != nil {
|
||||
if err := server.CsvDb.DelHost(host); err != nil {
|
||||
s.AjaxErr("删除失败")
|
||||
}
|
||||
s.AjaxOk("删除成功")
|
||||
@@ -158,12 +159,12 @@ func (s *IndexController) AddHost() {
|
||||
s.SetInfo("新增")
|
||||
s.display("index/hadd")
|
||||
} else {
|
||||
h := &lib.HostList{
|
||||
h := &server.HostList{
|
||||
Vkey: s.GetString("vkey"),
|
||||
Host: s.GetString("host"),
|
||||
Target: s.GetString("target"),
|
||||
}
|
||||
lib.CsvDb.NewHost(h)
|
||||
server.CsvDb.NewHost(h)
|
||||
s.AjaxOk("添加成功")
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -2,7 +2,7 @@ package routers
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/cnlh/easyProxy/controllers"
|
||||
"github.com/cnlh/easyProxy/web/controllers"
|
||||
)
|
||||
|
||||
func init() {
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -17,7 +17,7 @@
|
||||
<select class="form-control" name="type" id="type">
|
||||
<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 "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 "hostServer" .type}}selected{{end}} value="hostServer">host客户端</option>
|
||||
</select>
|
||||
@@ -75,7 +75,7 @@
|
||||
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["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["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">
|
||||
<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 "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 "hostServer" .t.Mode}}selected{{end}} value="hostServer">host客户端</option>
|
||||
</select>
|
||||
@@ -72,7 +72,7 @@
|
||||
arr["all"] = ["type", "port", "compress", "u", "p", "target"]
|
||||
arr["tunnelServer"] = ["type", "port", "target", "u", "p", "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["hostServer"] = ["type", "compress", "u", "p"]
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Reference in new issue
Block a user