目录变更

pull/1219/head
刘河 2019-02-03 17:25:00 +08:00
parent 87f2c8b2ce
commit 74b262503e
27 changed files with 328 additions and 203 deletions

View File

@ -2,16 +2,16 @@ package bridge
import (
"errors"
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
"net"
"sync"
"time"
)
type Client struct {
tunnel *utils.Conn
signal *utils.Conn
linkMap map[int]*utils.Link
tunnel *lib.Conn
signal *lib.Conn
linkMap map[int]*lib.Link
linkStatusMap map[int]bool
stop chan bool
sync.RWMutex
@ -51,21 +51,21 @@ func (s *Bridge) tunnelProcess() error {
for {
conn, err := s.listener.Accept()
if err != nil {
utils.Println(err)
lib.Println(err)
continue
}
go s.cliProcess(utils.NewConn(conn))
go s.cliProcess(lib.NewConn(conn))
}
return err
}
//验证失败返回错误验证flag并且关闭连接
func (s *Bridge) verifyError(c *utils.Conn) {
c.Write([]byte(utils.VERIFY_EER))
func (s *Bridge) verifyError(c *lib.Conn) {
c.Write([]byte(lib.VERIFY_EER))
c.Conn.Close()
}
func (s *Bridge) cliProcess(c *utils.Conn) {
func (s *Bridge) cliProcess(c *lib.Conn) {
c.SetReadDeadline(5)
var buf []byte
var err error
@ -74,9 +74,9 @@ func (s *Bridge) cliProcess(c *utils.Conn) {
return
}
//验证
id, err := utils.GetCsvDb().GetIdByVerifyKey(string(buf), c.Conn.RemoteAddr().String())
id, err := lib.GetCsvDb().GetIdByVerifyKey(string(buf), c.Conn.RemoteAddr().String())
if err != nil {
utils.Println("当前客户端连接校验错误,关闭此客户端:", c.Conn.RemoteAddr())
lib.Println("当前客户端连接校验错误,关闭此客户端:", c.Conn.RemoteAddr())
s.verifyError(c)
return
}
@ -97,9 +97,9 @@ func (s *Bridge) closeClient(id int) {
}
//tcp连接类型区分
func (s *Bridge) typeDeal(typeVal string, c *utils.Conn, id int) {
func (s *Bridge) typeDeal(typeVal string, c *lib.Conn, id int) {
switch typeVal {
case utils.WORK_MAIN:
case lib.WORK_MAIN:
//客户端已经存在,下线
s.clientLock.Lock()
if _, ok := s.Client[id]; ok {
@ -111,15 +111,15 @@ func (s *Bridge) typeDeal(typeVal string, c *utils.Conn, id int) {
s.clientLock.Lock()
s.Client[id] = &Client{
linkMap: make(map[int]*utils.Link),
linkMap: make(map[int]*lib.Link),
stop: make(chan bool),
linkStatusMap: make(map[int]bool),
}
utils.Printf("客户端%d连接成功,地址为:%s", id, c.Conn.RemoteAddr())
lib.Printf("客户端%d连接成功,地址为:%s", id, c.Conn.RemoteAddr())
s.Client[id].signal = c
s.clientLock.Unlock()
go s.GetStatus(id)
case utils.WORK_CHAN:
case lib.WORK_CHAN:
s.clientLock.Lock()
if v, ok := s.Client[id]; ok {
s.clientLock.Unlock()
@ -161,13 +161,13 @@ func (s *Bridge) waitStatus(clientId, id int) (bool) {
return false
}
func (s *Bridge) SendLinkInfo(clientId int, link *utils.Link) (tunnel *utils.Conn, err error) {
func (s *Bridge) SendLinkInfo(clientId int, link *lib.Link) (tunnel *lib.Conn, err error) {
s.clientLock.Lock()
if v, ok := s.Client[clientId]; ok {
s.clientLock.Unlock()
v.signal.SendLinkInfo(link)
if err != nil {
utils.Println("send error:", err, link.Id)
lib.Println("send error:", err, link.Id)
s.DelClient(clientId)
return
}
@ -192,7 +192,7 @@ func (s *Bridge) SendLinkInfo(clientId int, link *utils.Link) (tunnel *utils.Con
}
//得到一个tcp隧道
func (s *Bridge) GetTunnel(id int, en, de int, crypt, mux bool) (conn *utils.Conn, err error) {
func (s *Bridge) GetTunnel(id int, en, de int, crypt, mux bool) (conn *lib.Conn, err error) {
s.clientLock.Lock()
defer s.clientLock.Unlock()
if v, ok := s.Client[id]; !ok {
@ -204,7 +204,7 @@ func (s *Bridge) GetTunnel(id int, en, de int, crypt, mux bool) (conn *utils.Con
}
//得到一个通信通道
func (s *Bridge) GetSignal(id int) (conn *utils.Conn, err error) {
func (s *Bridge) GetSignal(id int) (conn *lib.Conn, err error) {
s.clientLock.Lock()
defer s.clientLock.Unlock()
if v, ok := s.Client[id]; !ok {
@ -257,19 +257,19 @@ func (s *Bridge) clientCopy(clientId int) {
for {
if id, err := client.tunnel.GetLen(); err != nil {
s.closeClient(clientId)
utils.Println("读取msg id 错误", err, id)
lib.Println("读取msg id 错误", err, id)
break
} else {
client.Lock()
if link, ok := client.linkMap[id]; ok {
client.Unlock()
if content, err := client.tunnel.GetMsgContent(link); err != nil {
utils.PutBufPoolCopy(content)
lib.PutBufPoolCopy(content)
s.closeClient(clientId)
utils.Println("read msg content error", err, "close client")
lib.Println("read msg content error", err, "close client")
break
} else {
if len(content) == len(utils.IO_EOF) && string(content) == utils.IO_EOF {
if len(content) == len(lib.IO_EOF) && string(content) == lib.IO_EOF {
if link.Conn != nil {
link.Conn.Close()
}
@ -281,7 +281,7 @@ func (s *Bridge) clientCopy(clientId int) {
}
link.Flow.Add(0, len(content))
}
utils.PutBufPoolCopy(content)
lib.PutBufPoolCopy(content)
}
} else {
client.Unlock()

View File

@ -1,7 +1,7 @@
package client
import (
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
"net"
"sync"
"time"
@ -9,9 +9,9 @@ import (
type TRPClient struct {
svrAddr string
linkMap map[int]*utils.Link
linkMap map[int]*lib.Link
stop chan bool
tunnel *utils.Conn
tunnel *lib.Conn
sync.Mutex
vKey string
}
@ -20,7 +20,7 @@ type TRPClient struct {
func NewRPClient(svraddr string, vKey string) *TRPClient {
return &TRPClient{
svrAddr: svraddr,
linkMap: make(map[int]*utils.Link),
linkMap: make(map[int]*lib.Link),
stop: make(chan bool),
tunnel: nil,
Mutex: sync.Mutex{},
@ -39,18 +39,18 @@ func (s *TRPClient) NewConn() {
retry:
conn, err := net.Dial("tcp", s.svrAddr)
if err != nil {
utils.Println("连接服务端失败,五秒后将重连")
lib.Println("连接服务端失败,五秒后将重连")
time.Sleep(time.Second * 5)
goto retry
return
}
s.processor(utils.NewConn(conn))
s.processor(lib.NewConn(conn))
}
//处理
func (s *TRPClient) processor(c *utils.Conn) {
func (s *TRPClient) processor(c *lib.Conn) {
c.SetAlive()
if _, err := c.Write([]byte(utils.Getverifyval(s.vKey))); err != nil {
if _, err := c.Write([]byte(lib.Getverifyval(s.vKey))); err != nil {
return
}
c.WriteMain()
@ -60,13 +60,13 @@ func (s *TRPClient) processor(c *utils.Conn) {
for {
flags, err := c.ReadFlag()
if err != nil {
utils.Println("服务端断开,正在重新连接")
lib.Println("服务端断开,正在重新连接")
break
}
switch flags {
case utils.VERIFY_EER:
utils.Fatalf("vKey:%s不正确,服务端拒绝连接,请检查", s.vKey)
case utils.NEW_CONN:
case lib.VERIFY_EER:
lib.Fatalf("vKey:%s不正确,服务端拒绝连接,请检查", s.vKey)
case lib.NEW_CONN:
if link, err := c.GetLinkInfo(); err != nil {
break
} else {
@ -75,47 +75,47 @@ func (s *TRPClient) processor(c *utils.Conn) {
s.Unlock()
go s.linkProcess(link, c)
}
case utils.RES_CLOSE:
utils.Fatalln("该vkey被另一客户连接")
case utils.RES_MSG:
utils.Println("服务端返回错误,重新连接")
case lib.RES_CLOSE:
lib.Fatalln("该vkey被另一客户连接")
case lib.RES_MSG:
lib.Println("服务端返回错误,重新连接")
break
default:
utils.Println("无法解析该错误,重新连接")
lib.Println("无法解析该错误,重新连接")
break
}
}
s.stop <- true
s.linkMap = make(map[int]*utils.Link)
s.linkMap = make(map[int]*lib.Link)
go s.NewConn()
}
func (s *TRPClient) linkProcess(link *utils.Link, c *utils.Conn) {
func (s *TRPClient) linkProcess(link *lib.Link, c *lib.Conn) {
//与目标建立连接
server, err := net.DialTimeout(link.ConnType, link.Host, time.Second*3)
if err != nil {
c.WriteFail(link.Id)
utils.Println("connect to ", link.Host, "error:", err)
lib.Println("connect to ", link.Host, "error:", err)
return
}
c.WriteSuccess(link.Id)
link.Conn = utils.NewConn(server)
link.Conn = lib.NewConn(server)
for {
buf := utils.BufPoolCopy.Get().([]byte)
buf := lib.BufPoolCopy.Get().([]byte)
if n, err := server.Read(buf); err != nil {
utils.PutBufPoolCopy(buf)
s.tunnel.SendMsg([]byte(utils.IO_EOF), link)
lib.PutBufPoolCopy(buf)
s.tunnel.SendMsg([]byte(lib.IO_EOF), link)
break
} else {
if _, err := s.tunnel.SendMsg(buf[:n], link); err != nil {
utils.PutBufPoolCopy(buf)
lib.PutBufPoolCopy(buf)
c.Close()
break
}
utils.PutBufPoolCopy(buf)
lib.PutBufPoolCopy(buf)
//if link.ConnType == utils.CONN_UDP {
// c.Close()
// break
@ -134,16 +134,16 @@ func (s *TRPClient) dealChan() {
//创建一个tcp连接
conn, err := net.Dial("tcp", s.svrAddr)
if err != nil {
utils.Println("connect to ", s.svrAddr, "error:", err)
lib.Println("connect to ", s.svrAddr, "error:", err)
return
}
//验证
if _, err := conn.Write([]byte(utils.Getverifyval(s.vKey))); err != nil {
utils.Println("connect to ", s.svrAddr, "error:", err)
if _, err := conn.Write([]byte(lib.Getverifyval(s.vKey))); err != nil {
lib.Println("connect to ", s.svrAddr, "error:", err)
return
}
//默认长连接保持
s.tunnel = utils.NewConn(conn)
s.tunnel = lib.NewConn(conn)
s.tunnel.SetAlive()
//写标志
s.tunnel.WriteChan()
@ -151,17 +151,17 @@ func (s *TRPClient) dealChan() {
go func() {
for {
if id, err := s.tunnel.GetLen(); err != nil {
utils.Println("get msg id error")
lib.Println("get msg id error")
break
} else {
s.Lock()
if v, ok := s.linkMap[id]; ok {
s.Unlock()
if content, err := s.tunnel.GetMsgContent(v); err != nil {
utils.Println("get msg content error:", err, id)
lib.Println("get msg content error:", err, id)
break
} else {
if len(content) == len(utils.IO_EOF) && string(content) == utils.IO_EOF {
if len(content) == len(lib.IO_EOF) && string(content) == lib.IO_EOF {
v.Conn.Close()
} else if v.Conn != nil {
v.Conn.Write(content)

View File

@ -3,8 +3,8 @@ package main
import (
"flag"
"github.com/cnlh/nps/client"
"github.com/cnlh/nps/utils"
_ "github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
_ "github.com/cnlh/nps/lib"
"strings"
)
@ -18,15 +18,15 @@ var (
func main() {
flag.Parse()
utils.InitDaemon("client")
lib.InitDaemon("npc")
if *logType == "stdout" {
utils.InitLogFile("client", true)
lib.InitLogFile("npc", true)
} else {
utils.InitLogFile("client", false)
lib.InitLogFile("npc", false)
}
stop := make(chan int)
for _, v := range strings.Split(*verifyKey, ",") {
utils.Println("客户端启动,连接:", *serverAddr, " 验证令牌:", v)
lib.Println("客户端启动,连接:", *serverAddr, " 验证令牌:", v)
go client.NewRPClient(*serverAddr, v).Start()
}
<-stop

View File

@ -4,7 +4,7 @@ import (
"flag"
"github.com/astaxie/beego"
"github.com/cnlh/nps/server"
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
_ "github.com/cnlh/nps/web/routers"
"os"
)
@ -30,37 +30,37 @@ func main() {
if len(os.Args) > 1 && os.Args[1] == "test" {
test = true
}
utils.InitDaemon("server")
lib.InitDaemon("nps")
if *logType == "stdout" || test {
utils.InitLogFile("server", true)
lib.InitLogFile("nps", true)
} else {
utils.InitLogFile("server", false)
lib.InitLogFile("nps", false)
}
task := &utils.Tunnel{
task := &lib.Tunnel{
TcpPort: *httpPort,
Mode: *rpMode,
Target: *tunnelTarget,
Config: &utils.Config{
Config: &lib.Config{
U: *u,
P: *p,
Compress: *compress,
Crypt: utils.GetBoolByStr(*crypt),
Crypt: lib.GetBoolByStr(*crypt),
},
Flow: &utils.Flow{},
Flow: &lib.Flow{},
UseClientCnf: false,
}
if *VerifyKey != "" {
c := &utils.Client{
c := &lib.Client{
Id: 0,
VerifyKey: *VerifyKey,
Addr: "",
Remark: "",
Status: true,
IsConnect: false,
Cnf: &utils.Config{},
Flow: &utils.Flow{},
Cnf: &lib.Config{},
Flow: &lib.Flow{},
}
c.Cnf.CompressDecode, c.Cnf.CompressEncode = utils.GetCompressType(c.Cnf.Compress)
c.Cnf.CompressDecode, c.Cnf.CompressEncode = lib.GetCompressType(c.Cnf.Compress)
server.CsvDb.Clients[0] = c
task.Client = c
}
@ -72,8 +72,8 @@ func main() {
*TcpPort = 8284
}
}
utils.Println("服务端启动监听tcp服务端端口", *TcpPort)
task.Config.CompressDecode, task.Config.CompressEncode = utils.GetCompressType(task.Config.Compress)
lib.Println("服务端启动监听tcp服务端端口", *TcpPort)
task.Config.CompressDecode, task.Config.CompressEncode = lib.GetCompressType(task.Config.Compress)
if *rpMode != "webServer" {
server.CsvDb.Tasks[0] = task
}

View File

@ -1,4 +1,4 @@
appname = easyProxy
appname = nps
#web管理端口
httpport = 8080
@ -25,4 +25,4 @@ httpsProxyPort=
pemPath=/etc/nginx/certificate.crt
##keyFile绝对路径
keyPath=/etc/nginx/private.key
keyPath=/etc/nginx/private.key

View File

@ -1 +0,0 @@
1,wajajb6bl086s2aq,111,true,1,2,1,,20000,1000
1 1 wajajb6bl086s2aq 111 true 1 2 1 20000 1000
1 wajajb6bl086s2aq 111 true 1 2 1 20000 1000

View File

@ -1,2 +0,0 @@
a.o.com,"127.0.0.1:8082
127.0.0.1:8080",1,,www.baidu.com,测试
1 a.o.com 127.0.0.1:8082 127.0.0.1:8080 1 www.baidu.com 测试
a.o.com 127.0.0.1:8082 127.0.0.1:8080 1 www.baidu.com 测试

View File

@ -1,4 +0,0 @@
9002,tunnelServer,127.0.0.1:8082,2,2,,1,1,0,0,1,1,false,123
53,udpServer,114.114.114.114:53,,,,1,0,0,0,2,1,true,udp测试
9003,httpProxyServer,,,,,1,0,0,0,3,1,false,
8024,socks5Server,,,,,1,0,0,0,4,1,true,
1 9002 tunnelServer 127.0.0.1:8082 2 2 1 1 0 0 1 1 false 123
9002 tunnelServer 127.0.0.1:8082 2 2 1 1 0 0 1 1 false 123
53 udpServer 114.114.114.114:53 1 0 0 0 2 1 true udp测试
9003 httpProxyServer 1 0 0 0 3 1 false
8024 socks5Server 1 0 0 0 4 1 true

View File

@ -1,4 +1,4 @@
package utils
package lib
import (
"bufio"

View File

@ -1,4 +1,4 @@
package utils
package lib
import (
"bytes"

View File

@ -1,4 +1,4 @@
package utils
package lib
import (
"github.com/astaxie/beego"
@ -32,6 +32,8 @@ func InitDaemon(f string) {
stop(f, args[0])
start(args, f)
os.Exit(0)
case "install":
InstallNps()
}
}
@ -41,7 +43,7 @@ func start(osArgs []string, f string) {
log.Println("执行启动成功")
if cmd.Process.Pid > 0 {
d1 := []byte(strconv.Itoa(cmd.Process.Pid))
ioutil.WriteFile(beego.AppPath+"/proxy_"+f+".pid", d1, 0600)
ioutil.WriteFile(beego.AppPath+"/"+f+".pid", d1, 0600)
}
}
@ -53,7 +55,7 @@ func stop(f string, p string) {
p := strings.Split(p, `\`)
c = exec.Command("taskkill", "/F", "/IM", p[len(p)-1])
case "linux", "darwin":
b, err := ioutil.ReadFile(beego.AppPath + "/proxy_" + f + ".pid")
b, err := ioutil.ReadFile(beego.AppPath + "/" + f + ".pid")
if err == nil {
c = exec.Command("/bin/bash", "-c", `kill -9 `+string(b))
} else {

View File

@ -1,4 +1,4 @@
package utils
package lib
import (
"encoding/csv"

130
lib/install.go Normal file
View 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
}

View File

@ -1,4 +1,4 @@
package utils
package lib
import (
"net"

View File

@ -1,4 +1,4 @@
package utils
package lib
import (
"github.com/astaxie/beego"
@ -12,7 +12,7 @@ var Log *log.Logger
func InitLogFile(f string, isStdout bool) {
var prefix string
if !isStdout {
logFile, err := os.OpenFile(beego.AppPath+"/proxy_"+f+"_log.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)
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 !")
}

View File

@ -1,4 +1,4 @@
package utils
package lib
import (
"sync"

View File

@ -1,4 +1,4 @@
package utils
package lib
import (
"sync/atomic"

View File

@ -1,4 +1,4 @@
package utils
package lib
import (
"encoding/base64"

View File

@ -3,7 +3,7 @@ package server
import (
"errors"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
"net"
"net/http"
"sync"
@ -13,8 +13,8 @@ import (
type server struct {
id int
bridge *bridge.Bridge
task *utils.Tunnel
config *utils.Config
task *lib.Tunnel
config *lib.Config
errorContent []byte
sync.Mutex
}
@ -26,7 +26,7 @@ func (s *server) FlowAdd(in, out int64) {
s.task.Flow.InletFlow += in
}
func (s *server) FlowAddHost(host *utils.Host, in, out int64) {
func (s *server) FlowAddHost(host *lib.Host, in, out int64) {
s.Lock()
defer s.Unlock()
host.Flow.ExportFlow += out
@ -62,11 +62,11 @@ func (s *server) ResetConfig() bool {
}
}
s.task.Client.Rate = client.Rate
s.config.CompressDecode, s.config.CompressEncode = utils.GetCompressType(s.config.Compress)
s.config.CompressDecode, s.config.CompressEncode = lib.GetCompressType(s.config.Compress)
return true
}
func (s *server) linkCopy(link *utils.Link, c *utils.Conn, rb []byte, tunnel *utils.Conn, flow *utils.Flow) {
func (s *server) linkCopy(link *lib.Link, c *lib.Conn, rb []byte, tunnel *lib.Conn, flow *lib.Flow) {
if rb != nil {
if _, err := tunnel.SendMsg(rb, link); err != nil {
c.Close()
@ -75,31 +75,31 @@ func (s *server) linkCopy(link *utils.Link, c *utils.Conn, rb []byte, tunnel *ut
flow.Add(len(rb), 0)
}
for {
buf := utils.BufPoolCopy.Get().([]byte)
buf := lib.BufPoolCopy.Get().([]byte)
if n, err := c.Read(buf); err != nil {
tunnel.SendMsg([]byte(utils.IO_EOF), link)
tunnel.SendMsg([]byte(lib.IO_EOF), link)
break
} else {
if _, err := tunnel.SendMsg(buf[:n], link); err != nil {
utils.PutBufPoolCopy(buf)
lib.PutBufPoolCopy(buf)
c.Close()
break
}
utils.PutBufPoolCopy(buf)
lib.PutBufPoolCopy(buf)
flow.Add(n, 0)
}
}
}
func (s *server) writeConnFail(c net.Conn) {
c.Write([]byte(utils.ConnectionFailBytes))
c.Write([]byte(lib.ConnectionFailBytes))
c.Write(s.errorContent)
}
//权限认证
func (s *server) auth(r *http.Request, c *utils.Conn, u, p string) error {
if u != "" && p != "" && !utils.CheckAuth(r, u, p) {
c.Write([]byte(utils.UnauthorizedBytes))
func (s *server) auth(r *http.Request, c *lib.Conn, u, p string) error {
if u != "" && p != "" && !lib.CheckAuth(r, u, p) {
c.Write([]byte(lib.UnauthorizedBytes))
c.Close()
return errors.New("401 Unauthorized")
}

View File

@ -5,7 +5,7 @@ import (
"crypto/tls"
"github.com/astaxie/beego"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
"net"
"net/http"
"net/http/httputil"
@ -22,7 +22,7 @@ type httpServer struct {
stop chan bool
}
func NewHttp(bridge *bridge.Bridge, c *utils.Tunnel) *httpServer {
func NewHttp(bridge *bridge.Bridge, c *lib.Tunnel) *httpServer {
httpPort, _ := beego.AppConfig.Int("httpProxyPort")
httpsPort, _ := beego.AppConfig.Int("httpsProxyPort")
pemPath := beego.AppConfig.String("pemPath")
@ -44,39 +44,39 @@ func NewHttp(bridge *bridge.Bridge, c *utils.Tunnel) *httpServer {
func (s *httpServer) Start() error {
var err error
var http, https *http.Server
if s.errorContent, err = utils.ReadAllFromFile(beego.AppPath + "/web/static/page/error.html"); err != nil {
if s.errorContent, err = lib.ReadAllFromFile(beego.AppPath + "/web/static/page/error.html"); err != nil {
s.errorContent = []byte("easyProxy 404")
}
if s.httpPort > 0 {
if !s.TestTcpPort(s.httpPort) {
utils.Fatalln("http端口", s.httpPort, "被占用!")
lib.Fatalln("http端口", s.httpPort, "被占用!")
}
http = s.NewServer(s.httpPort)
go func() {
utils.Println("启动http监听,端口为", s.httpPort)
lib.Println("启动http监听,端口为", s.httpPort)
err := http.ListenAndServe()
if err != nil {
utils.Fatalln(err)
lib.Fatalln(err)
}
}()
}
if s.httpsPort > 0 {
if !s.TestTcpPort(s.httpsPort) {
utils.Fatalln("https端口", s.httpsPort, "被占用!")
lib.Fatalln("https端口", s.httpsPort, "被占用!")
}
if !utils.FileExists(s.pemPath) {
utils.Fatalf("ssl certFile文件%s不存在", s.pemPath)
if !lib.FileExists(s.pemPath) {
lib.Fatalf("ssl certFile文件%s不存在", s.pemPath)
}
if !utils.FileExists(s.keyPath) {
utils.Fatalf("ssl keyFile文件%s不存在", s.keyPath)
if !lib.FileExists(s.keyPath) {
lib.Fatalf("ssl keyFile文件%s不存在", s.keyPath)
}
https = s.NewServer(s.httpsPort)
go func() {
utils.Println("启动https监听,端口为", s.httpsPort)
lib.Println("启动https监听,端口为", s.httpsPort)
err := https.ListenAndServeTLS(s.pemPath, s.keyPath)
if err != nil {
utils.Fatalln(err)
lib.Fatalln(err)
}
}()
}
@ -108,35 +108,35 @@ func (s *httpServer) handleTunneling(w http.ResponseWriter, r *http.Request) {
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
}
s.process(utils.NewConn(conn), r)
s.process(lib.NewConn(conn), r)
}
func (s *httpServer) process(c *utils.Conn, r *http.Request) {
func (s *httpServer) process(c *lib.Conn, r *http.Request) {
//多客户端域名代理
var (
isConn = true
link *utils.Link
host *utils.Host
tunnel *utils.Conn
link *lib.Link
host *lib.Host
tunnel *lib.Conn
err error
)
for {
//首次获取conn
if isConn {
if host, err = GetInfoByHost(r.Host); err != nil {
utils.Printf("the host %s is not found !", r.Host)
lib.Printf("the host %s is not found !", r.Host)
break
}
//流量限制
if host.Client.Flow.FlowLimit > 0 && (host.Client.Flow.FlowLimit<<20) < (host.Client.Flow.ExportFlow+host.Client.Flow.InletFlow) {
break
}
host.Client.Cnf.CompressDecode, host.Client.Cnf.CompressEncode = utils.GetCompressType(host.Client.Cnf.Compress)
host.Client.Cnf.CompressDecode, host.Client.Cnf.CompressEncode = lib.GetCompressType(host.Client.Cnf.Compress)
//权限控制
if err = s.auth(r, c, host.Client.Cnf.U, host.Client.Cnf.P); err != nil {
break
}
link = utils.NewLink(host.Client.GetId(), utils.CONN_TCP, host.GetRandomTarget(), host.Client.Cnf.CompressEncode, host.Client.Cnf.CompressDecode, host.Client.Cnf.Crypt, c, host.Flow, nil, host.Client.Rate, nil)
link = lib.NewLink(host.Client.GetId(), lib.CONN_TCP, host.GetRandomTarget(), host.Client.Cnf.CompressEncode, host.Client.Cnf.CompressDecode, host.Client.Cnf.Crypt, c, host.Flow, nil, host.Client.Rate, nil)
if tunnel, err = s.bridge.SendLinkInfo(host.Client.Id, link); err != nil {
break
}
@ -148,7 +148,7 @@ func (s *httpServer) process(c *utils.Conn, r *http.Request) {
}
}
//根据设定修改header和host
utils.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String())
lib.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String())
b, err := httputil.DumpRequest(r, true)
if err != nil {
break
@ -163,7 +163,7 @@ func (s *httpServer) process(c *utils.Conn, r *http.Request) {
if isConn {
s.writeConnFail(c.Conn)
} else {
tunnel.SendMsg([]byte(utils.IO_EOF), link)
tunnel.SendMsg([]byte(lib.IO_EOF), link)
}
c.Close()

View File

@ -3,7 +3,7 @@ package server
import (
"errors"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
"log"
"os"
"reflect"
@ -13,7 +13,7 @@ import (
var (
Bridge *bridge.Bridge
RunList map[int]interface{} //运行中的任务
CsvDb = utils.GetCsvDb()
CsvDb = lib.GetCsvDb()
startFinish chan bool
)
@ -26,27 +26,27 @@ func init() {
func InitFromCsv() {
for _, v := range CsvDb.Tasks {
if v.Status {
utils.Println("启动模式:", v.Mode, "监听端口:", v.TcpPort)
lib.Println("启动模式:", v.Mode, "监听端口:", v.TcpPort)
AddTask(v)
}
}
}
//start a new server
func StartNewServer(bridgePort int, cnf *utils.Tunnel, test bool) {
func StartNewServer(bridgePort int, cnf *lib.Tunnel, test bool) {
go func() {
Bridge = bridge.NewTunnel(bridgePort, RunList)
if err := Bridge.StartTunnel(); err != nil {
utils.Fatalln("服务端开启失败", err)
lib.Fatalln("服务端开启失败", err)
}
if svr := NewMode(Bridge, cnf); svr != nil {
RunList[cnf.Id] = svr
err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
if err.Interface() != nil {
utils.Fatalln(err)
lib.Fatalln(err)
}
} else {
utils.Fatalln("启动模式不正确")
lib.Fatalln("启动模式不正确")
}
}()
for {
@ -61,7 +61,7 @@ func StartNewServer(bridgePort int, cnf *utils.Tunnel, test bool) {
}
//new a server by mode name
func NewMode(Bridge *bridge.Bridge, c *utils.Tunnel) interface{} {
func NewMode(Bridge *bridge.Bridge, c *lib.Tunnel) interface{} {
switch c.Mode {
case "tunnelServer":
return NewTunnelModeServer(ProcessTunnel, Bridge, c)
@ -73,11 +73,11 @@ func NewMode(Bridge *bridge.Bridge, c *utils.Tunnel) interface{} {
return NewUdpModeServer(Bridge, c)
case "webServer":
InitFromCsv()
t := &utils.Tunnel{
t := &lib.Tunnel{
TcpPort: 0,
Mode: "httpHostServer",
Target: "",
Config: &utils.Config{},
Config: &lib.Config{},
Status: true,
}
AddTask(t)
@ -106,13 +106,13 @@ func StopServer(id int) error {
}
//add task
func AddTask(t *utils.Tunnel) error {
func AddTask(t *lib.Tunnel) error {
if svr := NewMode(Bridge, t); svr != nil {
RunList[t.Id] = svr
go func() {
err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
if err.Interface() != nil {
utils.Fatalln("服务端", t.Id, "启动失败,错误:", err)
lib.Fatalln("服务端", t.Id, "启动失败,错误:", err)
delete(RunList, t.Id)
}
}()
@ -143,7 +143,7 @@ func DelTask(id int) error {
}
//get key by host from x
func GetInfoByHost(host string) (h *utils.Host, err error) {
func GetInfoByHost(host string) (h *lib.Host, err error) {
for _, v := range CsvDb.Hosts {
s := strings.Split(host, ":")
if s[0] == v.Host {
@ -156,8 +156,8 @@ func GetInfoByHost(host string) (h *utils.Host, err error) {
}
//get task list by page num
func GetTunnel(start, length int, typeVal string, clientId int) ([]*utils.Tunnel, int) {
list := make([]*utils.Tunnel, 0)
func GetTunnel(start, length int, typeVal string, clientId int) ([]*lib.Tunnel, int) {
list := make([]*lib.Tunnel, 0)
var cnt int
for _, v := range CsvDb.Tasks {
if (typeVal != "" && v.Mode != typeVal) || (typeVal == "" && clientId != v.Client.Id) {
@ -184,13 +184,13 @@ func GetTunnel(start, length int, typeVal string, clientId int) ([]*utils.Tunnel
}
//获取客户端列表
func GetClientList(start, length int) (list []*utils.Client, cnt int) {
func GetClientList(start, length int) (list []*lib.Client, cnt int) {
list, cnt = CsvDb.GetClientList(start, length)
dealClientData(list)
return
}
func dealClientData(list []*utils.Client) {
func dealClientData(list []*lib.Client) {
for _, v := range list {
if _, ok := Bridge.Client[v.Id]; ok {
v.IsConnect = true

View File

@ -4,7 +4,7 @@ import (
"encoding/binary"
"errors"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
"io"
"net"
"strconv"
@ -65,7 +65,7 @@ func (s *Sock5ModeServer) handleRequest(c net.Conn) {
_, err := io.ReadFull(c, header)
if err != nil {
utils.Println("illegal request", err)
lib.Println("illegal request", err)
c.Close()
return
}
@ -135,18 +135,18 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) {
addr := net.JoinHostPort(host, strconv.Itoa(int(port)))
var ltype string
if command == associateMethod {
ltype = utils.CONN_UDP
ltype = lib.CONN_UDP
} else {
ltype = utils.CONN_TCP
ltype = lib.CONN_TCP
}
link := utils.NewLink(s.task.Client.GetId(), ltype, addr, s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, utils.NewConn(c), s.task.Flow, nil, s.task.Client.Rate, nil)
link := lib.NewLink(s.task.Client.GetId(), ltype, addr, s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, lib.NewConn(c), s.task.Flow, nil, s.task.Client.Rate, nil)
if tunnel, err := s.bridge.SendLinkInfo(s.task.Client.Id, link); err != nil {
c.Close()
return
} else {
s.sendReply(c, succeeded)
s.linkCopy(link, utils.NewConn(c), nil, tunnel, s.task.Flow)
s.linkCopy(link, lib.NewConn(c), nil, tunnel, s.task.Flow)
}
return
}
@ -162,7 +162,7 @@ func (s *Sock5ModeServer) handleBind(c net.Conn) {
//udp
func (s *Sock5ModeServer) handleUDP(c net.Conn) {
utils.Println("UDP Associate")
lib.Println("UDP Associate")
/*
+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
@ -175,7 +175,7 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) {
// relay udp datagram silently, without any notification to the requesting client
if buf[2] != 0 {
// does not support fragmentation, drop it
utils.Println("does not support fragmentation, drop")
lib.Println("does not support fragmentation, drop")
dummy := make([]byte, maxUDPPacketSize)
c.Read(dummy)
}
@ -187,13 +187,13 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) {
func (s *Sock5ModeServer) handleConn(c net.Conn) {
buf := make([]byte, 2)
if _, err := io.ReadFull(c, buf); err != nil {
utils.Println("negotiation err", err)
lib.Println("negotiation err", err)
c.Close()
return
}
if version := buf[0]; version != 5 {
utils.Println("only support socks5, request from: ", c.RemoteAddr())
lib.Println("only support socks5, request from: ", c.RemoteAddr())
c.Close()
return
}
@ -201,7 +201,7 @@ func (s *Sock5ModeServer) handleConn(c net.Conn) {
methods := make([]byte, nMethods)
if len, err := c.Read(methods); len != int(nMethods) || err != nil {
utils.Println("wrong method")
lib.Println("wrong method")
c.Close()
return
}
@ -210,7 +210,7 @@ func (s *Sock5ModeServer) handleConn(c net.Conn) {
c.Write(buf)
if err := s.Auth(c); err != nil {
c.Close()
utils.Println("验证失败:", err)
lib.Println("验证失败:", err)
return
}
} else {
@ -269,7 +269,7 @@ func (s *Sock5ModeServer) Start() error {
if strings.Contains(err.Error(), "use of closed network connection") {
break
}
utils.Fatalln("accept error: ", err)
lib.Fatalln("accept error: ", err)
}
if !s.ResetConfig() {
conn.Close()
@ -286,11 +286,11 @@ func (s *Sock5ModeServer) Close() error {
}
//new
func NewSock5ModeServer(bridge *bridge.Bridge, task *utils.Tunnel) *Sock5ModeServer {
func NewSock5ModeServer(bridge *bridge.Bridge, task *lib.Tunnel) *Sock5ModeServer {
s := new(Sock5ModeServer)
s.bridge = bridge
s.task = task
s.config = utils.DeepCopyConfig(task.Config)
s.config = lib.DeepCopyConfig(task.Config)
if s.config.U != "" && s.config.P != "" {
s.isVerify = true
} else {

View File

@ -4,7 +4,7 @@ import (
"errors"
"github.com/astaxie/beego"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
"net"
"strings"
)
@ -16,12 +16,12 @@ type TunnelModeServer struct {
}
//tcp|http|host
func NewTunnelModeServer(process process, bridge *bridge.Bridge, task *utils.Tunnel) *TunnelModeServer {
func NewTunnelModeServer(process process, bridge *bridge.Bridge, task *lib.Tunnel) *TunnelModeServer {
s := new(TunnelModeServer)
s.bridge = bridge
s.process = process
s.task = task
s.config = utils.DeepCopyConfig(task.Config)
s.config = lib.DeepCopyConfig(task.Config)
return s
}
@ -38,17 +38,17 @@ func (s *TunnelModeServer) Start() error {
if strings.Contains(err.Error(), "use of closed network connection") {
break
}
utils.Println(err)
lib.Println(err)
continue
}
go s.process(utils.NewConn(conn), s)
go s.process(lib.NewConn(conn), s)
}
return nil
}
//与客户端建立通道
func (s *TunnelModeServer) dealClient(c *utils.Conn, cnf *utils.Config, addr string, method string, rb []byte) error {
link := utils.NewLink(s.task.Client.GetId(), utils.CONN_TCP, addr, cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, c, s.task.Flow, nil, s.task.Client.Rate, nil)
func (s *TunnelModeServer) dealClient(c *lib.Conn, cnf *lib.Config, addr string, method string, rb []byte) error {
link := lib.NewLink(s.task.Client.GetId(), lib.CONN_TCP, addr, cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, c, s.task.Flow, nil, s.task.Client.Rate, nil)
if tunnel, err := s.bridge.SendLinkInfo(s.task.Client.Id, link); err != nil {
c.Close()
@ -72,7 +72,7 @@ type WebServer struct {
//开始
func (s *WebServer) Start() error {
beego.BConfig.WebConfig.Session.SessionOn = true
utils.Println("web管理启动访问端口为", beego.AppConfig.String("httpport"))
lib.Println("web管理启动访问端口为", beego.AppConfig.String("httpport"))
beego.SetViewsPath(beego.AppPath + "/web/views")
beego.SetStaticPath("/static", beego.AppPath+"/web/static")
beego.Run()
@ -96,10 +96,10 @@ func (s *HostServer) Start() error {
return nil
}
func NewHostServer(task *utils.Tunnel) *HostServer {
func NewHostServer(task *lib.Tunnel) *HostServer {
s := new(HostServer)
s.task = task
s.config = utils.DeepCopyConfig(task.Config)
s.config = lib.DeepCopyConfig(task.Config)
return s
}
@ -108,10 +108,10 @@ func (s *HostServer) Close() error {
return nil
}
type process func(c *utils.Conn, s *TunnelModeServer) error
type process func(c *lib.Conn, s *TunnelModeServer) error
//tcp隧道模式
func ProcessTunnel(c *utils.Conn, s *TunnelModeServer) error {
func ProcessTunnel(c *lib.Conn, s *TunnelModeServer) error {
if !s.ResetConfig() {
c.Close()
return errors.New("流量超出")
@ -120,7 +120,7 @@ func ProcessTunnel(c *utils.Conn, s *TunnelModeServer) error {
}
//http代理模式
func ProcessHttp(c *utils.Conn, s *TunnelModeServer) error {
func ProcessHttp(c *lib.Conn, s *TunnelModeServer) error {
if !s.ResetConfig() {
c.Close()
return errors.New("流量超出")

View File

@ -2,7 +2,7 @@ package server
import (
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
"net"
"strings"
)
@ -10,15 +10,15 @@ import (
type UdpModeServer struct {
server
listener *net.UDPConn
udpMap map[string]*utils.Conn
udpMap map[string]*lib.Conn
}
func NewUdpModeServer(bridge *bridge.Bridge, task *utils.Tunnel) *UdpModeServer {
func NewUdpModeServer(bridge *bridge.Bridge, task *lib.Tunnel) *UdpModeServer {
s := new(UdpModeServer)
s.bridge = bridge
s.udpMap = make(map[string]*utils.Conn)
s.udpMap = make(map[string]*lib.Conn)
s.task = task
s.config = utils.DeepCopyConfig(task.Config)
s.config = lib.DeepCopyConfig(task.Config)
return s
}
@ -29,7 +29,7 @@ func (s *UdpModeServer) Start() error {
if err != nil {
return err
}
buf := utils.BufPoolUdp.Get().([]byte)
buf := lib.BufPoolUdp.Get().([]byte)
for {
n, addr, err := s.listener.ReadFromUDP(buf)
if err != nil {
@ -47,7 +47,7 @@ func (s *UdpModeServer) Start() error {
}
func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
link := utils.NewLink(s.task.Client.GetId(), utils.CONN_UDP, s.task.Target, s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, nil, s.task.Flow, s.listener, s.task.Client.Rate, addr)
link := lib.NewLink(s.task.Client.GetId(), lib.CONN_UDP, s.task.Target, s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, nil, s.task.Flow, s.listener, s.task.Client.Rate, addr)
if tunnel, err := s.bridge.SendLinkInfo(s.task.Client.Id, link); err != nil {
return

View File

@ -3,7 +3,7 @@ package controllers
import (
"github.com/astaxie/beego"
"github.com/cnlh/nps/server"
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
"strconv"
"strings"
)
@ -40,7 +40,7 @@ func (s *BaseController) display(tpl ...string) {
}
ip := s.Ctx.Request.Host
if strings.LastIndex(ip, ":") > 0 {
arr := strings.Split(utils.GetHostByName(ip), ":")
arr := strings.Split(lib.GetHostByName(ip), ":")
s.Data["ip"] = arr[0]
}
s.Data["p"] = server.Bridge.TunnelPort

View File

@ -2,7 +2,7 @@ package controllers
import (
"github.com/cnlh/nps/server"
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
)
type ClientController struct {
@ -28,26 +28,26 @@ func (s *ClientController) Add() {
s.SetInfo("新增")
s.display()
} else {
t := &utils.Client{
VerifyKey: utils.GetRandomString(16),
t := &lib.Client{
VerifyKey: lib.GetRandomString(16),
Id: server.CsvDb.GetClientId(),
Status: true,
Remark: s.GetString("remark"),
Cnf: &utils.Config{
Cnf: &lib.Config{
U: s.GetString("u"),
P: s.GetString("p"),
Compress: s.GetString("compress"),
Crypt: s.GetBoolNoErr("crypt"),
},
RateLimit: s.GetIntNoErr("rate_limit"),
Flow: &utils.Flow{
Flow: &lib.Flow{
ExportFlow: 0,
InletFlow: 0,
FlowLimit: int64(s.GetIntNoErr("flow_limit")),
},
}
if t.RateLimit > 0 {
t.Rate = utils.NewRate(int64(t.RateLimit * 1024))
t.Rate = lib.NewRate(int64(t.RateLimit * 1024))
t.Rate.Start()
}
server.CsvDb.NewClient(t)
@ -96,7 +96,7 @@ func (s *ClientController) Edit() {
c.Rate.Stop()
}
if c.RateLimit > 0 {
c.Rate = utils.NewRate(int64(c.RateLimit * 1024))
c.Rate = lib.NewRate(int64(c.RateLimit * 1024))
c.Rate.Start()
} else {
c.Rate = nil

View File

@ -2,7 +2,7 @@ package controllers
import (
"github.com/cnlh/nps/server"
"github.com/cnlh/nps/utils"
"github.com/cnlh/nps/lib"
)
type IndexController struct {
@ -72,11 +72,11 @@ func (s *IndexController) Add() {
s.SetInfo("新增")
s.display()
} else {
t := &utils.Tunnel{
t := &lib.Tunnel{
TcpPort: s.GetIntNoErr("port"),
Mode: s.GetString("type"),
Target: s.GetString("target"),
Config: &utils.Config{
Config: &lib.Config{
U: s.GetString("u"),
P: s.GetString("p"),
Compress: s.GetString("compress"),
@ -86,7 +86,7 @@ func (s *IndexController) Add() {
UseClientCnf: s.GetBoolNoErr("use_client"),
Status: true,
Remark: s.GetString("remark"),
Flow: &utils.Flow{},
Flow: &lib.Flow{},
}
var err error
if t.Client, err = server.CsvDb.GetClient(s.GetIntNoErr("client_id")); err != nil {
@ -213,13 +213,13 @@ func (s *IndexController) AddHost() {
s.SetInfo("新增")
s.display("index/hadd")
} else {
h := &utils.Host{
h := &lib.Host{
Host: s.GetString("host"),
Target: s.GetString("target"),
HeaderChange: s.GetString("header"),
HostChange: s.GetString("hostchange"),
Remark: s.GetString("remark"),
Flow: &utils.Flow{},
Flow: &lib.Flow{},
}
var err error
if h.Client, err = server.CsvDb.GetClient(s.GetIntNoErr("client_id")); err != nil {