客户端服务端分离

This commit is contained in:
刘河
2019-01-09 20:33:00 +08:00
parent dcd21f211d
commit 1f61b99387
46 changed files with 1062 additions and 1431 deletions

View File

@@ -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
}

View File

@@ -1,161 +0,0 @@
package lib
import (
"errors"
"fmt"
"log"
"net"
"sync"
"time"
)
type TRPClient struct {
svrAddr string
tcpNum int
sync.Mutex
vKey string
}
//new client
func NewRPClient(svraddr string, tcpNum int, vKey string) *TRPClient {
c := new(TRPClient)
c.svrAddr = svraddr
c.tcpNum = tcpNum
c.vKey = vKey
return c
}
//start
func (s *TRPClient) Start() error {
for i := 0; i < s.tcpNum; i++ {
go s.newConn()
}
return nil
}
//新建
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()
return err
}
s.Unlock()
return s.process(NewConn(conn))
}
//处理
func (s *TRPClient) process(c *Conn) error {
c.SetAlive()
if _, err := c.Write([]byte(getverifyval(s.vKey))); err != nil {
return err
}
c.wMain()
for {
flags, err := c.ReadFlag()
if err != nil {
log.Println("服务端断开,五秒后将重连", err)
time.Sleep(5 * time.Second)
go s.newConn()
break
}
switch flags {
case 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个加快连接速度
for i := 0; i < 5; i++ {
go s.dealChan()
}
case RES_MSG:
log.Println("服务端返回错误。")
default:
log.Println("无法解析该错误。", flags)
}
}
return nil
}
//隧道模式处理
func (s *TRPClient) dealChan() {
var err error
//创建一个tcp连接
conn, err := net.Dial("tcp", s.svrAddr)
if err != nil {
log.Println("connect to ", s.svrAddr, "error:", err)
return
}
//验证
if _, err := conn.Write([]byte(getverifyval(s.vKey))); err != nil {
log.Println("connect to ", s.svrAddr, "error:", err)
return
}
//默认长连接保持
c := NewConn(conn)
c.SetAlive()
//写标志
c.wChan()
re:
//获取连接的host type(tcp or udp)
typeStr, host, en, de, crypt, mux, err := c.GetHostFromConn()
if err != nil {
log.Println("get host info error:", err)
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:
if mux {
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)
if err != nil {
c.wError()
return err
}
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
}

View File

@@ -1,352 +0,0 @@
package lib
import (
"bufio"
"bytes"
"encoding/binary"
"errors"
"github.com/golang/snappy"
"io"
"log"
"net"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
type CryptConn struct {
conn net.Conn
crypt bool
}
func NewCryptConn(conn net.Conn, crypt bool) *CryptConn {
c := new(CryptConn)
c.conn = conn
c.crypt = crypt
return c
}
//加密写
func (s *CryptConn) Write(b []byte) (n int, err error) {
n = len(b)
if s.crypt {
if b, err = AesEncrypt(b, []byte(cryptKey)); err != nil {
return
}
}
if b, err = GetLenBytes(b); err != nil {
return
}
_, err = s.conn.Write(b)
return
}
//解密读
func (s *CryptConn) Read(b []byte) (n int, err error) {
defer func() {
if err == nil && n == len(IO_EOF) && string(b[:n]) == IO_EOF {
err = io.EOF
n = 0
}
}()
var lens int
var buf, bs []byte
c := NewConn(s.conn)
if lens, err = c.GetLen(); err != nil {
return
}
if buf, err = c.ReadLen(lens); err != nil {
return
}
if s.crypt {
if bs, err = AesDecrypt(buf, []byte(cryptKey)); err != nil {
return
}
} else {
bs = buf
}
n = len(bs)
copy(b, bs)
return
}
type SnappyConn struct {
w *snappy.Writer
r *snappy.Reader
crypt bool
}
func NewSnappyConn(conn net.Conn, crypt bool) *SnappyConn {
c := new(SnappyConn)
c.w = snappy.NewBufferedWriter(conn)
c.r = snappy.NewReader(conn)
c.crypt = crypt
return c
}
//snappy压缩写 包含加密
func (s *SnappyConn) Write(b []byte) (n int, err error) {
n = len(b)
if s.crypt {
if b, err = AesEncrypt(b, []byte(cryptKey)); err != nil {
log.Println("encode crypt error:", err)
return
}
}
if _, err = s.w.Write(b); err != nil {
return
}
err = s.w.Flush()
return
}
//snappy压缩读 包含解密
func (s *SnappyConn) Read(b []byte) (n int, err error) {
defer func() {
if err == nil && n == len(IO_EOF) && string(b[:n]) == IO_EOF {
err = io.EOF
n = 0
}
}()
if n, err = s.r.Read(b); err != nil {
return
}
if s.crypt {
var bs []byte
if bs, err = AesDecrypt(b[:n], []byte(cryptKey)); err != nil {
log.Println("decode crypt error:", err)
return
}
n = len(bs)
copy(b, bs)
}
return
}
type Conn struct {
conn net.Conn
}
//new conn
func NewConn(conn net.Conn) *Conn {
c := new(Conn)
c.conn = conn
return c
}
//读取指定长度内容
func (s *Conn) ReadLen(cLen int) ([]byte, error) {
if cLen > 65535 {
return nil, errors.New("长度错误")
}
buf := bufPool.Get().([]byte)[:cLen]
if n, err := io.ReadFull(s, buf); err != nil || n != cLen {
return buf, errors.New("读取指定长度错误" + err.Error())
}
return buf, nil
}
//获取长度
func (s *Conn) GetLen() (int, error) {
val, err := s.ReadLen(4)
if err != nil {
return 0, err
}
return GetLenByBytes(val)
}
//写入长度+内容 粘包
func (s *Conn) WriteLen(buf []byte) (int, error) {
var b []byte
if b, err = GetLenBytes(buf); err != nil {
return 0, err
}
return s.Write(b)
}
//读取flag
func (s *Conn) ReadFlag() (string, error) {
val, err := s.ReadLen(4)
if err != nil {
return "", err
}
return string(val), err
}
//读取host 连接地址 压缩类型
func (s *Conn) GetHostFromConn() (typeStr string, host string, en, de int, crypt, mux bool, err error) {
retry:
lType, err := s.ReadLen(3)
if err != nil {
return
}
if typeStr = string(lType); typeStr == TEST_FLAG {
en, de, crypt, mux = s.GetConnInfoFromConn()
goto retry
}
cLen, err := s.GetLen()
if err != nil {
return
}
hostByte, err := s.ReadLen(cLen)
if err != nil {
return
}
host = string(hostByte)
return
}
//写连接类型 和 host地址
func (s *Conn) WriteHost(ltype string, host string) (int, error) {
raw := bytes.NewBuffer([]byte{})
binary.Write(raw, binary.LittleEndian, []byte(ltype))
binary.Write(raw, binary.LittleEndian, int32(len([]byte(host))))
binary.Write(raw, binary.LittleEndian, []byte(host))
return s.Write(raw.Bytes())
}
//设置连接为长连接
func (s *Conn) SetAlive() {
conn := s.conn.(*net.TCPConn)
conn.SetReadDeadline(time.Time{})
conn.SetKeepAlive(true)
conn.SetKeepAlivePeriod(time.Duration(2 * time.Second))
}
//从tcp报文中解析出host连接类型等
func (s *Conn) GetHost() (method, address string, rb []byte, err error, r *http.Request) {
var b [32 * 1024]byte
var n int
if n, err = s.Read(b[:]); err != nil {
return
}
rb = b[:n]
r, err = http.ReadRequest(bufio.NewReader(bytes.NewReader(rb)))
if err != nil {
log.Println("解析host出错", err)
return
}
hostPortURL, err := url.Parse(r.Host)
if err != nil {
return
}
if hostPortURL.Opaque == "443" { //https访问
address = r.Host + ":443"
} else { //http访问
if strings.Index(hostPortURL.Host, ":") == -1 { //host不带端口 默认80
address = r.Host + ":80"
} else {
address = r.Host
}
}
return
}
//单独读(加密|压缩)
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 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 NewCryptConn(s.conn, crypt).Write(b)
}
//写压缩方式,加密
func (s *Conn) WriteConnInfo(en, de int, crypt, mux bool) {
s.Write([]byte(strconv.Itoa(en) + strconv.Itoa(de) + GetStrByBool(crypt) + GetStrByBool(mux)))
}
//获取压缩方式,是否加密
func (s *Conn) GetConnInfoFromConn() (en, de int, crypt, mux bool) {
buf, err := s.ReadLen(4)
//TODO错误处理
if err != nil {
return
}
en, _ = strconv.Atoi(string(buf[0]))
de, _ = strconv.Atoi(string(buf[1]))
crypt = GetBoolByStr(string(buf[2]))
mux = GetBoolByStr(string(buf[3]))
return
}
//close
func (s *Conn) Close() error {
return s.conn.Close()
}
//write
func (s *Conn) Write(b []byte) (int, error) {
return s.conn.Write(b)
}
//read
func (s *Conn) Read(b []byte) (int, error) {
return s.conn.Read(b)
}
//write error
func (s *Conn) wError() (int, error) {
return s.Write([]byte(RES_MSG))
}
//write sign flag
func (s *Conn) wSign() (int, error) {
return s.Write([]byte(RES_SIGN))
}
//write main
func (s *Conn) wMain() (int, error) {
return s.Write([]byte(WORK_MAIN))
}
//write chan
func (s *Conn) wChan() (int, error) {
return s.Write([]byte(WORK_CHAN))
}
//write test
func (s *Conn) wTest() (int, error) {
return s.Write([]byte(TEST_FLAG))
}
//write test
func (s *Conn) wSuccess() (int, error) {
return s.Write([]byte(CONN_SUCCESS))
}
//write test
func (s *Conn) wFail() (int, error) {
return s.Write([]byte(CONN_ERROR))
}
//获取长度+内容
func GetLenBytes(buf []byte) (b []byte, err error) {
raw := bytes.NewBuffer([]byte{})
if err = binary.Write(raw, binary.LittleEndian, int32(len(buf))); err != nil {
return
}
if err = binary.Write(raw, binary.LittleEndian, buf); err != nil {
return
}
b = raw.Bytes()
return
}
//解析出长度
func GetLenByBytes(buf []byte) (int, error) {
nlen := binary.LittleEndian.Uint32(buf)
if nlen <= 0 {
return 0, errors.New("数据长度错误")
}
return int(nlen), nil
}

View File

@@ -1,82 +0,0 @@
package lib
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"encoding/hex"
"github.com/pkg/errors"
"math/rand"
"time"
)
//en
func AesEncrypt(origData, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
origData = PKCS5Padding(origData, blockSize)
// origData = ZeroPadding(origData, block.BlockSize())
blockMode := cipher.NewCBCEncrypter(block, key[:blockSize])
crypted := make([]byte, len(origData))
// 根据CryptBlocks方法的说明如下方式初始化crypted也可以
// crypted := origData
blockMode.CryptBlocks(crypted, origData)
return crypted, nil
}
//de
func AesDecrypt(crypted, key []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
origData := make([]byte, len(crypted))
// origData := crypted
blockMode.CryptBlocks(origData, crypted)
err, origData = PKCS5UnPadding(origData)
// origData = ZeroUnPadding(origData)
return origData, err
}
//补全
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
//去补
func PKCS5UnPadding(origData []byte) (error, []byte) {
length := len(origData)
// 去掉最后一个字节 unpadding 次
unpadding := int(origData[length-1])
if (length - unpadding) < 0 {
return errors.New("len error"), nil
}
return nil, origData[:(length - unpadding)]
}
//生成32位md5字串
func Md5(s string) string {
h := md5.New()
h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}
//生成随机验证密钥
func GetRandomString(l int) string {
str := "0123456789abcdefghijklmnopqrstuvwxyz"
bytes := []byte(str)
result := []byte{}
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return string(result)
}

