mirror of
https://github.com/ehang-io/nps.git
synced 2025-09-01 10:56:53 +00:00
目录变更
This commit is contained in:
438
lib/conn.go
Executable file
438
lib/conn.go
Executable file
@@ -0,0 +1,438 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"github.com/golang/snappy"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const cryptKey = "1234567812345678"
|
||||
|
||||
type CryptConn struct {
|
||||
conn net.Conn
|
||||
crypt bool
|
||||
rate *Rate
|
||||
}
|
||||
|
||||
func NewCryptConn(conn net.Conn, crypt bool, rate *Rate) *CryptConn {
|
||||
c := new(CryptConn)
|
||||
c.conn = conn
|
||||
c.crypt = crypt
|
||||
c.rate = rate
|
||||
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)
|
||||
if s.rate != nil {
|
||||
s.rate.Get(int64(n))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//解密读
|
||||
func (s *CryptConn) Read(b []byte) (n int, err error) {
|
||||
var lens int
|
||||
var buf []byte
|
||||
var rb []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 rb, err = AesDecrypt(buf, []byte(cryptKey)); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
rb = buf
|
||||
}
|
||||
copy(b, rb)
|
||||
n = len(rb)
|
||||
if s.rate != nil {
|
||||
s.rate.Get(int64(n))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type SnappyConn struct {
|
||||
w *snappy.Writer
|
||||
r *snappy.Reader
|
||||
crypt bool
|
||||
rate *Rate
|
||||
}
|
||||
|
||||
func NewSnappyConn(conn net.Conn, crypt bool, rate *Rate) *SnappyConn {
|
||||
c := new(SnappyConn)
|
||||
c.w = snappy.NewBufferedWriter(conn)
|
||||
c.r = snappy.NewReader(conn)
|
||||
c.crypt = crypt
|
||||
c.rate = rate
|
||||
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 {
|
||||
Println("encode crypt error:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if _, err = s.w.Write(b); err != nil {
|
||||
return
|
||||
}
|
||||
if err = s.w.Flush(); err != nil {
|
||||
return
|
||||
}
|
||||
if s.rate != nil {
|
||||
s.rate.Get(int64(n))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//snappy压缩读 包含解密
|
||||
func (s *SnappyConn) Read(b []byte) (n int, err error) {
|
||||
buf := BufPool.Get().([]byte)
|
||||
defer BufPool.Put(buf)
|
||||
if n, err = s.r.Read(buf); err != nil {
|
||||
return
|
||||
}
|
||||
var bs []byte
|
||||
if s.crypt {
|
||||
if bs, err = AesDecrypt(buf[:n], []byte(cryptKey)); err != nil {
|
||||
Println("decode crypt error:", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
bs = buf[:n]
|
||||
}
|
||||
n = len(bs)
|
||||
copy(b, bs)
|
||||
if s.rate != nil {
|
||||
s.rate.Get(int64(n))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Conn struct {
|
||||
Conn net.Conn
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
//new conn
|
||||
func NewConn(conn net.Conn) *Conn {
|
||||
c := new(Conn)
|
||||
c.Conn = conn
|
||||
return c
|
||||
}
|
||||
|
||||
//从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 {
|
||||
return
|
||||
}
|
||||
hostPortURL, err := url.Parse(r.Host)
|
||||
if err != nil {
|
||||
address = r.Host
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
if hostPortURL.Opaque == "443" { //https访问
|
||||
if strings.Index(r.Host, ":") == -1 { //host不带端口, 默认80
|
||||
address = r.Host + ":443"
|
||||
} else {
|
||||
address = r.Host
|
||||
}
|
||||
} else { //http访问
|
||||
if strings.Index(r.Host, ":") == -1 { //host不带端口, 默认80
|
||||
address = r.Host + ":80"
|
||||
} else {
|
||||
address = r.Host
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//读取指定长度内容
|
||||
func (s *Conn) ReadLen(cLen int) ([]byte, error) {
|
||||
if cLen > poolSize {
|
||||
return nil, errors.New("长度错误" + strconv.Itoa(cLen))
|
||||
}
|
||||
var buf []byte
|
||||
if cLen <= poolSizeSmall {
|
||||
buf = BufPoolSmall.Get().([]byte)[:cLen]
|
||||
defer BufPoolSmall.Put(buf)
|
||||
} else {
|
||||
buf = BufPoolMax.Get().([]byte)[:cLen]
|
||||
defer BufPoolMax.Put(buf)
|
||||
}
|
||||
if n, err := io.ReadFull(s, buf); err != nil || n != cLen {
|
||||
return buf, errors.New("读取指定长度错误" + err.Error())
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
//read length or id (content length=4)
|
||||
func (s *Conn) GetLen() (int, error) {
|
||||
val, err := s.ReadLen(4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return GetLenByBytes(val)
|
||||
}
|
||||
|
||||
//read flag
|
||||
func (s *Conn) ReadFlag() (string, error) {
|
||||
val, err := s.ReadLen(4)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(val), err
|
||||
}
|
||||
|
||||
//read connect status
|
||||
func (s *Conn) GetConnStatus() (id int, status bool, err error) {
|
||||
id, err = s.GetLen()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var b []byte
|
||||
if b, err = s.ReadLen(1); err != nil {
|
||||
return
|
||||
} else {
|
||||
status = GetBoolByStr(string(b[0]))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//设置连接为长连接
|
||||
func (s *Conn) SetAlive() {
|
||||
conn := s.Conn.(*net.TCPConn)
|
||||
conn.SetReadDeadline(time.Time{})
|
||||
conn.SetKeepAlive(true)
|
||||
conn.SetKeepAlivePeriod(time.Duration(2 * time.Second))
|
||||
}
|
||||
|
||||
//set read dead time
|
||||
func (s *Conn) SetReadDeadline(t time.Duration) {
|
||||
s.Conn.(*net.TCPConn).SetReadDeadline(time.Now().Add(time.Duration(t) * time.Second))
|
||||
}
|
||||
|
||||
//单独读(加密|压缩)
|
||||
func (s *Conn) ReadFrom(b []byte, compress int, crypt bool, rate *Rate) (int, error) {
|
||||
if COMPRESS_SNAPY_DECODE == compress {
|
||||
return NewSnappyConn(s.Conn, crypt, rate).Read(b)
|
||||
}
|
||||
return NewCryptConn(s.Conn, crypt, rate).Read(b)
|
||||
}
|
||||
|
||||
//单独写(加密|压缩)
|
||||
func (s *Conn) WriteTo(b []byte, compress int, crypt bool, rate *Rate) (n int, err error) {
|
||||
if COMPRESS_SNAPY_ENCODE == compress {
|
||||
return NewSnappyConn(s.Conn, crypt, rate).Write(b)
|
||||
}
|
||||
return NewCryptConn(s.Conn, crypt, rate).Write(b)
|
||||
}
|
||||
|
||||
//send msg
|
||||
func (s *Conn) SendMsg(content []byte, link *Link) (n int, err error) {
|
||||
/*
|
||||
The msg info is formed as follows:
|
||||
+----+--------+
|
||||
|id | content |
|
||||
+----+--------+
|
||||
| 4 | ... |
|
||||
+----+--------+
|
||||
*/
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
raw := bytes.NewBuffer([]byte{})
|
||||
binary.Write(raw, binary.LittleEndian, int32(link.Id))
|
||||
if n, err = s.Write(raw.Bytes()); err != nil {
|
||||
return
|
||||
}
|
||||
raw.Reset()
|
||||
binary.Write(raw, binary.LittleEndian, content)
|
||||
n, err = s.WriteTo(raw.Bytes(), link.En, link.Crypt, link.Rate)
|
||||
return
|
||||
}
|
||||
|
||||
//get msg content from conn
|
||||
func (s *Conn) GetMsgContent(link *Link) (content []byte, err error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
buf := BufPoolCopy.Get().([]byte)
|
||||
if n, err := s.ReadFrom(buf, link.De, link.Crypt, link.Rate); err == nil && n > 4 {
|
||||
content = buf[:n]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//send info for link
|
||||
func (s *Conn) SendLinkInfo(link *Link) (int, error) {
|
||||
/*
|
||||
The link info is formed as follows:
|
||||
+----------+------+----------+------+----------+-----+
|
||||
| id | len | type | hostlen | host | en | de |crypt |
|
||||
+----------+------+----------+------+---------+------+
|
||||
| 4 | 4 | 3 | 4 | host | 1 | 1 | 1 |
|
||||
+----------+------+----------+------+----+----+------+
|
||||
*/
|
||||
raw := bytes.NewBuffer([]byte{})
|
||||
binary.Write(raw, binary.LittleEndian, []byte(NEW_CONN))
|
||||
binary.Write(raw, binary.LittleEndian, int32(14+len(link.Host)))
|
||||
binary.Write(raw, binary.LittleEndian, int32(link.Id))
|
||||
binary.Write(raw, binary.LittleEndian, []byte(link.ConnType))
|
||||
binary.Write(raw, binary.LittleEndian, int32(len(link.Host)))
|
||||
binary.Write(raw, binary.LittleEndian, []byte(link.Host))
|
||||
binary.Write(raw, binary.LittleEndian, []byte(strconv.Itoa(link.En)))
|
||||
binary.Write(raw, binary.LittleEndian, []byte(strconv.Itoa(link.De)))
|
||||
binary.Write(raw, binary.LittleEndian, []byte(GetStrByBool(link.Crypt)))
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
return s.Write(raw.Bytes())
|
||||
}
|
||||
|
||||
func (s *Conn) GetLinkInfo() (link *Link, err error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
var hostLen, n int
|
||||
var buf []byte
|
||||
if n, err = s.GetLen(); err != nil {
|
||||
return
|
||||
}
|
||||
link = new(Link)
|
||||
if buf, err = s.ReadLen(n); err != nil {
|
||||
return
|
||||
}
|
||||
if link.Id, err = GetLenByBytes(buf[:4]); err != nil {
|
||||
return
|
||||
}
|
||||
link.ConnType = string(buf[4:7])
|
||||
if hostLen, err = GetLenByBytes(buf[7:11]); err != nil {
|
||||
return
|
||||
} else {
|
||||
link.Host = string(buf[11 : 11+hostLen])
|
||||
link.En = GetIntNoErrByStr(string(buf[11+hostLen]))
|
||||
link.De = GetIntNoErrByStr(string(buf[12+hostLen]))
|
||||
link.Crypt = GetBoolByStr(string(buf[13+hostLen]))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//write connect success
|
||||
func (s *Conn) WriteSuccess(id int) (int, error) {
|
||||
raw := bytes.NewBuffer([]byte{})
|
||||
binary.Write(raw, binary.LittleEndian, int32(id))
|
||||
binary.Write(raw, binary.LittleEndian, []byte("1"))
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
return s.Write(raw.Bytes())
|
||||
}
|
||||
|
||||
//write connect fail
|
||||
func (s *Conn) WriteFail(id int) (int, error) {
|
||||
raw := bytes.NewBuffer([]byte{})
|
||||
binary.Write(raw, binary.LittleEndian, int32(id))
|
||||
binary.Write(raw, binary.LittleEndian, []byte("0"))
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
return s.Write(raw.Bytes())
|
||||
}
|
||||
|
||||
//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) WriteError() (int, error) {
|
||||
return s.Write([]byte(RES_MSG))
|
||||
}
|
||||
|
||||
//write sign flag
|
||||
func (s *Conn) WriteSign() (int, error) {
|
||||
return s.Write([]byte(RES_SIGN))
|
||||
}
|
||||
|
||||
//write sign flag
|
||||
func (s *Conn) WriteClose() (int, error) {
|
||||
return s.Write([]byte(RES_CLOSE))
|
||||
}
|
||||
|
||||
//write main
|
||||
func (s *Conn) WriteMain() (int, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
return s.Write([]byte(WORK_MAIN))
|
||||
}
|
||||
|
||||
//write chan
|
||||
func (s *Conn) WriteChan() (int, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
return s.Write([]byte(WORK_CHAN))
|
||||
}
|
||||
|
||||
//获取长度+内容
|
||||
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
|
||||
}
|
82
lib/crypt.go
Normal file
82
lib/crypt.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"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)
|
||||
}
|
71
lib/daemon.go
Normal file
71
lib/daemon.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func InitDaemon(f string) {
|
||||
if len(os.Args) < 2 {
|
||||
return
|
||||
}
|
||||
var args []string
|
||||
args = append(args, os.Args[0])
|
||||
if len(os.Args) >= 2 {
|
||||
args = append(args, os.Args[2:]...)
|
||||
}
|
||||
args = append(args, "-log=file")
|
||||
switch os.Args[1] {
|
||||
case "start":
|
||||
start(args, f)
|
||||
os.Exit(0)
|
||||
case "stop":
|
||||
stop(f, args[0])
|
||||
os.Exit(0)
|
||||
case "restart":
|
||||
stop(f, args[0])
|
||||
start(args, f)
|
||||
os.Exit(0)
|
||||
case "install":
|
||||
InstallNps()
|
||||
}
|
||||
}
|
||||
|
||||
func start(osArgs []string, f string) {
|
||||
cmd := exec.Command(osArgs[0], osArgs[1:]...)
|
||||
cmd.Start()
|
||||
log.Println("执行启动成功")
|
||||
if cmd.Process.Pid > 0 {
|
||||
d1 := []byte(strconv.Itoa(cmd.Process.Pid))
|
||||
ioutil.WriteFile(beego.AppPath+"/"+f+".pid", d1, 0600)
|
||||
}
|
||||
}
|
||||
|
||||
func stop(f string, p string) {
|
||||
var c *exec.Cmd
|
||||
var err error
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
p := strings.Split(p, `\`)
|
||||
c = exec.Command("taskkill", "/F", "/IM", p[len(p)-1])
|
||||
case "linux", "darwin":
|
||||
b, err := ioutil.ReadFile(beego.AppPath + "/" + f + ".pid")
|
||||
if err == nil {
|
||||
c = exec.Command("/bin/bash", "-c", `kill -9 `+string(b))
|
||||
} else {
|
||||
log.Println("停止服务失败,pid文件不存在")
|
||||
}
|
||||
}
|
||||
err = c.Run()
|
||||
if err != nil {
|
||||
log.Println("停止服务失败,", err)
|
||||
} else {
|
||||
log.Println("停止服务成功")
|
||||
}
|
||||
}
|
426
lib/file.go
Normal file
426
lib/file.go
Normal file
@@ -0,0 +1,426 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"github.com/astaxie/beego"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
CsvDb *Csv
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
func NewCsv() *Csv {
|
||||
return new(Csv)
|
||||
}
|
||||
|
||||
type Csv struct {
|
||||
Tasks []*Tunnel
|
||||
Path string
|
||||
Hosts []*Host //域名列表
|
||||
Clients []*Client //客户端
|
||||
ClientIncreaseId int //客户端id
|
||||
TaskIncreaseId int //任务自增ID
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (s *Csv) Init() {
|
||||
s.LoadClientFromCsv()
|
||||
s.LoadTaskFromCsv()
|
||||
s.LoadHostFromCsv()
|
||||
}
|
||||
|
||||
func (s *Csv) StoreTasksToCsv() {
|
||||
// 创建文件
|
||||
csvFile, err := os.Create(beego.AppPath + "/conf/tasks.csv")
|
||||
if err != nil {
|
||||
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.Config.U,
|
||||
task.Config.P,
|
||||
task.Config.Compress,
|
||||
GetStrByBool(task.Status),
|
||||
GetStrByBool(task.Config.Crypt),
|
||||
strconv.Itoa(task.Config.CompressEncode),
|
||||
strconv.Itoa(task.Config.CompressDecode),
|
||||
strconv.Itoa(task.Id),
|
||||
strconv.Itoa(task.Client.Id),
|
||||
strconv.FormatBool(task.UseClientCnf),
|
||||
task.Remark,
|
||||
}
|
||||
err := writer.Write(record)
|
||||
if err != nil {
|
||||
Fatalf(err.Error())
|
||||
}
|
||||
}
|
||||
writer.Flush()
|
||||
}
|
||||
|
||||
func (s *Csv) openFile(path string) ([][]string, error) {
|
||||
// 打开文件
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// 获取csv的reader
|
||||
reader := csv.NewReader(file)
|
||||
|
||||
// 设置FieldsPerRecord为-1
|
||||
reader.FieldsPerRecord = -1
|
||||
|
||||
// 读取文件中所有行保存到slice中
|
||||
return reader.ReadAll()
|
||||
}
|
||||
|
||||
func (s *Csv) LoadTaskFromCsv() {
|
||||
path := beego.AppPath + "/conf/tasks.csv"
|
||||
records, err := s.openFile(path)
|
||||
if err != nil {
|
||||
Fatalln("配置文件打开错误:", path)
|
||||
}
|
||||
var tasks []*Tunnel
|
||||
// 将每一行数据保存到内存slice中
|
||||
for _, item := range records {
|
||||
post := &Tunnel{
|
||||
TcpPort: GetIntNoErrByStr(item[0]),
|
||||
Mode: item[1],
|
||||
Target: item[2],
|
||||
Config: &Config{
|
||||
U: item[3],
|
||||
P: item[4],
|
||||
Compress: item[5],
|
||||
Crypt: GetBoolByStr(item[7]),
|
||||
CompressEncode: GetIntNoErrByStr(item[8]),
|
||||
CompressDecode: GetIntNoErrByStr(item[9]),
|
||||
},
|
||||
Status: GetBoolByStr(item[6]),
|
||||
Id: GetIntNoErrByStr(item[10]),
|
||||
UseClientCnf: GetBoolByStr(item[12]),
|
||||
Remark: item[13],
|
||||
}
|
||||
post.Flow = new(Flow)
|
||||
if post.Client, err = s.GetClient(GetIntNoErrByStr(item[11])); err != nil {
|
||||
continue
|
||||
}
|
||||
tasks = append(tasks, post)
|
||||
if post.Id > s.TaskIncreaseId {
|
||||
s.TaskIncreaseId = post.Id
|
||||
}
|
||||
}
|
||||
s.Tasks = tasks
|
||||
}
|
||||
|
||||
func (s *Csv) GetTaskId() int {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
s.TaskIncreaseId++
|
||||
return s.TaskIncreaseId
|
||||
}
|
||||
|
||||
func (s *Csv) GetIdByVerifyKey(vKey string, addr string) (int, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
for _, v := range s.Clients {
|
||||
if Getverifyval(v.VerifyKey) == vKey && v.Status {
|
||||
if arr := strings.Split(addr, ":"); len(arr) > 0 {
|
||||
v.Addr = arr[0]
|
||||
}
|
||||
return v.Id, nil
|
||||
}
|
||||
}
|
||||
return 0, errors.New("not found")
|
||||
}
|
||||
|
||||
func (s *Csv) NewTask(t *Tunnel) {
|
||||
t.Flow = new(Flow)
|
||||
s.Tasks = append(s.Tasks, t)
|
||||
s.StoreTasksToCsv()
|
||||
}
|
||||
|
||||
func (s *Csv) UpdateTask(t *Tunnel) error {
|
||||
for k, v := range s.Tasks {
|
||||
if v.Id == t.Id {
|
||||
s.Tasks = append(s.Tasks[:k], s.Tasks[k+1:]...)
|
||||
s.Tasks = append(s.Tasks, t)
|
||||
s.StoreTasksToCsv()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("不存在")
|
||||
}
|
||||
|
||||
func (s *Csv) DelTask(id int) error {
|
||||
for k, v := range s.Tasks {
|
||||
if v.Id == id {
|
||||
s.Tasks = append(s.Tasks[:k], s.Tasks[k+1:]...)
|
||||
s.StoreTasksToCsv()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("不存在")
|
||||
}
|
||||
|
||||
func (s *Csv) GetTask(id int) (v *Tunnel, err error) {
|
||||
for _, v = range s.Tasks {
|
||||
if v.Id == id {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = errors.New("未找到")
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Csv) StoreHostToCsv() {
|
||||
// 创建文件
|
||||
csvFile, err := os.Create(beego.AppPath + "/conf/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,
|
||||
strconv.Itoa(host.Client.Id),
|
||||
host.HeaderChange,
|
||||
host.HostChange,
|
||||
host.Remark,
|
||||
}
|
||||
err1 := writer.Write(record)
|
||||
if err1 != nil {
|
||||
panic(err1)
|
||||
}
|
||||
}
|
||||
// 确保所有内存数据刷到csv文件
|
||||
writer.Flush()
|
||||
}
|
||||
|
||||
func (s *Csv) LoadClientFromCsv() {
|
||||
path := beego.AppPath + "/conf/clients.csv"
|
||||
records, err := s.openFile(path)
|
||||
if err != nil {
|
||||
Fatalln("配置文件打开错误:", path)
|
||||
}
|
||||
var clients []*Client
|
||||
// 将每一行数据保存到内存slice中
|
||||
for _, item := range records {
|
||||
post := &Client{
|
||||
Id: GetIntNoErrByStr(item[0]),
|
||||
VerifyKey: item[1],
|
||||
Remark: item[2],
|
||||
Status: GetBoolByStr(item[3]),
|
||||
RateLimit: GetIntNoErrByStr(item[8]),
|
||||
Cnf: &Config{
|
||||
U: item[4],
|
||||
P: item[5],
|
||||
Crypt: GetBoolByStr(item[6]),
|
||||
Compress: item[7],
|
||||
},
|
||||
}
|
||||
if post.Id > s.ClientIncreaseId {
|
||||
s.ClientIncreaseId = post.Id
|
||||
}
|
||||
if post.RateLimit > 0 {
|
||||
post.Rate = NewRate(int64(post.RateLimit * 1024))
|
||||
post.Rate.Start()
|
||||
}
|
||||
post.Flow = new(Flow)
|
||||
post.Flow.FlowLimit = int64(GetIntNoErrByStr(item[9]))
|
||||
clients = append(clients, post)
|
||||
}
|
||||
s.Clients = clients
|
||||
}
|
||||
|
||||
func (s *Csv) LoadHostFromCsv() {
|
||||
path := beego.AppPath + "/conf/hosts.csv"
|
||||
records, err := s.openFile(path)
|
||||
if err != nil {
|
||||
Fatalln("配置文件打开错误:", path)
|
||||
}
|
||||
var hosts []*Host
|
||||
// 将每一行数据保存到内存slice中
|
||||
for _, item := range records {
|
||||
post := &Host{
|
||||
Host: item[0],
|
||||
Target: item[1],
|
||||
HeaderChange: item[3],
|
||||
HostChange: item[4],
|
||||
Remark: item[5],
|
||||
}
|
||||
if post.Client, err = s.GetClient(GetIntNoErrByStr(item[2])); err != nil {
|
||||
continue
|
||||
}
|
||||
post.Flow = new(Flow)
|
||||
hosts = append(hosts, post)
|
||||
}
|
||||
s.Hosts = hosts
|
||||
}
|
||||
|
||||
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 *Host) {
|
||||
t.Flow = new(Flow)
|
||||
s.Hosts = append(s.Hosts, t)
|
||||
s.StoreHostToCsv()
|
||||
|
||||
}
|
||||
|
||||
func (s *Csv) UpdateHost(t *Host) error {
|
||||
for k, v := range s.Hosts {
|
||||
if v.Host == t.Host {
|
||||
s.Hosts = append(s.Hosts[:k], s.Hosts[k+1:]...)
|
||||
s.Hosts = append(s.Hosts, t)
|
||||
s.StoreHostToCsv()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("不存在")
|
||||
}
|
||||
|
||||
func (s *Csv) GetHost(start, length int, id int) ([]*Host, int) {
|
||||
list := make([]*Host, 0)
|
||||
var cnt int
|
||||
for _, v := range s.Hosts {
|
||||
if id == 0 || v.Client.Id == id {
|
||||
cnt++
|
||||
if start--; start < 0 {
|
||||
if length--; length > 0 {
|
||||
list = append(list, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list, cnt
|
||||
}
|
||||
|
||||
func (s *Csv) DelClient(id int) error {
|
||||
for k, v := range s.Clients {
|
||||
if v.Id == id {
|
||||
s.Clients = append(s.Clients[:k], s.Clients[k+1:]...)
|
||||
s.StoreClientsToCsv()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("不存在")
|
||||
}
|
||||
|
||||
func (s *Csv) NewClient(c *Client) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
c.Flow = new(Flow)
|
||||
s.Clients = append(s.Clients, c)
|
||||
s.StoreClientsToCsv()
|
||||
}
|
||||
|
||||
func (s *Csv) GetClientId() int {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
s.ClientIncreaseId++
|
||||
return s.ClientIncreaseId
|
||||
}
|
||||
|
||||
func (s *Csv) UpdateClient(t *Client) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
for _, v := range s.Clients {
|
||||
if v.Id == t.Id {
|
||||
v.Cnf = t.Cnf
|
||||
v.VerifyKey = t.VerifyKey
|
||||
v.Remark = t.Remark
|
||||
v.RateLimit = t.RateLimit
|
||||
v.Flow = t.Flow
|
||||
v.Rate = t.Rate
|
||||
s.StoreClientsToCsv()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("不存在")
|
||||
}
|
||||
|
||||
func (s *Csv) GetClientList(start, length int) ([]*Client, int) {
|
||||
list := make([]*Client, 0)
|
||||
var cnt int
|
||||
for _, v := range s.Clients {
|
||||
cnt++
|
||||
if start--; start < 0 {
|
||||
if length--; length > 0 {
|
||||
list = append(list, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
return list, cnt
|
||||
}
|
||||
|
||||
func (s *Csv) GetClient(id int) (v *Client, err error) {
|
||||
for _, v = range s.Clients {
|
||||
if v.Id == id {
|
||||
return
|
||||
}
|
||||
}
|
||||
err = errors.New("未找到")
|
||||
return
|
||||
}
|
||||
func (s *Csv) StoreClientsToCsv() {
|
||||
// 创建文件
|
||||
csvFile, err := os.Create(beego.AppPath + "/conf/clients.csv")
|
||||
if err != nil {
|
||||
Fatalln(err.Error())
|
||||
}
|
||||
defer csvFile.Close()
|
||||
writer := csv.NewWriter(csvFile)
|
||||
for _, client := range s.Clients {
|
||||
record := []string{
|
||||
strconv.Itoa(client.Id),
|
||||
client.VerifyKey,
|
||||
client.Remark,
|
||||
strconv.FormatBool(client.Status),
|
||||
client.Cnf.U,
|
||||
client.Cnf.P,
|
||||
GetStrByBool(client.Cnf.Crypt),
|
||||
client.Cnf.Compress,
|
||||
strconv.Itoa(client.RateLimit),
|
||||
strconv.Itoa(int(client.Flow.FlowLimit)),
|
||||
}
|
||||
err := writer.Write(record)
|
||||
if err != nil {
|
||||
Fatalln(err.Error())
|
||||
}
|
||||
}
|
||||
writer.Flush()
|
||||
}
|
||||
|
||||
//init csv from file
|
||||
func GetCsvDb() *Csv {
|
||||
once.Do(func() {
|
||||
CsvDb = NewCsv()
|
||||
CsvDb.Init()
|
||||
})
|
||||
return CsvDb
|
||||
}
|
130
lib/install.go
Normal file
130
lib/install.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func InstallNps() {
|
||||
var path string
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
path = "C:/"
|
||||
case "linux", "darwin":
|
||||
path = "/etc/nps/"
|
||||
}
|
||||
if err := os.Mkdir(path, 0755); err != nil {
|
||||
log.Fatalf("创建目录%s失败:%s", path, err.Error())
|
||||
}
|
||||
//复制文件到对应目录
|
||||
if err := CopyDir("./web", path); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
if err := CopyDir("./conf", path); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
//linux加入到/etc/init.d
|
||||
|
||||
//windows处理
|
||||
|
||||
//darwin处理
|
||||
}
|
||||
|
||||
func CopyDir(srcPath string, destPath string) error {
|
||||
//检测目录正确性
|
||||
if srcInfo, err := os.Stat(srcPath); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return err
|
||||
} else {
|
||||
if !srcInfo.IsDir() {
|
||||
e := errors.New("srcPath不是一个正确的目录!")
|
||||
fmt.Println(e.Error())
|
||||
return e
|
||||
}
|
||||
}
|
||||
if destInfo, err := os.Stat(destPath); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return err
|
||||
} else {
|
||||
if !destInfo.IsDir() {
|
||||
e := errors.New("destInfo不是一个正确的目录!")
|
||||
fmt.Println(e.Error())
|
||||
return e
|
||||
}
|
||||
}
|
||||
//加上拷贝时间:不用可以去掉
|
||||
destPath = destPath + "_" + time.Now().Format("20060102150405")
|
||||
|
||||
err := filepath.Walk(srcPath, func(path string, f os.FileInfo, err error) error {
|
||||
if f == nil {
|
||||
return err
|
||||
}
|
||||
if !f.IsDir() {
|
||||
path := strings.Replace(path, "\\", "/", -1)
|
||||
destNewPath := strings.Replace(path, srcPath, destPath, -1)
|
||||
fmt.Println("复制文件:" + path + " 到 " + destNewPath)
|
||||
copyFile(path, destNewPath)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf(err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//生成目录并拷贝文件
|
||||
func copyFile(src, dest string) (w int64, err error) {
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer srcFile.Close()
|
||||
//分割path目录
|
||||
destSplitPathDirs := strings.Split(dest, "/")
|
||||
|
||||
//检测时候存在目录
|
||||
destSplitPath := ""
|
||||
for index, dir := range destSplitPathDirs {
|
||||
if index < len(destSplitPathDirs)-1 {
|
||||
destSplitPath = destSplitPath + dir + "/"
|
||||
b, _ := pathExists(destSplitPath)
|
||||
if b == false {
|
||||
fmt.Println("创建目录:" + destSplitPath)
|
||||
//创建目录
|
||||
err := os.Mkdir(destSplitPath, os.ModePerm)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dstFile, err := os.Create(dest)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return
|
||||
}
|
||||
defer dstFile.Close()
|
||||
|
||||
return io.Copy(dstFile, srcFile)
|
||||
}
|
||||
|
||||
//检测文件夹路径时候存在
|
||||
func pathExists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
134
lib/link.go
Normal file
134
lib/link.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Link struct {
|
||||
Id int //id
|
||||
ConnType string //连接类型
|
||||
Host string //目标
|
||||
En int //加密
|
||||
De int //解密
|
||||
Crypt bool //加密
|
||||
Conn *Conn
|
||||
Flow *Flow
|
||||
UdpListener *net.UDPConn
|
||||
Rate *Rate
|
||||
UdpRemoteAddr *net.UDPAddr
|
||||
}
|
||||
|
||||
func NewLink(id int, connType string, host string, en, de int, crypt bool, conn *Conn, flow *Flow, udpListener *net.UDPConn, rate *Rate, UdpRemoteAddr *net.UDPAddr) *Link {
|
||||
return &Link{
|
||||
Id: id,
|
||||
ConnType: connType,
|
||||
Host: host,
|
||||
En: en,
|
||||
De: de,
|
||||
Crypt: crypt,
|
||||
Conn: conn,
|
||||
Flow: flow,
|
||||
UdpListener: udpListener,
|
||||
Rate: rate,
|
||||
UdpRemoteAddr: UdpRemoteAddr,
|
||||
}
|
||||
}
|
||||
|
||||
type Flow struct {
|
||||
ExportFlow int64 //出口流量
|
||||
InletFlow int64 //入口流量
|
||||
FlowLimit int64 //流量限制,出口+入口 /M
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *Flow) Add(in, out int) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
s.InletFlow += int64(in)
|
||||
s.ExportFlow += int64(out)
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
Cnf *Config
|
||||
Id int //id
|
||||
VerifyKey string //验证密钥
|
||||
Addr string //客户端ip地址
|
||||
Remark string //备注
|
||||
Status bool //是否开启
|
||||
IsConnect bool //是否连接
|
||||
RateLimit int //速度限制 /kb
|
||||
Flow *Flow //流量
|
||||
Rate *Rate //速度控制
|
||||
id int
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *Client) GetId() int {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
s.id++
|
||||
return s.id
|
||||
}
|
||||
|
||||
type Tunnel struct {
|
||||
Id int //Id
|
||||
TcpPort int //服务端与客户端通信端口
|
||||
Mode string //启动方式
|
||||
Target string //目标
|
||||
Status bool //是否开启
|
||||
Client *Client //所属客户端id
|
||||
Flow *Flow
|
||||
Config *Config
|
||||
UseClientCnf bool //是否继承客户端配置
|
||||
Remark string //备注
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
U string //socks5验证用户名
|
||||
P string //socks5验证密码
|
||||
Compress string //压缩方式
|
||||
Crypt bool //是否加密
|
||||
CompressEncode int //加密方式
|
||||
CompressDecode int //解密方式
|
||||
}
|
||||
|
||||
type Host struct {
|
||||
Host string //启动方式
|
||||
Target string //目标
|
||||
HeaderChange string //host修改
|
||||
HostChange string //host修改
|
||||
Flow *Flow
|
||||
Client *Client
|
||||
Remark string //备注
|
||||
NowIndex int
|
||||
TargetArr []string
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *Host) GetRandomTarget() string {
|
||||
if s.TargetArr == nil {
|
||||
s.TargetArr = strings.Split(s.Target, "\n")
|
||||
}
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
if s.NowIndex >= len(s.TargetArr)-1 {
|
||||
s.NowIndex = 0
|
||||
} else {
|
||||
s.NowIndex++
|
||||
}
|
||||
return s.TargetArr[s.NowIndex]
|
||||
}
|
||||
|
||||
//深拷贝Config
|
||||
func DeepCopyConfig(c *Config) *Config {
|
||||
return &Config{
|
||||
U: c.U,
|
||||
P: c.P,
|
||||
Compress: c.Compress,
|
||||
Crypt: c.Crypt,
|
||||
CompressEncode: c.CompressEncode,
|
||||
CompressDecode: c.CompressDecode,
|
||||
}
|
||||
}
|
45
lib/log.go
Normal file
45
lib/log.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var Log *log.Logger
|
||||
|
||||
func InitLogFile(f string, isStdout bool) {
|
||||
var prefix string
|
||||
if !isStdout {
|
||||
logFile, err := os.OpenFile(beego.AppPath+"/"+f+"_log.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)
|
||||
if err != nil {
|
||||
log.Fatalln("open file error !")
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
prefix = "\r\n"
|
||||
}
|
||||
Log = log.New(logFile, prefix, log.Ldate|log.Ltime)
|
||||
} else {
|
||||
Log = log.New(os.Stdout, "", log.Ldate|log.Ltime)
|
||||
}
|
||||
}
|
||||
|
||||
func Println(v ...interface{}) {
|
||||
Log.Println(v ...)
|
||||
}
|
||||
|
||||
func Fatalln(v ...interface{}) {
|
||||
Log.SetPrefix("error ")
|
||||
Log.Fatalln(v ...)
|
||||
Log.SetPrefix("")
|
||||
}
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
Log.SetPrefix("error ")
|
||||
Log.Fatalf(format, v...)
|
||||
Log.SetPrefix("")
|
||||
}
|
||||
|
||||
func Printf(format string, v ...interface{}) {
|
||||
Log.Printf(format, v...)
|
||||
}
|
43
lib/pool.go
Normal file
43
lib/pool.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
const poolSize = 64 * 1024
|
||||
const poolSizeSmall = 100
|
||||
const poolSizeUdp = 1472
|
||||
const poolSizeCopy = 32 * 1024
|
||||
|
||||
var BufPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, poolSize)
|
||||
},
|
||||
}
|
||||
|
||||
var BufPoolUdp = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, poolSizeUdp)
|
||||
},
|
||||
}
|
||||
var BufPoolMax = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, poolSize)
|
||||
},
|
||||
}
|
||||
var BufPoolSmall = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, poolSizeSmall)
|
||||
},
|
||||
}
|
||||
var BufPoolCopy = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, poolSizeCopy)
|
||||
},
|
||||
}
|
||||
|
||||
func PutBufPoolCopy(buf []byte) {
|
||||
if cap(buf) == poolSizeCopy {
|
||||
BufPoolCopy.Put(buf[:poolSizeCopy])
|
||||
}
|
||||
}
|
74
lib/rate.go
Normal file
74
lib/rate.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Rate struct {
|
||||
bucketSize int64 //木桶容量
|
||||
bucketSurplusSize int64 //当前桶中体积
|
||||
bucketAddSize int64 //每次加水大小
|
||||
stopChan chan bool //停止
|
||||
}
|
||||
|
||||
func NewRate(addSize int64) *Rate {
|
||||
return &Rate{
|
||||
bucketSize: addSize * 2,
|
||||
bucketSurplusSize: 0,
|
||||
bucketAddSize: addSize,
|
||||
stopChan: make(chan bool),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Rate) Start() {
|
||||
go s.session()
|
||||
}
|
||||
|
||||
func (s *Rate) add(size int64) {
|
||||
if (s.bucketSize - s.bucketSurplusSize) < s.bucketAddSize {
|
||||
return
|
||||
}
|
||||
atomic.AddInt64(&s.bucketSurplusSize, size)
|
||||
}
|
||||
|
||||
//回桶
|
||||
func (s *Rate) ReturnBucket(size int64) {
|
||||
s.add(size)
|
||||
}
|
||||
|
||||
//停止
|
||||
func (s *Rate) Stop() {
|
||||
s.stopChan <- true
|
||||
}
|
||||
|
||||
func (s *Rate) Get(size int64) {
|
||||
if s.bucketSurplusSize >= size {
|
||||
atomic.AddInt64(&s.bucketSurplusSize, -size)
|
||||
return
|
||||
}
|
||||
ticker := time.NewTicker(time.Millisecond * 100)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
if s.bucketSurplusSize >= size {
|
||||
atomic.AddInt64(&s.bucketSurplusSize, -size)
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Rate) session() {
|
||||
ticker := time.NewTicker(time.Second * 1)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
s.add(s.bucketAddSize)
|
||||
case <-s.stopChan:
|
||||
ticker.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
163
lib/util.go
Executable file
163
lib/util.go
Executable file
@@ -0,0 +1,163 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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"
|
||||
RES_CLOSE = "clse"
|
||||
NEW_CONN = "conn" //新连接标志
|
||||
CONN_SUCCESS = "sucs"
|
||||
CONN_TCP = "tcp"
|
||||
CONN_UDP = "udp"
|
||||
UnauthorizedBytes = `HTTP/1.1 401 Unauthorized
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
WWW-Authenticate: Basic realm="easyProxy"
|
||||
|
||||
401 Unauthorized`
|
||||
IO_EOF = "PROXYEOF"
|
||||
ConnectionFailBytes = `HTTP/1.1 404 Not Found
|
||||
|
||||
`
|
||||
)
|
||||
|
||||
//判断压缩方式
|
||||
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:
|
||||
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
|
||||
}
|
||||
|
||||
//简单的一个校验值
|
||||
func Getverifyval(vkey string) string {
|
||||
return Md5(vkey)
|
||||
}
|
||||
|
||||
func ChangeHostAndHeader(r *http.Request, host string, header string, addr string) {
|
||||
if host != "" {
|
||||
r.Host = host
|
||||
}
|
||||
if header != "" {
|
||||
h := strings.Split(header, "\n")
|
||||
for _, v := range h {
|
||||
hd := strings.Split(v, ":")
|
||||
if len(hd) == 2 {
|
||||
r.Header.Set(hd[0], hd[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
addr = strings.Split(addr, ":")[0]
|
||||
r.Header.Set("X-Forwarded-For", addr)
|
||||
r.Header.Set("X-Real-IP", addr)
|
||||
}
|
||||
|
||||
func ReadAllFromFile(filePath string) ([]byte, error) {
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ioutil.ReadAll(f)
|
||||
}
|
||||
|
||||
|
||||
// FileExists reports whether the named file or directory exists.
|
||||
func FileExists(name string) bool {
|
||||
if _, err := os.Stat(name); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
Reference in New Issue
Block a user