From 1d89e7dae285f63b213f50f41049d6db3fce773e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B2=B3?= Date: Thu, 3 Jan 2019 01:44:45 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=AF=86=E4=BC=A0=E8=BE=93=EF=BC=8C?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf/app.conf | 12 +- conf/tasks.csv | 9 +- controllers/index.go | 2 + lib/client.go | 13 +- lib/conn.go | 207 ++++++++++++++++++--------- lib/crypt.go | 86 ++++++++++++ lib/file.go | 318 ++++++++++++++++++++++++++++++++++++++++++ lib/init.go | 30 ++-- lib/server.go | 34 +++-- lib/sock5.go | 14 +- lib/tunnel.go | 4 +- lib/udp.go | 6 +- lib/util.go | 165 +++++++++++----------- views/index/add.html | 8 +- views/index/edit.html | 13 +- views/index/list.html | 12 ++ 16 files changed, 725 insertions(+), 208 deletions(-) create mode 100644 lib/crypt.go create mode 100644 lib/file.go diff --git a/conf/app.conf b/conf/app.conf index 8005a66..8da3d29 100755 --- a/conf/app.conf +++ b/conf/app.conf @@ -1,12 +1,20 @@ appname = httpMonitor + #web管理端口 httpport = 8080 + #启动模式dev|pro runmode = dev + #web管理密码 password=123 + #http监听端口 hostPort=8028 -#basic auth认证用户名和密码 + +#basic auth认证用户名和密码,为空则不验证 auth.user=test -auth.password=1234 \ No newline at end of file +auth.password=1234 + +#是否加密传输(0|1) +crypt=1 \ No newline at end of file diff --git a/conf/tasks.csv b/conf/tasks.csv index 6666df6..4c19909 100644 --- a/conf/tasks.csv +++ b/conf/tasks.csv @@ -1,8 +1 @@ -8021,tunnelServer,10.1.50.203:80,um80bbyvcaiw7n17,,,,1 -8001,tunnelServer,10.1.50.101:22,h8vcpciko9lczxmb,,,gzip,0 -8022,tunnelServer,10.1.50.196:4000,vcerzo01q16cdn9n,,,snappy,1 -8002,udpServer,10.1.50.102:53,zcbsx5kp53cg5yqv,,,,0 -8003,sock5Server,,9mq856pqq3jq05qv,,,snappy,1 -8010,sock5Server,,0aj2xfec0mbkann5,test,test,gzip,0 -8004,httpProxyServer,,y72zj8t074lslln0,,,gzip,0 -0,hostServer,,o2430bnq22jgnmcl,,,,1 +8001,tunnelServer,10.1.50.196:4000,jq5i7n0sjs1h0jje,,,,1,1 diff --git a/controllers/index.go b/controllers/index.go index 255cd79..903c630 100755 --- a/controllers/index.go +++ b/controllers/index.go @@ -64,6 +64,7 @@ func (s *IndexController) Add() { U: s.GetString("u"), P: s.GetString("p"), Compress: s.GetString("compress"), + Crypt: s.GetString("crypt"), IsRun: 0, } lib.CsvDb.NewTask(t) @@ -96,6 +97,7 @@ func (s *IndexController) Edit() { t.U = s.GetString("u") t.P = s.GetString("p") t.Compress = s.GetString("compress") + t.Crypt = s.GetString("crypt") lib.CsvDb.UpdateTask(t) lib.StopServer(t.VerifyKey) lib.StartTask(t.VerifyKey) diff --git a/lib/client.go b/lib/client.go index 4a414f9..e7b5e7a 100755 --- a/lib/client.go +++ b/lib/client.go @@ -86,10 +86,12 @@ func (s *TRPClient) dealChan() error { //创建一个tcp连接 conn, err := net.Dial("tcp", s.svrAddr) if err != nil { + log.Println("connect to ", s.svrAddr, "error:", err) return err } //验证 if _, err := conn.Write([]byte(getverifyval(s.vKey))); err != nil { + log.Println("connect to ", s.svrAddr, "error:", err) return err } //默认长连接保持 @@ -98,25 +100,26 @@ func (s *TRPClient) dealChan() error { //写标志 c.wChan() //获取连接的host type(tcp or udp) - typeStr, host, en, de, err := c.GetHostFromConn() + typeStr, host, en, de, crypt, err := c.GetHostFromConn() if err != nil { + log.Println("get host info error:", err) return err } //与目标建立连接 server, err := net.Dial(typeStr, host) if err != nil { - log.Println(err) + log.Println("connect to ", host, "error:", err) return err } - go relay(NewConn(server), c, de) - relay(c, NewConn(server), en) + go relay(NewConn(server), c, de, crypt) + relay(c, NewConn(server), en, crypt) return nil } //http模式处理 func (s *TRPClient) dealHttp(c *Conn) error { buf := make([]byte, 1024*32) - en, de := c.GetCompressTypeFromConn() + en, de, _ := c.GetConnInfoFromConn() n, err := c.ReadFromCompress(buf, de) if err != nil { c.wError() diff --git a/lib/conn.go b/lib/conn.go index 6eb2900..683012c 100755 --- a/lib/conn.go +++ b/lib/conn.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "github.com/golang/snappy" - "io" "log" "net" "net/http" @@ -18,20 +17,76 @@ import ( "time" ) -type SnappyConn struct { - w *snappy.Writer - r *snappy.Reader +type CryptConn struct { + conn net.Conn + crypt bool } -func NewSnappyConn(conn net.Conn) *SnappyConn { +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) { + if s.crypt { + 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 bs, err = AesDecrypt(buf, []byte(cryptKey)); err != nil { + return + } + n = len(bs) + copy(b, bs) + return + } + return s.conn.Read(b) +} + +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 } func (s *SnappyConn) Write(b []byte) (n int, err error) { - if n, err = s.w.Write(b); err != nil { + 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() @@ -39,25 +94,42 @@ func (s *SnappyConn) Write(b []byte) (n int, err error) { } func (s *SnappyConn) Read(b []byte) (n int, err error) { - return s.r.Read(b) + 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 GzipConn struct { - w *gzip.Writer - r *gzip.Reader + w *gzip.Writer + r *gzip.Reader + crypt bool } -func NewGzipConn(conn net.Conn) *GzipConn { +func NewGzipConn(conn net.Conn, crypt bool) *GzipConn { c := new(GzipConn) + c.crypt = crypt c.w = gzip.NewWriter(conn) c.r, err = gzip.NewReader(conn) + fmt.Println("err", err) + //错误处理 return c } func (s *GzipConn) Write(b []byte) (n int, err error) { - if n, err = s.w.Write(b); err != nil || err == io.EOF { - err = s.w.Flush() - s.w.Close() + fmt.Println(string(b)) + if n, err = s.w.Write(b); err != nil { + //err = s.w.Flush() + //s.w.Close() return } err = s.w.Flush() @@ -65,7 +137,20 @@ func (s *GzipConn) Write(b []byte) (n int, err error) { } func (s *GzipConn) Read(b []byte) (n int, err error) { - return s.r.Read(b) + fmt.Println("read") + 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 { @@ -80,72 +165,49 @@ func NewConn(conn net.Conn) *Conn { //读取指定内容长度 func (s *Conn) ReadLen(len int) ([]byte, error) { - raw := make([]byte, 0) - buff := make([]byte, 1024) - c := 0 - for { - clen, err := s.Read(buff) - if err != nil && err != io.EOF { - return raw, err - } - raw = append(raw, buff[:clen]...) - if c += clen; c >= len { - break - } + buf := make([]byte, len) + if n, err := s.Read(buf); err != nil || n != len { + return buf, errors.New("读取指定长度错误" + err.Error()) } - if c != len { - return raw, errors.New(fmt.Sprintf("已读取长度错误,已读取%dbyte,需要读取%dbyte。", c, len)) - } - return raw, nil + return buf, nil } //获取长度 func (s *Conn) GetLen() (int, error) { val := make([]byte, 4) - _, err := s.Read(val) - if err != nil { + if _, err := s.Read(val); err != nil { return 0, err } - nlen := binary.LittleEndian.Uint32(val) - if nlen <= 0 { - return 0, errors.New("数据长度错误") - } - return int(nlen), nil + return GetLenByBytes(val) } //写入长度 func (s *Conn) WriteLen(buf []byte) (int, error) { - raw := bytes.NewBuffer([]byte{}) - if err := binary.Write(raw, binary.LittleEndian, int32(len(buf))); err != nil { - log.Println(err) + var b []byte + if b, err = GetLenBytes(buf); err != nil { return 0, err } - if err = binary.Write(raw, binary.LittleEndian, buf); err != nil { - log.Println(err) - return 0, err - } - return s.Write(raw.Bytes()) + return s.Write(b) } //读取flag func (s *Conn) ReadFlag() (string, error) { val := make([]byte, 4) - _, err := s.Read(val) - if err != nil { + if _, err := s.Read(val); err != nil { return "", err } return string(val), err } //读取host 连接地址 压缩类型 -func (s *Conn) GetHostFromConn() (typeStr string, host string, en, de int, err error) { +func (s *Conn) GetHostFromConn() (typeStr string, host string, en, de int, crypt bool, err error) { retry: ltype := make([]byte, 3) if _, err = s.Read(ltype); err != nil { return } if typeStr = string(ltype); typeStr == TEST_FLAG { - en, de = s.GetCompressTypeFromConn() + en, de, crypt = s.GetConnInfoFromConn() goto retry } len, err := s.GetLen() @@ -209,16 +271,10 @@ func (s *Conn) GetHost() (method, address string, rb []byte, err error, r *http. //压缩方式读 func (s *Conn) ReadFromCompress(b []byte, compress int) (int, error) { switch compress { - case COMPRESS_GZIP_DECODE: - r, err := gzip.NewReader(s) - if err != nil { - return 0, err - } - return r.Read(b) case COMPRESS_SNAPY_DECODE: r := snappy.NewReader(s) return r.Read(b) - case COMPRESS_NONE: + default: return s.Read(b) } return 0, nil @@ -227,35 +283,30 @@ func (s *Conn) ReadFromCompress(b []byte, compress int) (int, error) { //压缩方式写 func (s *Conn) WriteCompress(b []byte, compress int) (n int, err error) { switch compress { - case COMPRESS_GZIP_ENCODE: - w := gzip.NewWriter(s) - if n, err = w.Write(b); err == nil { - w.Flush() - } - err = w.Close() case COMPRESS_SNAPY_ENCODE: w := snappy.NewBufferedWriter(s) if n, err = w.Write(b); err == nil { w.Flush() } err = w.Close() - case COMPRESS_NONE: + default: n, err = s.Write(b) } return } //写压缩方式 -func (s *Conn) WriteCompressType(en, de int) { - s.Write([]byte(strconv.Itoa(en) + strconv.Itoa(de))) +func (s *Conn) WriteConnInfo(en, de int, crypt bool) { + s.Write([]byte(strconv.Itoa(en) + strconv.Itoa(de) + GetStrByBool(crypt))) } //获取压缩方式 -func (s *Conn) GetCompressTypeFromConn() (en, de int) { - buf := make([]byte, 2) +func (s *Conn) GetConnInfoFromConn() (en, de int, crypt bool) { + buf := make([]byte, 3) s.Read(buf) en, _ = strconv.Atoi(string(buf[0])) de, _ = strconv.Atoi(string(buf[1])) + crypt = GetBoolByStr(string(buf[2])) return } @@ -290,3 +341,25 @@ func (s *Conn) wChan() (int, error) { func (s *Conn) wTest() (int, error) { return s.Write([]byte(TEST_FLAG)) } + +//获取长度+内容 +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 +} diff --git a/lib/crypt.go b/lib/crypt.go new file mode 100644 index 0000000..7e6a19d --- /dev/null +++ b/lib/crypt.go @@ -0,0 +1,86 @@ +package lib + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/md5" + "encoding/hex" + "math/rand" + "time" +) + +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 +} + +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) + origData = PKCS5UnPadding(origData) + // origData = ZeroUnPadding(origData) + return origData, nil +} + +func ZeroPadding(ciphertext []byte, blockSize int) []byte { + padding := blockSize - len(ciphertext)%blockSize + padtext := bytes.Repeat([]byte{0}, padding) + return append(ciphertext, padtext...) +} + +func ZeroUnPadding(origData []byte) []byte { + length := len(origData) + unpadding := int(origData[length-1]) + return origData[:(length - unpadding)] +} + +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) []byte { + length := len(origData) + // 去掉最后一个字节 unpadding 次 + unpadding := int(origData[length-1]) + return 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) +} diff --git a/lib/file.go b/lib/file.go new file mode 100644 index 0000000..82448f8 --- /dev/null +++ b/lib/file.go @@ -0,0 +1,318 @@ +package lib + +import ( + "encoding/csv" + "encoding/json" + "errors" + "io/ioutil" + "log" + "os" + "strconv" +) + +type TaskList struct { + TcpPort int //服务端与客户端通信端口 + Mode string //启动方式 + Target string //目标 + VerifyKey string //flag + U string //socks5验证用户名 + P string //socks5验证密码 + Compress string //压缩方式 + Start int //是否开启 + IsRun int //是否在运行 + ClientStatus int //客户端状态 + Crypt string //是否加密 +} + +type HostList struct { + Vkey string //服务端与客户端通信端口 + Host string //启动方式 + Target string //目标 +} + +func NewCsv(path string, bridge *Tunnel, runList map[string]interface{}) *Csv { + c := new(Csv) + c.Path = path + c.Bridge = bridge + c.RunList = runList + return c +} + +type Csv struct { + Tasks []*TaskList + 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(s.Path + "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), + task.Crypt, + } + err := writer.Write(record) + if err != nil { + log.Fatalf(err.Error()) + } + } + writer.Flush() +} + +func (s *Csv) LoadTaskFromCsv() { + // 打开文件 + file, err := os.Open(s.Path + "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 []*TaskList + // 将每一行数据保存到内存slice中 + for _, item := range records { + tcpPort, _ := strconv.Atoi(item[0]) + Start, _ := strconv.Atoi(item[7]) + post := &TaskList{ + TcpPort: tcpPort, + Mode: item[1], + Target: item[2], + VerifyKey: item[3], + U: item[4], + P: item[5], + Compress: item[6], + Start: Start, + Crypt: item[8], + } + 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(s.Path + "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) GetTaskList(start, length int, typeVal string) ([]*TaskList, int) { + list := make([]*TaskList, 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 *TaskList) { + s.Tasks = append(s.Tasks, t) + s.StoreTasksToCsv() +} + +func (s *Csv) UpdateTask(t *TaskList) 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 *TaskList, 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 +} diff --git a/lib/init.go b/lib/init.go index b3fcc7a..2ba97f2 100644 --- a/lib/init.go +++ b/lib/init.go @@ -21,13 +21,17 @@ var ( p = flag.String("p", "", "socks5验证密码") compress = flag.String("compress", "", "数据压缩方式(gzip|snappy)") serverAddr = flag.String("server", "", "服务器地址ip:端口") + crypt = flag.String("crypt", "", "是否加密(1|0)") config Config err error RunList map[string]interface{} //运行中的任务 bridge *Tunnel CsvDb *Csv + //crypt = GetBoolNoErrFromConfig("crypt") ) +const cryptKey = "1234567812345678" + func init() { RunList = make(map[string]interface{}) } @@ -52,7 +56,7 @@ func InitMode() { log.Fatalln("服务端开启失败", err) } log.Println("服务端启动,监听tcp服务端端口:", *TcpPort) - if svr := newMode(*rpMode, bridge, *httpPort, *tunnelTarget, *u, *p, en, de, *verifyKey); svr != nil { + if svr := newMode(*rpMode, bridge, *httpPort, *tunnelTarget, *u, *p, en, de, *verifyKey, *crypt); svr != nil { reflect.ValueOf(svr).MethodByName("Start").Call(nil) } else { log.Fatalln("启动模式不正确") @@ -71,29 +75,33 @@ func InitFromCsv() { } } -func newMode(mode string, bridge *Tunnel, httpPort int, tunnelTarget string, u string, p string, enCompress int, deCompress int, vkey string) interface{} { - if u == "" || p == "" { //如果web管理中设置了用户名和密码,则覆盖配置文件 +func newMode(mode string, bridge *Tunnel, httpPort int, tunnelTarget string, u string, p string, enCompress int, deCompress int, vkey string, crypt string) interface{} { + if u == "" || p == "" { //如果web管理或者命令中设置了用户名和密码,则覆盖配置文件 u = beego.AppConfig.String("auth.user") p = beego.AppConfig.String("auth.password") } + if crypt == "" { //如果web管理或者命令中设置了是否加密,则覆盖配置文件 + crypt = beego.AppConfig.String("crypt") + } + bCrypt := GetBoolByStr(crypt) switch mode { case "httpServer": - return NewHttpModeServer(httpPort, bridge, enCompress, deCompress, vkey) + return NewHttpModeServer(httpPort, bridge, enCompress, deCompress, vkey, bCrypt) case "tunnelServer": - return NewTunnelModeServer(httpPort, tunnelTarget, ProcessTunnel, bridge, enCompress, deCompress, vkey, u, p) + return NewTunnelModeServer(httpPort, tunnelTarget, ProcessTunnel, bridge, enCompress, deCompress, vkey, u, p, bCrypt) case "sock5Server": - return NewSock5ModeServer(httpPort, u, p, bridge, enCompress, deCompress, vkey) + return NewSock5ModeServer(httpPort, u, p, bridge, enCompress, deCompress, vkey, bCrypt) case "httpProxyServer": - return NewTunnelModeServer(httpPort, tunnelTarget, ProcessHttp, bridge, enCompress, deCompress, vkey, u, p) + return NewTunnelModeServer(httpPort, tunnelTarget, ProcessHttp, bridge, enCompress, deCompress, vkey, u, p, bCrypt) case "udpServer": - return NewUdpModeServer(httpPort, tunnelTarget, bridge, enCompress, deCompress, vkey) + return NewUdpModeServer(httpPort, tunnelTarget, bridge, enCompress, deCompress, vkey, bCrypt) case "webServer": InitCsvDb() return NewWebServer(bridge) case "hostServer": - return NewHostServer() + return NewHostServer(bCrypt) case "httpHostServer": - return NewTunnelModeServer(httpPort, tunnelTarget, ProcessHost, bridge, enCompress, deCompress, vkey, u, p) + return NewTunnelModeServer(httpPort, tunnelTarget, ProcessHost, bridge, enCompress, deCompress, vkey, u, p, bCrypt) } return nil } @@ -119,7 +127,7 @@ func StopServer(cFlag string) error { func AddTask(t *TaskList) error { de, en := getCompressType(t.Compress) - if svr := newMode(t.Mode, bridge, t.TcpPort, t.Target, t.U, t.P, en, de, t.VerifyKey); svr != nil { + if svr := newMode(t.Mode, bridge, t.TcpPort, t.Target, t.U, t.P, en, de, t.VerifyKey, t.Crypt); svr != nil { RunList[t.VerifyKey] = svr go func() { err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0] diff --git a/lib/server.go b/lib/server.go index a5fc785..3bb3f2b 100755 --- a/lib/server.go +++ b/lib/server.go @@ -36,15 +36,17 @@ type HttpModeServer struct { enCompress int deCompress int vKey string + crypt bool } -func NewHttpModeServer(httpPort int, bridge *Tunnel, enCompress int, deCompress int, vKey string) *HttpModeServer { +func NewHttpModeServer(httpPort int, bridge *Tunnel, enCompress int, deCompress int, vKey string, crypt bool) *HttpModeServer { s := new(HttpModeServer) s.bridge = bridge s.httpPort = httpPort s.enCompress = enCompress s.deCompress = deCompress s.vKey = vKey + s.crypt = crypt return s } @@ -90,7 +92,7 @@ func (s *HttpModeServer) writeRequest(r *http.Request, conn *Conn) error { return err } conn.wSign() - conn.WriteCompressType(s.enCompress, s.deCompress) + conn.WriteConnInfo(s.enCompress, s.deCompress, s.crypt) c, err := conn.WriteCompress(raw, s.enCompress) if err != nil { return err @@ -152,9 +154,10 @@ type TunnelModeServer struct { basicUser string basicPassword string vKey string + crypt bool } -func NewTunnelModeServer(httpPort int, tunnelTarget string, process process, bridge *Tunnel, enCompress, deCompress int, vKey, basicUser, basicPasswd string) *TunnelModeServer { +func NewTunnelModeServer(httpPort int, tunnelTarget string, process process, bridge *Tunnel, enCompress, deCompress int, vKey, basicUser, basicPasswd string, crypt bool) *TunnelModeServer { s := new(TunnelModeServer) s.httpPort = httpPort s.bridge = bridge @@ -165,6 +168,7 @@ func NewTunnelModeServer(httpPort int, tunnelTarget string, process process, bri s.vKey = vKey s.basicUser = basicUser s.basicPassword = basicPasswd + s.crypt = crypt return s } @@ -202,7 +206,7 @@ func (s *TunnelModeServer) Close() error { //tcp隧道模式 func ProcessTunnel(c *Conn, s *TunnelModeServer) error { - link, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress) + link, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress, s.crypt) if err != nil { log.Println(err) c.Close() @@ -214,8 +218,8 @@ func ProcessTunnel(c *Conn, s *TunnelModeServer) error { log.Println(err) return err } - go relay(link, c, s.enCompress) - relay(c, link, s.deCompress) + go relay(link, c, s.enCompress, s.crypt) + relay(c, link, s.deCompress, s.crypt) return nil } @@ -229,7 +233,7 @@ func ProcessHttp(c *Conn, s *TunnelModeServer) error { if err := s.auth(r, c); err != nil { return err } - link, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress) + link, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress, s.crypt) if err != nil { log.Println(err) c.Close() @@ -246,8 +250,8 @@ func ProcessHttp(c *Conn, s *TunnelModeServer) error { } else { link.WriteCompress(rb, s.enCompress) } - go relay(link, c, s.enCompress) - relay(c, link, s.deCompress) + go relay(link, c, s.enCompress, s.crypt) + relay(c, link, s.deCompress, s.crypt) return nil } @@ -267,7 +271,7 @@ func ProcessHost(c *Conn, s *TunnelModeServer) error { return err } de, en := getCompressType(task.Compress) - link, err := s.bridge.GetTunnel(getverifyval(host.Vkey), en, de) + link, err := s.bridge.GetTunnel(getverifyval(host.Vkey), en, de, s.crypt) if err != nil { log.Println(err) c.Close() @@ -284,8 +288,8 @@ func ProcessHost(c *Conn, s *TunnelModeServer) error { } else { link.WriteCompress(rb, en) } - go relay(link, c, en) - relay(c, link, de) + go relay(link, c, en, s.crypt) + relay(c, link, de, s.crypt) return nil } @@ -324,6 +328,7 @@ func NewWebServer(bridge *Tunnel) *WebServer { //host type HostServer struct { + crypt bool } //开始 @@ -331,9 +336,10 @@ func (s *HostServer) Start() error { return nil } -//TODO:host模式的客户端,无需指定和监听端口等,此处有待优化 -func NewHostServer() *HostServer { +//TODO:host模式的客户端,无需指定和监听端口等 +func NewHostServer(crypt bool) *HostServer { s := new(HostServer) + s.crypt = crypt return s } diff --git a/lib/sock5.go b/lib/sock5.go index 4427dce..da58b48 100755 --- a/lib/sock5.go +++ b/lib/sock5.go @@ -53,6 +53,7 @@ type Sock5ModeServer struct { isVerify bool listener net.Listener vKey string + crypt bool } func (s *Sock5ModeServer) handleRequest(c net.Conn) { @@ -136,7 +137,7 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *Conn, binary.Read(c, binary.BigEndian, &port) // connect to host addr := net.JoinHostPort(host, strconv.Itoa(int(port))) - client, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress) + client, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress, s.crypt) if err != nil { log.Println(err) client.Close() @@ -159,8 +160,8 @@ func (s *Sock5ModeServer) handleConnect(c net.Conn) { log.Println(err) c.Close() } else { - go relay(proxyConn, NewConn(c), s.enCompress) - go relay(NewConn(c), proxyConn, s.deCompress) + go relay(proxyConn, NewConn(c), s.enCompress, s.crypt) + go relay(NewConn(c), proxyConn, s.deCompress, s.crypt) } } @@ -192,8 +193,8 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) { if err != nil { c.Close() } else { - go relay(proxyConn, NewConn(c), s.enCompress) - go relay(NewConn(c), proxyConn, s.deCompress) + go relay(proxyConn, NewConn(c), s.enCompress, s.crypt) + go relay(NewConn(c), proxyConn, s.deCompress, s.crypt) } } @@ -290,7 +291,7 @@ func (s *Sock5ModeServer) Close() error { return s.listener.Close() } -func NewSock5ModeServer(httpPort int, u, p string, brige *Tunnel, enCompress int, deCompress int, vKey string) *Sock5ModeServer { +func NewSock5ModeServer(httpPort int, u, p string, brige *Tunnel, enCompress int, deCompress int, vKey string, crypt bool) *Sock5ModeServer { s := new(Sock5ModeServer) s.httpPort = httpPort s.bridge = brige @@ -304,5 +305,6 @@ func NewSock5ModeServer(httpPort int, u, p string, brige *Tunnel, enCompress int s.enCompress = enCompress s.deCompress = deCompress s.vKey = vKey + s.crypt = crypt return s } diff --git a/lib/tunnel.go b/lib/tunnel.go index 4107442..959805e 100755 --- a/lib/tunnel.go +++ b/lib/tunnel.go @@ -141,7 +141,7 @@ retry: } //得到一个tcp隧道 -func (s *Tunnel) GetTunnel(cFlag string, en, de int) (c *Conn, err error) { +func (s *Tunnel) GetTunnel(cFlag string, en, de int, crypt bool) (c *Conn, err error) { if v, ok := s.tunnelList[cFlag]; !ok || v.Len() < 10 { //新建通道 go s.newChan(cFlag) } @@ -154,7 +154,7 @@ retry: c.Close() goto retry } - c.WriteCompressType(en, de) + c.WriteConnInfo(en, de, crypt) return } diff --git a/lib/udp.go b/lib/udp.go index 16156ce..aefad6b 100755 --- a/lib/udp.go +++ b/lib/udp.go @@ -18,9 +18,10 @@ type UdpModeServer struct { enCompress int deCompress int vKey string + crypt bool } -func NewUdpModeServer(udpPort int, tunnelTarget string, bridge *Tunnel, enCompress int, deCompress int, vKey string) *UdpModeServer { +func NewUdpModeServer(udpPort int, tunnelTarget string, bridge *Tunnel, enCompress int, deCompress int, vKey string, crypt bool) *UdpModeServer { s := new(UdpModeServer) s.udpPort = udpPort s.tunnelTarget = tunnelTarget @@ -29,6 +30,7 @@ func NewUdpModeServer(udpPort int, tunnelTarget string, bridge *Tunnel, enCompre s.enCompress = enCompress s.deCompress = deCompress s.vKey = vKey + s.crypt = crypt return s } @@ -57,7 +59,7 @@ func (s *UdpModeServer) Start() error { func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) { fmt.Println(addr.String()) fmt.Println(string(data)) - conn, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress) + conn, err := s.bridge.GetTunnel(getverifyval(s.vKey), s.enCompress, s.deCompress, s.crypt) if err != nil { log.Println(err) return diff --git a/lib/util.go b/lib/util.go index 2647ca4..c8051de 100755 --- a/lib/util.go +++ b/lib/util.go @@ -3,18 +3,12 @@ package lib import ( "bufio" "bytes" - "compress/gzip" - "crypto/md5" "encoding/base64" "encoding/binary" - "encoding/hex" - "encoding/json" "errors" "fmt" "io" - "io/ioutil" "log" - "math/rand" "net" "net/http" "net/http/httputil" @@ -22,19 +16,25 @@ import ( "regexp" "strconv" "strings" - "time" + "sync" ) var ( disabledRedirect = errors.New("disabled redirect.") + bufPool = &sync.Pool{ + New: func() interface{} { + return make([]byte, 32*1024) + }, + } ) +//pool 实现 +type bufType [32 * 1024]byte const ( - COMPRESS_NONE = iota + COMPRESS_NONE_ENCODE = iota + COMPRESS_NONE_DECODE COMPRESS_SNAPY_ENCODE COMPRESS_SNAPY_DECODE - COMPRESS_GZIP_ENCODE - COMPRESS_GZIP_DECODE ) func BadRequest(w http.ResponseWriter) { @@ -134,83 +134,36 @@ func replaceHost(resp []byte) []byte { return []byte(str) } -func relay(in, out *Conn, compressType int) { - buf := make([]byte, 32*1024) +func relay(in, out *Conn, compressType int, crypt bool) { + fmt.Println(crypt) switch compressType { - case COMPRESS_GZIP_ENCODE: - //TODO:GZIP压缩存在问题有待解决 - w := gzip.NewWriter(in) - for { - n, err := out.Read(buf) - if err != nil || err == io.EOF { - break - } - if _, err = w.Write(buf[:n]); err != nil { - break - } - if err = w.Flush(); err != nil { - log.Println(err) - break - } - } - w.Close() case COMPRESS_SNAPY_ENCODE: - io.Copy(NewSnappyConn(in.conn), out) - case COMPRESS_GZIP_DECODE: - io.Copy(in, NewGzipConn(out.conn)) + copyBuffer(NewSnappyConn(in.conn, crypt), out) case COMPRESS_SNAPY_DECODE: - io.Copy(in, NewSnappyConn(out.conn)) - default: - io.Copy(in, out) + copyBuffer(in, NewSnappyConn(out.conn, crypt)) + case COMPRESS_NONE_ENCODE: + copyBuffer(NewCryptConn(in.conn, crypt), out) + case COMPRESS_NONE_DECODE: + copyBuffer(in, NewCryptConn(out.conn, crypt)) } out.Close() in.Close() } -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 -} - //判断压缩方式 func getCompressType(compress string) (int, int) { switch compress { case "": - return COMPRESS_NONE, COMPRESS_NONE - case "gzip": - return COMPRESS_GZIP_DECODE, COMPRESS_GZIP_ENCODE + return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE case "snappy": return COMPRESS_SNAPY_DECODE, COMPRESS_SNAPY_ENCODE default: log.Fatalln("数据压缩格式错误") } - return COMPRESS_NONE, COMPRESS_NONE + return COMPRESS_NONE_DECODE, COMPRESS_NONE_ENCODE } -// 简单的一个校验值 +//简单的一个校验值 func getverifyval(vkey string) string { //单客户端模式 if *verifyKey != "" { @@ -219,6 +172,7 @@ func getverifyval(vkey string) string { return Md5(vkey) } +//验证 func verify(verifyKeyMd5 string) bool { if *verifyKey != "" && getverifyval(*verifyKey) == verifyKeyMd5 { return true @@ -233,6 +187,7 @@ func verify(verifyKeyMd5 string) bool { return false } +//get key by host from x func getKeyByHost(host string) (h *HostList, t *TaskList, err error) { for _, v := range CsvDb.Hosts { if strings.Contains(host, v.Host) { @@ -245,25 +200,6 @@ func getKeyByHost(host string) (h *HostList, t *TaskList, err error) { return } -//生成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) -} - //通过host获取对应的ip地址 func Gethostbyname(hostname string) string { if !DomainCheck(hostname) { @@ -310,3 +246,58 @@ func checkAuth(r *http.Request, user, passwd string) bool { } 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" +} + +// io.copy的优化版,读取buffer长度原为32*1024,与snappy不同,导致读取出的内容存在差异,不利于解密 +func copyBuffer(dst io.Writer, src io.Reader) (written int64, err error) { + // If the reader has a WriteTo method, use it to do the copy. + // Avoids an allocation and a copy. + if wt, ok := src.(io.WriterTo); ok { + return wt.WriteTo(dst) + } + // Similarly, if the writer has a ReadFrom method, use it to do the copy. + if rt, ok := dst.(io.ReaderFrom); ok { + return rt.ReadFrom(src) + } + buf := make([]byte, 65535) + 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 +} diff --git a/views/index/add.html b/views/index/add.html index fc70b30..fe3415e 100755 --- a/views/index/add.html +++ b/views/index/add.html @@ -34,10 +34,16 @@ +
+ + +
diff --git a/views/index/edit.html b/views/index/edit.html index 22b1423..00397b5 100755 --- a/views/index/edit.html +++ b/views/index/edit.html @@ -7,7 +7,7 @@
- @@ -29,10 +29,16 @@
+
+ + +