View File

@@ -1,327 +0,0 @@
package lib
import (
"encoding/csv"
"encoding/json"
"errors"
"github.com/astaxie/beego"
"io/ioutil"
"log"
"os"
"strconv"
)
type ServerConfig struct {
TcpPort int //服务端与客户端通信端口
Mode string //启动方式
Target string //目标
VerifyKey string //flag
U string //socks5验证用户名
P string //socks5验证密码
Compress string //压缩方式
Start int //是否开启
IsRun int //是否在运行
ClientStatus int //客s户端状态
Crypt bool //是否加密
Mux bool //是否加密
CompressEncode int
CompressDecode int
}
type HostList struct {
Vkey string //服务端与客户端通信端口
Host string //启动方式
Target string //目标
}
func NewCsv(bridge *Tunnel, runList map[string]interface{}) *Csv {
c := new(Csv)
c.Bridge = bridge
c.RunList = runList
return c
}
type Csv struct {
Tasks []*ServerConfig
Path string
Bridge *Tunnel
RunList map[string]interface{}
Hosts []*HostList //域名列表
}
func (s *Csv) Init() {
s.LoadTaskFromCsv()
s.LoadHostFromCsv()
}
func (s *Csv) StoreTasksToCsv() {
// 创建文件
csvFile, err := os.Create(beego.AppPath + "/conf/tasks.csv")
if err != nil {
log.Fatalf(err.Error())
}
defer csvFile.Close()
writer := csv.NewWriter(csvFile)
for _, task := range s.Tasks {
record := []string{
strconv.Itoa(task.TcpPort),
task.Mode,
task.Target,
task.VerifyKey,
task.U,
task.P,
task.Compress,
strconv.Itoa(task.Start),
GetStrByBool(task.Crypt),
GetStrByBool(task.Mux),
strconv.Itoa(task.CompressEncode),
strconv.Itoa(task.CompressDecode),
}
err := writer.Write(record)
if err != nil {
log.Fatalf(err.Error())
}
}
writer.Flush()
}
func (s *Csv) LoadTaskFromCsv() {
// 打开文件
file, err := os.Open(beego.AppPath + "/conf/tasks.csv")
if err != nil {
panic(err)
}
defer file.Close()
// 获取csv的reader
reader := csv.NewReader(file)
// 设置FieldsPerRecord为-1
reader.FieldsPerRecord = -1
// 读取文件中所有行保存到slice中
records, err := reader.ReadAll()
if err != nil {
panic(err)
}
var tasks []*ServerConfig
// 将每一行数据保存到内存slice中
for _, item := range records {
tcpPort, _ := strconv.Atoi(item[0])
Start, _ := strconv.Atoi(item[7])
post := &ServerConfig{
TcpPort: tcpPort,
Mode: item[1],
Target: item[2],
VerifyKey: item[3],
U: item[4],
P: item[5],
Compress: item[6],
Start: Start,
Crypt: GetBoolByStr(item[8]),
Mux: GetBoolByStr(item[9]),
CompressEncode: GetIntNoerrByStr(item[10]),
CompressDecode: GetIntNoerrByStr(item[11]),
}
tasks = append(tasks, post)
}
s.Tasks = tasks
}
func (s *Csv) StoreHostToCsv() {
// 创建文件
csvFile, err := os.Create(s.Path + "hosts.csv")
if err != nil {
panic(err)
}
defer csvFile.Close()
// 获取csv的Writer
writer := csv.NewWriter(csvFile)
// 将map中的Post转换成slice因为csv的Write需要slice参数
// 并写入csv文件
for _, host := range s.Hosts {
record := []string{
host.Host,
host.Target,
host.Vkey,
}
err1 := writer.Write(record)
if err1 != nil {
panic(err1)
}
}
// 确保所有内存数据刷到csv文件
writer.Flush()
}
func (s *Csv) LoadHostFromCsv() {
// 打开文件
file, err := os.Open(beego.AppPath + "/conf/hosts.csv")
if err != nil {
panic(err)
}
defer file.Close()
// 获取csv的reader
reader := csv.NewReader(file)
// 设置FieldsPerRecord为-1
reader.FieldsPerRecord = -1
// 读取文件中所有行保存到slice中
records, err := reader.ReadAll()
if err != nil {
panic(err)
}
var hosts []*HostList
// 将每一行数据保存到内存slice中
for _, item := range records {
post := &HostList{
Vkey: item[2],
Host: item[0],
Target: item[1],
}
hosts = append(hosts, post)
}
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()
}
func (s *Csv) UpdateTask(t *ServerConfig) error {
for k, v := range s.Tasks {
if v.VerifyKey == t.VerifyKey {
s.Tasks = append(s.Tasks[:k], s.Tasks[k+1:]...)
s.Tasks = append(s.Tasks, t)
s.StoreTasksToCsv()
return nil
}
}
//TODO:待测试
return errors.New("不存在")
}
func (s *Csv) AddRunList(vKey string, svr interface{}) {
s.RunList[vKey] = svr
}
func (s *Csv) DelRunList(vKey string) {
delete(s.RunList, vKey)
}
func (s *Csv) DelTask(vKey string) error {
for k, v := range s.Tasks {
if v.VerifyKey == vKey {
s.Tasks = append(s.Tasks[:k], s.Tasks[k+1:]...)
s.StoreTasksToCsv()
return nil
}
}
return errors.New("不存在")
}
func (s *Csv) GetTask(vKey string) (v *ServerConfig, err error) {
for _, v = range s.Tasks {
if v.VerifyKey == vKey {
return
}
}
err = errors.New("未找到")
return
}
func (s *Csv) DelHost(host string) error {
for k, v := range s.Hosts {
if v.Host == host {
s.Hosts = append(s.Hosts[:k], s.Hosts[k+1:]...)
s.StoreHostToCsv()
return nil
}
}
return errors.New("不存在")
}
func (s *Csv) NewHost(t *HostList) {
s.Hosts = append(s.Hosts, t)
s.StoreHostToCsv()
}
func (s *Csv) GetHostList(start, length int, vKey string) ([]*HostList, int) {
list := make([]*HostList, 0)
var cnt int
for _, v := range s.Hosts {
if v.Vkey == vKey {
cnt++
if start--; start < 0 {
if length--; length > 0 {
list = append(list, v)
}
}
}
}
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
}

View File

@@ -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
}

View File

@@ -1,321 +0,0 @@
package lib
import (
"encoding/binary"
"errors"
"io"
"log"
"net"
"strconv"
"strings"
)
const (
ipV4 = 1
domainName = 3
ipV6 = 4
connectMethod = 1
bindMethod = 2
associateMethod = 3
// The maximum packet size of any udp Associate packet, based on ethernet's max size,
// minus the IP and UDP headers. IPv4 has a 20 byte header, UDP adds an
// additional 4 bytes. This is a total overhead of 24 bytes. Ethernet's
// max packet size is 1500 bytes, 1500 - 24 = 1476.
maxUDPPacketSize = 1476
)
const (
succeeded uint8 = iota
serverFailure
notAllowed
networkUnreachable
hostUnreachable
connectionRefused
ttlExpired
commandNotSupported
addrTypeNotSupported
)
const (
UserPassAuth = uint8(2)
userAuthVersion = uint8(1)
authSuccess = uint8(0)
authFailure = uint8(1)
)
type Sock5ModeServer struct {
bridge *Tunnel
isVerify bool
listener net.Listener
config *ServerConfig
}
//req
func (s *Sock5ModeServer) handleRequest(c net.Conn) {
/*
The SOCKS request is formed as follows:
+----+-----+-------+------+----------+----------+
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+
*/
header := make([]byte, 3)
_, err := io.ReadFull(c, header)
if err != nil {
log.Println("illegal request", err)
c.Close()
return
}
switch header[1] {
case connectMethod:
s.handleConnect(c)
case bindMethod:
s.handleBind(c)
case associateMethod:
s.handleUDP(c)
default:
s.sendReply(c, commandNotSupported)
c.Close()
}
}
//reply
func (s *Sock5ModeServer) sendReply(c net.Conn, rep uint8) {
reply := []byte{
5,
rep,
0,
1,
}
localAddr := c.LocalAddr().String()
localHost, localPort, _ := net.SplitHostPort(localAddr)
ipBytes := net.ParseIP(localHost).To4()
nPort, _ := strconv.Atoi(localPort)
reply = append(reply, ipBytes...)
portBytes := make([]byte, 2)
binary.BigEndian.PutUint16(portBytes, uint16(nPort))
reply = append(reply, portBytes...)
c.Write(reply)
}
//do conn
func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *Conn, err error) {
addrType := make([]byte, 1)
c.Read(addrType)
var host string
switch addrType[0] {
case ipV4:
ipv4 := make(net.IP, net.IPv4len)
c.Read(ipv4)
host = ipv4.String()
case ipV6:
ipv6 := make(net.IP, net.IPv6len)
c.Read(ipv6)
host = ipv6.String()
case domainName:
var domainLen uint8
binary.Read(c, binary.BigEndian, &domainLen)
domain := make([]byte, domainLen)
c.Read(domain)
host = string(domain)
default:
s.sendReply(c, addrTypeNotSupported)
err = errors.New("Address type not supported")
return nil, err
}
var port uint16
binary.Read(c, binary.BigEndian, &port)
// connect to host
addr := net.JoinHostPort(host, strconv.Itoa(int(port)))
client, err := s.bridge.GetTunnel(getverifyval(s.config.VerifyKey), s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
if err != nil {
log.Println(err)
return
}
s.sendReply(c, succeeded)
var ltype string
if command == associateMethod {
ltype = CONN_UDP
} else {
ltype = CONN_TCP
}
_, err = client.WriteHost(ltype, addr)
var flag string
if flag, err = client.ReadFlag(); err == nil {
if flag != CONN_SUCCESS {
err = errors.New("conn failed")
}
}
return client, err
}
//conn
func (s *Sock5ModeServer) handleConnect(c net.Conn) {
proxyConn, err := s.doConnect(c, connectMethod)
defer func() {
if s.config.Mux {
s.bridge.ReturnTunnel(proxyConn, getverifyval(s.config.VerifyKey))
}
}()
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)
}
}
// passive mode
func (s *Sock5ModeServer) handleBind(c net.Conn) {
}
//udp
func (s *Sock5ModeServer) handleUDP(c net.Conn) {
log.Println("UDP Associate")
/*
+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
+----+------+------+----------+----------+----------+
| 2 | 1 | 1 | Variable | 2 | Variable |
+----+------+------+----------+----------+----------+
*/
buf := make([]byte, 3)
c.Read(buf)
// relay udp datagram silently, without any notification to the requesting client
if buf[2] != 0 {
// does not support fragmentation, drop it
log.Println("does not support fragmentation, drop")
dummy := make([]byte, maxUDPPacketSize)
c.Read(dummy)
}
proxyConn, err := s.doConnect(c, associateMethod)
defer func() {
if s.config.Mux {
s.bridge.ReturnTunnel(proxyConn, getverifyval(s.config.VerifyKey))
}
}()
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)
}
}
//new conn
func (s *Sock5ModeServer) handleNewConn(c net.Conn) {
buf := make([]byte, 2)
if _, err := io.ReadFull(c, buf); err != nil {
log.Println("negotiation err", err)
c.Close()
return
}
if version := buf[0]; version != 5 {
log.Println("only support socks5, request from: ", c.RemoteAddr())
c.Close()
return
}
nMethods := buf[1]
methods := make([]byte, nMethods)
if len, err := c.Read(methods); len != int(nMethods) || err != nil {
log.Println("wrong method")
c.Close()
return
}
if s.isVerify {
buf[1] = UserPassAuth
c.Write(buf)
if err := s.Auth(c); err != nil {
c.Close()
log.Println("验证失败:", err)
return
}
} else {
buf[1] = 0
c.Write(buf)
}
s.handleRequest(c)
}
//socks5 auth
func (s *Sock5ModeServer) Auth(c net.Conn) error {
header := []byte{0, 0}
if _, err := io.ReadAtLeast(c, header, 2); err != nil {
return err
}
if header[0] != userAuthVersion {
return errors.New("验证方式不被支持")
}
userLen := int(header[1])
user := make([]byte, userLen)
if _, err := io.ReadAtLeast(c, user, userLen); err != nil {
return err
}
if _, err := c.Read(header[:1]); err != nil {
return errors.New("密码长度获取错误")
}
passLen := int(header[0])
pass := make([]byte, passLen)
if _, err := io.ReadAtLeast(c, pass, passLen); err != nil {
return err
}
if string(pass) == s.config.U && string(user) == s.config.P {
if _, err := c.Write([]byte{userAuthVersion, authSuccess}); err != nil {
return err
}
return nil
} else {
if _, err := c.Write([]byte{userAuthVersion, authFailure}); err != nil {
return err
}
return errors.New("验证不通过")
}
return errors.New("未知错误")
}
//start
func (s *Sock5ModeServer) Start() error {
s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.config.TcpPort))
if err != nil {
return err
}
for {
conn, err := s.listener.Accept()
if err != nil {
if strings.Contains(err.Error(), "use of closed network connection") {
break
}
log.Fatal("accept error: ", err)
}
go s.handleNewConn(conn)
}
return nil
}
//close
func (s *Sock5ModeServer) Close() error {
return s.listener.Close()
}
//new
func NewSock5ModeServer(bridge *Tunnel, cnf *ServerConfig) *Sock5ModeServer {
s := new(Sock5ModeServer)
s.bridge = bridge
s.config = cnf
if s.config.U != "" && s.config.P != "" {
s.isVerify = true
} else {
s.isVerify = false
}
return s
}

View File

@@ -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
}
//TODOhost模式的客户端无需指定和监听端口等
func NewHostServer(cnf *ServerConfig) *HostServer {
s := new(HostServer)
s.config = cnf
return s
}
//close
func (s *HostServer) Close() error {
return nil
}

View File

@@ -1,81 +0,0 @@
package lib
import (
"io"
"log"
"net"
"strings"
)
type UdpModeServer struct {
bridge *Tunnel
listener *net.UDPConn
udpMap map[string]*Conn
config *ServerConfig
}
func NewUdpModeServer(bridge *Tunnel, cnf *ServerConfig) *UdpModeServer {
s := new(UdpModeServer)
s.bridge = bridge
s.udpMap = make(map[string]*Conn)
s.config = cnf
return s
}
//开始
func (s *UdpModeServer) Start() error {
s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.config.TcpPort, ""})
if err != nil {
return err
}
data := make([]byte, 1472) //udp数据包大小
for {
n, addr, err := s.listener.ReadFromUDP(data)
if err != nil {
if strings.Contains(err.Error(), "use of closed network connection") {
break
}
continue
}
go s.process(addr, data[:n])
}
return nil
}
//TODO:效率问题有待解决
func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
conn, err := s.bridge.GetTunnel(getverifyval(s.config.VerifyKey), s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, s.config.Mux)
if err != nil {
log.Println(err)
return
}
if _, err := conn.WriteHost(CONN_UDP, s.config.Target); err != nil {
conn.Close()
return
}
if flag, err := conn.ReadFlag(); err == nil {
defer func() {
if s.config.Mux {
s.bridge.ReturnTunnel(conn, getverifyval(s.config.VerifyKey))
} else {
conn.Close()
}
}()
if flag == 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)))
n, err := conn.ReadFrom(buf, s.config.CompressDecode, s.config.Crypt)
if err != nil || err == io.EOF {
log.Println("revieve error:", err)
return
}
s.listener.WriteToUDP(buf[:n], addr)
conn.WriteTo([]byte(IO_EOF), s.config.CompressEncode, s.config.Crypt)
}
}
}
func (s *UdpModeServer) Close() error {
return s.listener.Close()
}

View File

@@ -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{})
}