客户端配置,端口白名单等

pull/59/head
刘河 2019-02-13 03:54:00 +08:00
parent 59d789d253
commit 44d314515b
34 changed files with 1096 additions and 472 deletions

View File

@ -1,13 +1,17 @@
package bridge
import (
"encoding/binary"
"errors"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/kcp"
"github.com/cnlh/nps/lib/lg"
"github.com/cnlh/nps/lib/pool"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/server/tool"
"log"
"net"
"strconv"
"sync"
@ -38,19 +42,21 @@ type Bridge struct {
tcpListener *net.TCPListener //server端监听
kcpListener *kcp.Listener //server端监听
Client map[int]*Client
RunList map[int]interface{} //运行中的任务
tunnelType string //bridge type kcp or tcp
tunnelType string //bridge type kcp or tcp
OpenTask chan *file.Tunnel
CloseClient chan int
lock sync.Mutex
tunnelLock sync.Mutex
clientLock sync.RWMutex
}
func NewTunnel(tunnelPort int, runList map[int]interface{}, tunnelType string) *Bridge {
func NewTunnel(tunnelPort int, tunnelType string) *Bridge {
t := new(Bridge)
t.TunnelPort = tunnelPort
t.Client = make(map[int]*Client)
t.RunList = runList
t.tunnelType = tunnelType
t.OpenTask = make(chan *file.Tunnel)
t.CloseClient = make(chan int)
return t
}
@ -97,6 +103,10 @@ func (s *Bridge) verifyError(c *conn.Conn) {
c.Conn.Close()
}
func (s *Bridge) verifySuccess(c *conn.Conn) {
c.Write([]byte(common.VERIFY_SUCCESS))
}
func (s *Bridge) cliProcess(c *conn.Conn) {
c.SetReadDeadline(5, s.tunnelType)
var buf []byte
@ -111,10 +121,15 @@ func (s *Bridge) cliProcess(c *conn.Conn) {
lg.Println("当前客户端连接校验错误,关闭此客户端:", c.Conn.RemoteAddr())
s.verifyError(c)
return
} else {
s.verifySuccess(c)
}
//做一个判断 添加到对应的channel里面以供使用
if flag, err := c.ReadFlag(); err == nil {
s.typeDeal(flag, c, id)
} else {
log.Println(222)
log.Println(err, flag)
}
return
}
@ -123,6 +138,9 @@ func (s *Bridge) closeClient(id int) {
s.clientLock.Lock()
defer s.clientLock.Unlock()
if v, ok := s.Client[id]; ok {
if c, err := file.GetCsvDb().GetClient(id); err == nil && c.NoStore {
s.CloseClient <- c.Id
}
v.signal.WriteClose()
delete(s.Client, id)
}
@ -146,7 +164,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) {
s.Client[id] = NewClient(nil, c)
s.clientLock.Unlock()
}
lg.Printf("客户端%d连接成功,地址为:%s", id, c.Conn.RemoteAddr())
lg.Printf("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr())
go s.GetStatus(id)
case common.WORK_CHAN:
s.clientLock.Lock()
@ -160,6 +178,8 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) {
s.clientLock.Unlock()
}
go s.clientCopy(id)
case common.WORK_CONFIG:
go s.GetConfig(c)
}
c.SetAlive(s.tunnelType)
return
@ -198,12 +218,12 @@ func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link) (tunnel *conn.Conn,
s.clientLock.Unlock()
v.signal.SendLinkInfo(link)
if err != nil {
lg.Println("send error:", err, link.Id)
lg.Println("send link information error:", err, link.Id)
s.DelClient(clientId)
return
}
if v.tunnel == nil {
err = errors.New("tunnel获取错误")
err = errors.New("get tunnel connection error")
return
} else {
tunnel = v.tunnel
@ -212,36 +232,12 @@ func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link) (tunnel *conn.Conn,
v.linkMap[link.Id] = link
v.Unlock()
if !s.waitStatus(clientId, link.Id) {
err = errors.New("连接失败")
err = errors.New("connect fail")
return
}
} else {
s.clientLock.Unlock()
err = errors.New("客户端未连接")
}
return
}
//得到一个tcp隧道
func (s *Bridge) GetTunnel(id int, en, de int, crypt, mux bool) (conn *conn.Conn, err error) {
s.clientLock.Lock()
defer s.clientLock.Unlock()
if v, ok := s.Client[id]; !ok {
err = errors.New("客户端未连接")
} else {
conn = v.tunnel
}
return
}
//得到一个通信通道
func (s *Bridge) GetSignal(id int) (conn *conn.Conn, err error) {
s.clientLock.Lock()
defer s.clientLock.Unlock()
if v, ok := s.Client[id]; !ok {
err = errors.New("客户端未连接")
} else {
conn = v.signal
err = errors.New("the connection is not connect")
}
return
}
@ -251,14 +247,91 @@ func (s *Bridge) DelClient(id int) {
s.closeClient(id)
}
func (s *Bridge) verify(id int) bool {
for k := range s.RunList {
if k == id {
return true
//get config
func (s *Bridge) GetConfig(c *conn.Conn) {
var client *file.Client
var fail bool
for {
flag, err := c.ReadFlag()
if err != nil {
break
}
switch flag {
case common.WORK_STATUS:
if b, err := c.ReadLen(16); err != nil {
break
} else {
var str string
id, err := file.GetCsvDb().GetClientIdByVkey(string(b))
if err != nil {
break
}
for _, v := range file.GetCsvDb().Hosts {
if v.Client.Id == id {
str += v.Remark + common.CONN_DATA_SEQ
}
}
for _, v := range file.GetCsvDb().Tasks {
if v.Client.Id == id {
str += v.Remark + common.CONN_DATA_SEQ
}
}
binary.Write(c, binary.LittleEndian, int32(len([]byte(str))))
binary.Write(c, binary.LittleEndian, []byte(str))
}
case common.NEW_CONF:
//new client ,Set the client not to store to the file
client = file.NewClient(crypt.GetRandomString(16), true, false)
client.Remark = "public veky"
//Send the key to the client
file.GetCsvDb().NewClient(client)
c.Write([]byte(client.VerifyKey))
if config, err := c.GetConfigInfo(); err != nil {
fail = true
c.WriteAddFail()
break
} else {
client.Cnf = config
c.WriteAddOk()
}
case common.NEW_HOST:
if h, err := c.GetHostInfo(); err != nil {
fail = true
c.WriteAddFail()
break
} else if file.GetCsvDb().IsHostExist(h.Host) {
fail = true
c.WriteAddFail()
} else {
h.Client = client
file.GetCsvDb().NewHost(h)
c.WriteAddOk()
}
case common.NEW_TASK:
if t, err := c.GetTaskInfo(); err != nil {
fail = true
c.WriteAddFail()
break
} else {
t.Client = client
file.GetCsvDb().NewTask(t)
if b := tool.TestServerPort(t.Port, t.Mode); !b {
fail = true
c.WriteAddFail()
} else {
s.OpenTask <- t
}
c.WriteAddOk()
}
}
}
return false
if fail && client != nil {
s.CloseClient <- client.Id
}
c.Close()
}
func (s *Bridge) GetStatus(clientId int) {
s.clientLock.Lock()
client := s.Client[clientId]

View File

@ -1,12 +1,16 @@
package client
import (
"errors"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/config"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/kcp"
"github.com/cnlh/nps/lib/lg"
"github.com/cnlh/nps/lib/pool"
"io/ioutil"
"net"
"path/filepath"
"sync"
"time"
)
@ -14,9 +18,9 @@ import (
type TRPClient struct {
svrAddr string
linkMap map[int]*conn.Link
stop chan bool
tunnel *conn.Conn
bridgeConnType string
stop chan bool
sync.Mutex
vKey string
}
@ -26,81 +30,70 @@ func NewRPClient(svraddr string, vKey string, bridgeConnType string) *TRPClient
return &TRPClient{
svrAddr: svraddr,
linkMap: make(map[int]*conn.Link),
stop: make(chan bool),
Mutex: sync.Mutex{},
vKey: vKey,
bridgeConnType: bridgeConnType,
stop: make(chan bool),
}
}
//start
func (s *TRPClient) Start() error {
s.NewConn()
return nil
}
//新建
func (s *TRPClient) NewConn() {
var err error
var c net.Conn
func (s *TRPClient) Start() {
retry:
if s.bridgeConnType == "tcp" {
c, err = net.Dial("tcp", s.svrAddr)
} else {
var sess *kcp.UDPSession
sess, err = kcp.DialWithOptions(s.svrAddr, nil, 150, 3)
conn.SetUdpSession(sess)
c = sess
}
c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN)
if err != nil {
lg.Println("连接服务端失败,五秒后将重连")
lg.Println("The connection server failed and will be reconnected in five seconds")
time.Sleep(time.Second * 5)
goto retry
return
}
s.processor(conn.NewConn(c))
lg.Printf("Successful connection with server %s", s.svrAddr)
s.processor(c)
}
func (s *TRPClient) Close() {
s.tunnel.Close()
s.stop <- true
for _, v := range s.linkMap {
v.Stop <- true
}
}
//处理
func (s *TRPClient) processor(c *conn.Conn) {
c.SetAlive(s.bridgeConnType)
if _, err := c.Write([]byte(common.Getverifyval(s.vKey))); err != nil {
return
}
c.WriteMain()
go s.dealChan()
for {
flags, err := c.ReadFlag()
if err != nil {
lg.Println("服务端断开,正在重新连接")
lg.Printf("Accept server data error %s, end this service", err.Error())
break
}
switch flags {
case common.VERIFY_EER:
lg.Fatalf("vKey:%s不正确,服务端拒绝连接,请检查", s.vKey)
lg.Fatalf("VKey:%s is incorrect, the server refuses to connect, please check", s.vKey)
case common.NEW_CONN:
if link, err := c.GetLinkInfo(); err != nil {
break
} else {
link.Stop = make(chan bool)
s.Lock()
s.linkMap[link.Id] = link
s.Unlock()
go s.linkProcess(link, c)
}
case common.RES_CLOSE:
lg.Fatalln("该vkey被另一客户连接")
lg.Fatalln("The authentication key is connected by another client or the server closes the client.")
case common.RES_MSG:
lg.Println("服务端返回错误,重新连接")
lg.Println("Server-side return error")
break
default:
lg.Println("无法解析该错误,重新连接")
lg.Println("The error could not be resolved")
break
}
}
s.stop <- true
s.linkMap = make(map[int]*conn.Link)
go s.NewConn()
c.Close()
s.Close()
}
func (s *TRPClient) linkProcess(link *conn.Link, c *conn.Conn) {
//与目标建立连接
server, err := net.DialTimeout(link.ConnType, link.Host, time.Second*3)
@ -113,56 +106,40 @@ func (s *TRPClient) linkProcess(link *conn.Link, c *conn.Conn) {
c.WriteSuccess(link.Id)
link.Conn = conn.NewConn(server)
buf := pool.BufPoolCopy.Get().([]byte)
for {
if n, err := server.Read(buf); err != nil {
s.tunnel.SendMsg([]byte(common.IO_EOF), link)
break
} else {
if _, err := s.tunnel.SendMsg(buf[:n], link); err != nil {
c.Close()
go func() {
link.Conn = conn.NewConn(server)
buf := pool.BufPoolCopy.Get().([]byte)
for {
if n, err := server.Read(buf); err != nil {
s.tunnel.SendMsg([]byte(common.IO_EOF), link)
break
} else {
if _, err := s.tunnel.SendMsg(buf[:n], link); err != nil {
c.Close()
break
}
}
}
}
pool.PutBufPoolCopy(buf)
s.Lock()
delete(s.linkMap, link.Id)
s.Unlock()
pool.PutBufPoolCopy(buf)
s.Lock()
delete(s.linkMap, link.Id)
s.Unlock()
}()
<-link.Stop
}
//隧道模式处理
func (s *TRPClient) dealChan() {
var err error
var c net.Conn
var sess *kcp.UDPSession
if s.bridgeConnType == "tcp" {
c, err = net.Dial("tcp", s.svrAddr)
} else {
sess, err = kcp.DialWithOptions(s.svrAddr, nil, 10, 3)
conn.SetUdpSession(sess)
c = sess
}
s.tunnel, err = NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_CHAN)
if err != nil {
lg.Println("connect to ", s.svrAddr, "error:", err)
return
}
//验证
if _, err := c.Write([]byte(common.Getverifyval(s.vKey))); err != nil {
lg.Println("connect to ", s.svrAddr, "error:", err)
return
}
//默认长连接保持
s.tunnel = conn.NewConn(c)
s.tunnel.SetAlive(s.bridgeConnType)
//写标志
s.tunnel.WriteChan()
go func() {
for {
if id, err := s.tunnel.GetLen(); err != nil {
lg.Println("get msg id error")
break
} else {
s.Lock()
@ -186,8 +163,103 @@ func (s *TRPClient) dealChan() {
}
}
}()
select {
case <-s.stop:
break
}
<-s.stop
}
var errAdd = errors.New("The server returned an error, which port or host may have been occupied or not allowed to open.")
func StartFromFile(path string) {
first := true
cnf, err := config.NewConfig(path)
if err != nil {
lg.Fatalln(err)
}
lg.Printf("Loading configuration file %s successfully", path)
re:
if first || cnf.CommonConfig.AutoReconnection {
if !first {
lg.Println("Reconnecting...")
time.Sleep(time.Second * 5)
}
} else {
return
}
first = false
c, err := NewConn(cnf.CommonConfig.Tp, cnf.CommonConfig.VKey, cnf.CommonConfig.Server, common.WORK_CONFIG)
if err != nil {
lg.Println(err)
goto re
}
if _, err := c.SendConfigInfo(cnf.CommonConfig.Cnf); err != nil {
lg.Println(err)
goto re
}
var b []byte
if b, err = c.ReadLen(16); err != nil {
lg.Println(err)
goto re
} else {
ioutil.WriteFile(filepath.Join(common.GetTmpPath(), "npc_vkey.txt"), []byte(string(b)), 0600)
}
if !c.GetAddStatus() {
lg.Println(errAdd)
goto re
}
for _, v := range cnf.Hosts {
if _, err := c.SendHostInfo(v); err != nil {
lg.Println(err)
goto re
}
if !c.GetAddStatus() {
lg.Println(errAdd, v.Host)
goto re
}
}
for _, v := range cnf.Tasks {
if _, err := c.SendTaskInfo(v); err != nil {
lg.Println(err)
goto re
}
if !c.GetAddStatus() {
lg.Println(errAdd, v.Port)
goto re
}
}
c.Close()
NewRPClient(cnf.CommonConfig.Server, string(b), cnf.CommonConfig.Tp).Start()
goto re
}
//Create a new connection with the server and verify it
func NewConn(tp string, vkey string, server string, connType string) (*conn.Conn, error) {
var err error
var connection net.Conn
var sess *kcp.UDPSession
if tp == "tcp" {
connection, err = net.Dial("tcp", server)
} else {
sess, err = kcp.DialWithOptions(server, nil, 10, 3)
conn.SetUdpSession(sess)
connection = sess
}
if err != nil {
return nil, err
}
c := conn.NewConn(connection)
if _, err := c.Write([]byte(common.Getverifyval(vkey))); err != nil {
lg.Println(err)
}
if s, err := c.ReadFlag(); err != nil {
lg.Println(err)
} else if s == common.VERIFY_EER {
lg.Fatalf("Validation key %s incorrect", vkey)
}
if _, err := c.Write([]byte(connType)); err != nil {
lg.Println(err)
}
c.SetAlive(tp)
return c, nil
}

74
client/client_test.go Normal file
View File

@ -0,0 +1,74 @@
package client
import (
"github.com/cnlh/nps/lib/common"
conn2 "github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file"
"net"
"sync"
"testing"
)
func TestConfig(t *testing.T) {
conn, err := net.Dial("tcp", "127.0.0.1:8284")
if err != nil {
t.Fail()
}
c := conn2.NewConn(conn)
c.SetAlive("tcp")
if _, err := c.Write([]byte(common.Getverifyval("123"))); err != nil {
t.Fail()
}
c.WriteConfig()
config := &file.Config{
U: "1",
P: "2",
Compress: "snappy",
Crypt: true,
CompressEncode: 0,
CompressDecode: 0,
}
host := &file.Host{
Host: "a.o.com",
Target: "127.0.0.1:8080",
HeaderChange: "",
HostChange: "",
Flow: nil,
Client: nil,
Remark: "111",
NowIndex: 0,
TargetArr: nil,
NoStore: false,
RWMutex: sync.RWMutex{},
}
tunnel := &file.Tunnel{
Port: 9001,
Mode: "tunnelServer",
Target: "127.0.0.1:8082",
Remark: "333",
}
var b []byte
if b, err = c.ReadLen(16); err != nil {
t.Fail()
}
if _, err := c.SendConfigInfo(config); err != nil {
t.Fail()
}
if !c.GetAddStatus() {
t.Fail()
}
if _, err := c.SendHostInfo(host); err != nil {
t.Fail()
}
if !c.GetAddStatus() {
t.Fail()
}
if _, err := c.SendTaskInfo(tunnel); err != nil {
t.Fail()
}
if !c.GetAddStatus() {
t.Fail()
}
c.Close()
NewRPClient("127.0.0.1:8284", string(b), "tcp").Start()
}

View File

@ -3,33 +3,81 @@ package main
import (
"flag"
"github.com/cnlh/nps/client"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/config"
"github.com/cnlh/nps/lib/daemon"
"github.com/cnlh/nps/lib/lg"
"github.com/cnlh/nps/lib/common"
"log"
"os"
"path/filepath"
"strings"
)
const VERSION = "v0.0.13"
const VERSION = "v0.0.15"
var (
serverAddr = flag.String("server", "", "服务器地址ip:端口")
verifyKey = flag.String("vkey", "", "验证密钥")
logType = flag.String("log", "stdout", "日志输出方式stdout|file")
connType = flag.String("type", "tcp", "与服务端建立连接方式kcp|tcp")
serverAddr = flag.String("server", "", "Server addr (ip:port)")
configPath = flag.String("config", "npc.conf", "Configuration file path")
verifyKey = flag.String("vkey", "", "Authentication key")
logType = flag.String("log", "stdout", "Log output modestdout|file")
connType = flag.String("type", "tcp", "Connection type with the serverkcp|tcp")
)
func main() {
flag.Parse()
daemon.InitDaemon("npc", common.GetRunPath(), common.GetPidPath())
if len(os.Args) > 2 {
switch os.Args[1] {
case "status":
path := strings.Replace(os.Args[2], "-config=", "", -1)
cnf, err := config.NewConfig(path)
if err != nil {
log.Fatalln(err)
}
c, err := client.NewConn(cnf.CommonConfig.Tp, cnf.CommonConfig.VKey, cnf.CommonConfig.Server, common.WORK_CONFIG)
if err != nil {
log.Fatalln(err)
}
if _, err := c.Write([]byte(common.WORK_STATUS)); err != nil {
log.Fatalln(err)
}
if f, err := common.ReadAllFromFile(filepath.Join(common.GetTmpPath(), "npc_vkey.txt")); err != nil {
log.Fatalln(err)
} else if _, err := c.Write([]byte(string(f))); err != nil {
log.Fatalln(err)
}
if l, err := c.GetLen(); err != nil {
log.Fatalln(err)
} else if b, err := c.ReadLen(l); err != nil {
lg.Fatalln(err)
} else {
arr := strings.Split(string(b), common.CONN_DATA_SEQ)
for _, v := range cnf.Hosts {
if common.InArr(arr, v.Remark) {
log.Println(v.Remark, "ok")
} else {
log.Println(v.Remark, "not running")
}
}
for _, v := range cnf.Tasks {
if common.InArr(arr, v.Remark) {
log.Println(v.Remark, "ok")
} else {
log.Println(v.Remark, "not running")
}
}
}
return
}
}
daemon.InitDaemon("npc", common.GetRunPath(), common.GetTmpPath())
if *logType == "stdout" {
lg.InitLogFile("npc", true, common.GetLogPath())
} else {
lg.InitLogFile("npc", false, common.GetLogPath())
}
stop := make(chan int)
for _, v := range strings.Split(*verifyKey, ",") {
lg.Println("客户端启动,连接:", *serverAddr, " 验证令牌:", v)
go client.NewRPClient(*serverAddr, v, *connType).Start()
if *verifyKey != "" && *serverAddr != "" {
client.NewRPClient(*serverAddr, *verifyKey, *connType).Start()
} else {
client.StartFromFile(*configPath)
}
<-stop
}

View File

@ -9,25 +9,17 @@ import (
"github.com/cnlh/nps/lib/install"
"github.com/cnlh/nps/lib/lg"
"github.com/cnlh/nps/server"
"github.com/cnlh/nps/server/test"
_ "github.com/cnlh/nps/web/routers"
"log"
"os"
"path/filepath"
)
const VERSION = "v0.0.13"
const VERSION = "v0.0.15"
var (
TcpPort = flag.Int("tcpport", 0, "客户端与服务端通信端口")
httpPort = flag.Int("httpport", 8024, "对外监听的端口")
rpMode = flag.String("mode", "webServer", "启动模式")
tunnelTarget = flag.String("target", "127.0.0.1:80", "远程目标")
VerifyKey = flag.String("vkey", "", "验证密钥")
u = flag.String("u", "", "验证用户名(socks5和web)")
p = flag.String("p", "", "验证密码(socks5和web)")
compress = flag.String("compress", "", "数据压缩方式snappy")
crypt = flag.String("crypt", "false", "是否加密(true|false)")
logType = flag.String("log", "stdout", "日志输出方式stdout|file")
logType = flag.String("log", "stdout", "Log output modestdout|file")
)
func main() {
@ -35,11 +27,11 @@ func main() {
if len(os.Args) > 1 {
switch os.Args[1] {
case "test":
server.TestServerConfig()
test.TestServerConfig()
log.Println("test ok, no error")
return
case "start", "restart", "stop", "status":
daemon.InitDaemon("nps", common.GetRunPath(), common.GetPidPath())
daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath())
case "install":
install.InstallNps()
return
@ -51,46 +43,12 @@ func main() {
lg.InitLogFile("nps", false, common.GetLogPath())
}
task := &file.Tunnel{
TcpPort: *httpPort,
Mode: *rpMode,
Target: *tunnelTarget,
Config: &file.Config{
U: *u,
P: *p,
Compress: *compress,
Crypt: common.GetBoolByStr(*crypt),
},
Flow: &file.Flow{},
UseClientCnf: false,
Mode: "webServer",
}
if *VerifyKey != "" {
c := &file.Client{
Id: 0,
VerifyKey: *VerifyKey,
Addr: "",
Remark: "",
Status: true,
IsConnect: false,
Cnf: &file.Config{},
Flow: &file.Flow{},
}
c.Cnf.CompressDecode, c.Cnf.CompressEncode = common.GetCompressType(c.Cnf.Compress)
file.GetCsvDb().Clients[0] = c
task.Client = c
}
if *TcpPort == 0 {
p, err := beego.AppConfig.Int("bridgePort")
if err == nil && *rpMode == "webServer" {
*TcpPort = p
} else {
*TcpPort = 8284
}
}
lg.Printf("服务端启动,监听%s服务端口%d", beego.AppConfig.String("bridgeType"), *TcpPort)
task.Config.CompressDecode, task.Config.CompressEncode = common.GetCompressType(task.Config.Compress)
if *rpMode != "webServer" {
file.GetCsvDb().Tasks[0] = task
bridgePort, err := beego.AppConfig.Int("bridgePort")
if err != nil {
lg.Fatalln("Getting bridgePort error", err)
}
beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "app.conf"))
server.StartNewServer(*TcpPort, task, beego.AppConfig.String("bridgeType"))
server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridgeType"))
}

View File

@ -30,4 +30,11 @@ pemPath=/etc/nginx/certificate.crt
keyPath=/etc/nginx/private.key
##Data transmission mode(kcp or tcp)
bridgeType=tcp
bridgeType=tcp
# Public password, which clients can use to connect to the server
# After the connection, the server will be able to open relevant ports and parse related domain names according to its own configuration file.
publicVkey=123
#Open ports allowed on the server side
allowPorts=9001-9009,10001,11000-12000

View File

@ -1 +0,0 @@
1,ydiigrm4ghu7mym1,测试,true,,,0,,0,0
1 1 ydiigrm4ghu7mym1 测试 true 0 0 0
1 ydiigrm4ghu7mym1 测试 true 0 0 0

View File

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

33
conf/npc.conf Normal file
View File

@ -0,0 +1,33 @@
[common]
server=127.0.0.1:8284
tp=tcp
vkey=123
username=111
password=222
compress=snappy
crypt=true
auto_reconnection=true
[web1]
host=a.o.com
host_change=www.sina.com
target=127.0.0.1:8080,127.0.0.1:8082
header_cookkile=122123
header_user-Agent=122123
[web2]
host=www.baidu.com
host_change=www.sina.com
target=127.0.0.1:8080,127.0.0.1:8082
header_cookkile="122123"
header_user-Agent=122123
[tunnel1]
mode=udpServer
target=127.0.0.1:8080
port=9001
[tunnel2]
mode=tunnelServer
target=127.0.0.1:8080
port=9001
[tunnel3]
mode=tunnelServer
target=127.0.0.1:8080
port=9002

View File

@ -1,4 +0,0 @@
53,udpServer,114.114.114.114:53,,,,1,0,0,0,2,1,true,udp
9005,httpProxyServer,,,,,1,0,0,0,4,1,true,
9002,socks5Server,,,,,1,0,0,0,3,1,true,socks5
9001,tunnelServer,127.0.0.1:8082,,,,1,0,0,0,1,1,true,测试tcp
1 53 udpServer 114.114.114.114:53 1 0 0 0 2 1 true udp
53 udpServer 114.114.114.114:53 1 0 0 0 2 1 true udp
9005 httpProxyServer 1 0 0 0 4 1 true
9002 socks5Server 1 0 0 0 3 1 true socks5
9001 tunnelServer 127.0.0.1:8082 1 0 0 0 1 1 true 测试tcp

View File

@ -1,19 +1,25 @@
package common
const (
CONN_DATA_SEQ = "*#*"
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" //新连接标志
NEW_TASK = "task" //新连接标志
CONN_SUCCESS = "sucs"
VERIFY_EER = "vkey"
VERIFY_SUCCESS = "sucs"
WORK_MAIN = "main"
WORK_CHAN = "chan"
WORK_CONFIG = "conf"
WORK_STATUS = "stus"
RES_SIGN = "sign"
RES_MSG = "msg0"
RES_CLOSE = "clse"
NEW_CONN = "conn" //新连接标志
NEW_TASK = "task" //新连接标志
NEW_CONF = "conf" //新连接标志
NEW_HOST = "host" //新连接标志
CONN_TCP = "tcp"
CONN_UDP = "udp"
UnauthorizedBytes = `HTTP/1.1 401 Unauthorized

View File

@ -56,7 +56,7 @@ func GetLogPath() string {
}
//interface pid file path
func GetPidPath() string {
func GetTmpPath() string {
var path string
if IsWindows() {
path = "./"

View File

@ -144,7 +144,11 @@ func FileExists(name string) bool {
//Judge whether the TCP port can open normally
func TestTcpPort(port int) bool {
l, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), port, ""})
defer l.Close()
defer func() {
if l != nil {
l.Close()
}
}()
if err != nil {
return false
}
@ -154,7 +158,11 @@ func TestTcpPort(port int) bool {
//Judge whether the UDP port can open normally
func TestUdpPort(port int) bool {
l, err := net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), port, ""})
defer l.Close()
defer func() {
if l != nil {
l.Close()
}
}()
if err != nil {
return false
}
@ -168,9 +176,28 @@ func BinaryWrite(raw *bytes.Buffer, v ...string) {
buffer := new(bytes.Buffer)
var l int32
for _, v := range v {
l += int32(len([]byte(v))) + int32(len([]byte("#")))
l += int32(len([]byte(v))) + int32(len([]byte(CONN_DATA_SEQ)))
binary.Write(buffer, binary.LittleEndian, []byte(v))
binary.Write(buffer, binary.LittleEndian, []byte("#"))
binary.Write(buffer, binary.LittleEndian, []byte(CONN_DATA_SEQ))
}
binary.Write(raw, binary.LittleEndian, l)
binary.Write(raw, binary.LittleEndian, buffer.Bytes())
}
func InArr(arr []string, val string) bool {
for _, v := range arr {
if v == val {
return true
}
}
return false
}
func InIntArr(arr []int, val int) bool {
for _, v := range arr {
if v == val {
return true
}
}
return false
}

158
lib/config/config.go Normal file
View File

@ -0,0 +1,158 @@
package config
import (
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/file"
"regexp"
"strings"
)
type CommonConfig struct {
Server string
VKey string
Tp string //bridgeType kcp or tcp
AutoReconnection bool
Cnf *file.Config
}
type Config struct {
content string
title []string
CommonConfig *CommonConfig
Hosts []*file.Host
Tasks []*file.Tunnel
}
func NewConfig(path string) (c *Config, err error) {
c = new(Config)
var b []byte
if b, err = common.ReadAllFromFile(path); err != nil {
return
} else {
c.content = string(b)
if c.title, err = getAllTitle(c.content); err != nil {
return
}
var nowIndex int
var nextIndex int
var nowContent string
for i := 0; i < len(c.title); i++ {
nowIndex = strings.Index(c.content, c.title[i]) + len(c.title[i])
if i < len(c.title)-1 {
nextIndex = strings.Index(c.content, c.title[i+1])
} else {
nextIndex = len(c.content)
}
nowContent = c.content[nowIndex:nextIndex]
switch c.title[i] {
case "[common]":
c.CommonConfig = dealCommon(nowContent)
default:
if strings.Index(nowContent, "host") > -1 {
h := dealHost(nowContent)
h.Remark = getTitleContent(c.title[i])
c.Hosts = append(c.Hosts, h)
} else {
t := dealTunnel(nowContent)
t.Remark = getTitleContent(c.title[i])
c.Tasks = append(c.Tasks, t)
}
}
}
}
return
}
func getTitleContent(s string) string {
re, _ := regexp.Compile(`[\[\]]`)
return re.ReplaceAllString(s, "")
}
func dealCommon(s string) *CommonConfig {
c := &CommonConfig{}
c.Cnf = new(file.Config)
for _, v := range strings.Split(s, "\n") {
item := strings.Split(v, "=")
if len(item) == 0 {
continue
} else if len(item) == 1 {
item = append(item, "")
}
switch item[0] {
case "server":
c.Server = item[1]
case "vkey":
c.VKey = item[1]
case "tp":
c.Tp = item[1]
case "auto_reconnection":
c.AutoReconnection = common.GetBoolByStr(item[1])
case "username":
c.Cnf.U = item[1]
case "password":
c.Cnf.P = item[1]
case "compress":
c.Cnf.Compress = item[1]
case "crypt":
c.Cnf.Crypt = common.GetBoolByStr(item[1])
}
}
return c
}
func dealHost(s string) *file.Host {
h := &file.Host{}
var headerChange string
for _, v := range strings.Split(s, "\n") {
item := strings.Split(v, "=")
if len(item) == 0 {
continue
} else if len(item) == 1 {
item = append(item, "")
}
switch item[0] {
case "host":
h.Host = item[1]
case "target":
h.Target = strings.Replace(item[1], ",", "\n", -1)
case "host_change":
h.HostChange = item[1]
default:
if strings.Contains(item[0], "header") {
headerChange += strings.Replace(item[0], "header_", "", -1) + ":" + item[1] + "\n"
}
h.HeaderChange = headerChange
}
}
return h
}
func dealTunnel(s string) *file.Tunnel {
t := &file.Tunnel{}
for _, v := range strings.Split(s, "\n") {
item := strings.Split(v, "=")
if len(item) == 0 {
continue
} else if len(item) == 1 {
item = append(item, "")
}
switch item[0] {
case "port":
t.Port = common.GetIntNoErrByStr(item[1])
case "mode":
t.Mode = item[1]
case "target":
t.Target = item[1]
}
}
return t
}
func getAllTitle(content string) (arr []string, err error) {
var re *regexp.Regexp
re, err = regexp.Compile(`\[.+?\]`)
if err != nil {
return
}
arr = re.FindAllString(content, -1)
return
}

69
lib/config/config_test.go Normal file
View File

@ -0,0 +1,69 @@
package config
import (
"log"
"regexp"
"testing"
)
func TestReg(t *testing.T) {
content := `
[common]
server=127.0.0.1:8284
tp=tcp
vkey=123
[web2]
host=www.baidu.com
host_change=www.sina.com
target=127.0.0.1:8080,127.0.0.1:8082
header_cookkile=122123
header_user-Agent=122123
[web2]
host=www.baidu.com
host_change=www.sina.com
target=127.0.0.1:8080,127.0.0.1:8082
header_cookkile="122123"
header_user-Agent=122123
[tunnel1]
type=udp
target=127.0.0.1:8080
port=9001
compress=snappy
crypt=true
u=1
p=2
[tunnel2]
type=tcp
target=127.0.0.1:8080
port=9001
compress=snappy
crypt=true
u=1
p=2
`
re, err := regexp.Compile(`\[.+?\]`)
if err != nil {
t.Fail()
}
log.Println(re.FindAllString(content, -1))
}
func TestDealCommon(t *testing.T) {
s := `server=127.0.0.1:8284
tp=tcp
vkey=123`
f := new(CommonConfig)
f.Server = "127.0.0.1:8284"
f.Tp = "tcp"
f.VKey = "123"
if c := dealCommon(s); *c != *f {
t.Fail()
}
}
func TestGetTitleContent(t *testing.T) {
s := "[common]"
if getTitleContent(s) != "common" {
t.Fail()
}
}

View File

@ -264,6 +264,98 @@ func (s *Conn) GetLinkInfo() (lk *Link, err error) {
return
}
//send host info
func (s *Conn) SendHostInfo(h *file.Host) (int, error) {
/*
The task info is formed as follows:
+----+-----+---------+
|type| len | content |
+----+---------------+
| 4 | 4 | ... |
+----+---------------+
*/
raw := bytes.NewBuffer([]byte{})
binary.Write(raw, binary.LittleEndian, []byte(common.NEW_HOST))
common.BinaryWrite(raw, h.Host, h.Target, h.HeaderChange, h.HostChange, h.Remark)
s.Lock()
defer s.Unlock()
return s.Write(raw.Bytes())
}
func (s *Conn) GetAddStatus() (b bool) {
binary.Read(s.Conn, binary.LittleEndian, &b)
return
}
func (s *Conn) WriteAddOk() error {
return binary.Write(s.Conn, binary.LittleEndian, true)
}
func (s *Conn) WriteAddFail() error {
defer s.Close()
return binary.Write(s.Conn, binary.LittleEndian, false)
}
//get task info
func (s *Conn) GetHostInfo() (h *file.Host, err error) {
var l int
var b []byte
if l, err = s.GetLen(); err != nil {
return
} else if b, err = s.ReadLen(l); err != nil {
return
} else {
arr := strings.Split(string(b), common.CONN_DATA_SEQ)
h = new(file.Host)
h.Host = arr[0]
h.Target = arr[1]
h.HeaderChange = arr[2]
h.HostChange = arr[3]
h.Remark = arr[4]
h.Flow = new(file.Flow)
h.NoStore = true
}
return
}
//send task info
func (s *Conn) SendConfigInfo(c *file.Config) (int, error) {
/*
The task info is formed as follows:
+----+-----+---------+
|type| len | content |
+----+---------------+
| 4 | 4 | ... |
+----+---------------+
*/
raw := bytes.NewBuffer([]byte{})
binary.Write(raw, binary.LittleEndian, []byte(common.NEW_CONF))
common.BinaryWrite(raw, c.U, c.P, common.GetStrByBool(c.Crypt), c.Compress)
s.Lock()
defer s.Unlock()
return s.Write(raw.Bytes())
}
//get task info
func (s *Conn) GetConfigInfo() (c *file.Config, err error) {
var l int
var b []byte
if l, err = s.GetLen(); err != nil {
return
} else if b, err = s.ReadLen(l); err != nil {
return
} else {
arr := strings.Split(string(b), common.CONN_DATA_SEQ)
c = new(file.Config)
c.U = arr[0]
c.P = arr[1]
c.Crypt = common.GetBoolByStr(arr[2])
c.Compress = arr[3]
c.CompressDecode, c.CompressDecode = common.GetCompressType(arr[3])
}
return
}
//send task info
func (s *Conn) SendTaskInfo(t *file.Tunnel) (int, error) {
/*
@ -275,8 +367,8 @@ func (s *Conn) SendTaskInfo(t *file.Tunnel) (int, error) {
+----+---------------+
*/
raw := bytes.NewBuffer([]byte{})
binary.Write(raw, binary.LittleEndian, common.NEW_TASK)
common.BinaryWrite(raw, t.Mode, string(t.TcpPort), string(t.Target), string(t.Config.U), string(t.Config.P), common.GetStrByBool(t.Config.Crypt), t.Config.Compress, t.Remark)
binary.Write(raw, binary.LittleEndian, []byte(common.NEW_TASK))
common.BinaryWrite(raw, t.Mode, strconv.Itoa(t.Port), t.Target, t.Remark)
s.Lock()
defer s.Unlock()
return s.Write(raw.Bytes())
@ -291,23 +383,16 @@ func (s *Conn) GetTaskInfo() (t *file.Tunnel, err error) {
} else if b, err = s.ReadLen(l); err != nil {
return
} else {
arr := strings.Split(string(b), "#")
arr := strings.Split(string(b), common.CONN_DATA_SEQ)
t = new(file.Tunnel)
t.Mode = arr[0]
t.TcpPort, _ = strconv.Atoi(arr[1])
t.Port, _ = strconv.Atoi(arr[1])
t.Target = arr[2]
t.Config = new(file.Config)
t.Config.U = arr[3]
t.Config.P = arr[4]
t.Config.Compress = arr[5]
t.Config.CompressDecode, t.Config.CompressDecode = common.GetCompressType(arr[5])
t.Id = file.GetCsvDb().GetTaskId()
t.Status = true
if t.Client, err = file.GetCsvDb().GetClient(0); err != nil {
return
}
t.Flow = new(file.Flow)
t.Remark = arr[6]
t.UseClientCnf = false
t.Remark = arr[3]
t.NoStore = true
}
return
}
@ -369,6 +454,13 @@ func (s *Conn) WriteMain() (int, error) {
return s.Write([]byte(common.WORK_MAIN))
}
//write main
func (s *Conn) WriteConfig() (int, error) {
s.Lock()
defer s.Unlock()
return s.Write([]byte(common.WORK_CONFIG))
}
//write chan
func (s *Conn) WriteChan() (int, error) {
s.Lock()

View File

@ -18,6 +18,7 @@ type Link struct {
UdpListener *net.UDPConn
Rate *rate.Rate
UdpRemoteAddr *net.UDPAddr
Stop chan bool
}
func NewLink(id int, connType string, host string, en, de int, crypt bool, c *Conn, flow *file.Flow, udpListener *net.UDPConn, rate *rate.Rate, UdpRemoteAddr *net.UDPAddr) *Link {

View File

@ -45,20 +45,17 @@ func (s *Csv) StoreTasksToCsv() {
defer csvFile.Close()
writer := csv.NewWriter(csvFile)
for _, task := range s.Tasks {
if task.NoStore {
continue
}
lg.Println(task)
record := []string{
strconv.Itoa(task.TcpPort),
strconv.Itoa(task.Port),
task.Mode,
task.Target,
task.Config.U,
task.Config.P,
task.Config.Compress,
common.GetStrByBool(task.Status),
common.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)
@ -97,24 +94,15 @@ func (s *Csv) LoadTaskFromCsv() {
// 将每一行数据保存到内存slice中
for _, item := range records {
post := &Tunnel{
TcpPort: common.GetIntNoErrByStr(item[0]),
Mode: item[1],
Target: item[2],
Config: &Config{
U: item[3],
P: item[4],
Compress: item[5],
Crypt: common.GetBoolByStr(item[7]),
CompressEncode: common.GetIntNoErrByStr(item[8]),
CompressDecode: common.GetIntNoErrByStr(item[9]),
},
Status: common.GetBoolByStr(item[6]),
Id: common.GetIntNoErrByStr(item[10]),
UseClientCnf: common.GetBoolByStr(item[12]),
Remark: item[13],
Port: common.GetIntNoErrByStr(item[0]),
Mode: item[1],
Target: item[2],
Status: common.GetBoolByStr(item[3]),
Id: common.GetIntNoErrByStr(item[4]),
Remark: item[6],
}
post.Flow = new(Flow)
if post.Client, err = s.GetClient(common.GetIntNoErrByStr(item[11])); err != nil {
if post.Client, err = s.GetClient(common.GetIntNoErrByStr(item[5])); err != nil {
continue
}
tasks = append(tasks, post)
@ -197,6 +185,9 @@ func (s *Csv) StoreHostToCsv() {
// 将map中的Post转换成slice因为csv的Write需要slice参数
// 并写入csv文件
for _, host := range s.Hosts {
if host.NoStore {
continue
}
record := []string{
host.Host,
host.Target,
@ -286,11 +277,22 @@ func (s *Csv) DelHost(host string) error {
return errors.New("不存在")
}
func (s *Csv) IsHostExist(host string) bool {
for _, v := range s.Hosts {
if v.Host == host {
return true
}
}
return false
}
func (s *Csv) NewHost(t *Host) {
if s.IsHostExist(t.Host) {
return
}
t.Flow = new(Flow)
s.Hosts = append(s.Hosts, t)
s.StoreHostToCsv()
}
func (s *Csv) UpdateHost(t *Host) error {
@ -333,9 +335,12 @@ func (s *Csv) DelClient(id int) error {
}
func (s *Csv) NewClient(c *Client) {
if c.Id == 0 {
c.Id = s.GetClientId()
}
c.Flow = new(Flow)
s.Lock()
defer s.Unlock()
c.Flow = new(Flow)
s.Clients = append(s.Clients, c)
s.StoreClientsToCsv()
}
@ -369,6 +374,9 @@ func (s *Csv) GetClientList(start, length int) ([]*Client, int) {
list := make([]*Client, 0)
var cnt int
for _, v := range s.Clients {
if v.NoDisplay {
continue
}
cnt++
if start--; start < 0 {
if length--; length > 0 {
@ -385,10 +393,32 @@ func (s *Csv) GetClient(id int) (v *Client, err error) {
return
}
}
err = errors.New("未找到")
err = errors.New("未找到客户端")
return
}
func (s *Csv) GetClientIdByVkey(vkey string) (id int, err error) {
for _, v := range s.Clients {
if v.VerifyKey == vkey {
id = v.Id
return
}
}
err = errors.New("未找到客户端")
return
}
//get key by host from x
func (s *Csv) GetInfoByHost(host string) (h *Host, err error) {
for _, v := range s.Hosts {
s := strings.Split(host, ":")
if s[0] == v.Host {
h = v
return
}
}
err = errors.New("未找到host对应的内网目标")
return
}
func (s *Csv) StoreClientsToCsv() {
// 创建文件
csvFile, err := os.Create(filepath.Join(s.RunPath, "conf", "clients.csv"))
@ -398,6 +428,9 @@ func (s *Csv) StoreClientsToCsv() {
defer csvFile.Close()
writer := csv.NewWriter(csvFile)
for _, client := range s.Clients {
if client.NoStore {
continue
}
record := []string{
strconv.Itoa(client.Id),
client.VerifyKey,

View File

@ -31,10 +31,30 @@ type Client struct {
RateLimit int //速度限制 /kb
Flow *Flow //流量
Rate *rate.Rate //速度控制
NoStore bool
NoDisplay bool
id int
sync.RWMutex
}
func NewClient(vKey string, noStore bool, noDisplay bool) *Client {
return &Client{
Cnf: new(Config),
Id: 0,
VerifyKey: vKey,
Addr: "",
Remark: "",
Status: true,
IsConnect: false,
RateLimit: 0,
Flow: new(Flow),
Rate: nil,
NoStore: noStore,
id: GetCsvDb().GetClientId(),
RWMutex: sync.RWMutex{},
NoDisplay: noDisplay,
}
}
func (s *Client) GetId() int {
s.Lock()
defer s.Unlock()
@ -43,16 +63,16 @@ func (s *Client) GetId() int {
}
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 //备注
Id int //Id
Port int //服务端监听端口
Mode string //启动方式
Target string //目标
Status bool //设置是否开启
RunStatus bool //当前运行状态
Client *Client //所属客户端id
Flow *Flow
Remark string //备注
NoStore bool
}
type Config struct {
@ -74,6 +94,7 @@ type Host struct {
Remark string //备注
NowIndex int
TargetArr []string
NoStore bool
sync.RWMutex
}

View File

@ -121,7 +121,7 @@ doLit:
//
// This always copies 16 bytes, instead of only length bytes, but that's
// OK. If the input is a valid Snappy encoding then subsequent iterations
// will fix up the overrun. Otherwise, Decode returns a nil []byte (and a
// will fix up the overserver. Otherwise, Decode returns a nil []byte (and a
// non-nil error), so the overrun will be ignored.
//
// Note that on amd64, it is legal and cheap to issue unaligned 8-byte or

View File

@ -473,7 +473,7 @@ emitLiteralFastPath:
// (Encode's documentation says that dst and src must not overlap.)
//
// This always copies 16 bytes, instead of only len(lit) bytes, but that's
// OK. Subsequent iterations will fix up the overrun.
// OK. Subsequent iterations will fix up the overserver.
//
// Note that on amd64, it is legal and cheap to issue unaligned 8-byte or
// 16-byte loads and stores. This technique probably wouldn't be as

View File

@ -1,4 +1,4 @@
package server
package proxy
import (
"errors"
@ -17,7 +17,6 @@ type server struct {
id int
bridge *bridge.Bridge
task *file.Tunnel
config *file.Config
errorContent []byte
sync.Mutex
}
@ -36,39 +35,6 @@ func (s *server) FlowAddHost(host *file.Host, in, out int64) {
host.Flow.InletFlow += in
}
//热更新配置
func (s *server) ResetConfig() bool {
//获取最新数据
task, err := file.GetCsvDb().GetTask(s.task.Id)
if err != nil {
return false
}
if s.task.Client.Flow.FlowLimit > 0 && (s.task.Client.Flow.FlowLimit<<20) < (s.task.Client.Flow.ExportFlow+s.task.Client.Flow.InletFlow) {
return false
}
s.task.UseClientCnf = task.UseClientCnf
//使用客户端配置
client, err := file.GetCsvDb().GetClient(s.task.Client.Id)
if s.task.UseClientCnf {
if err == nil {
s.config.U = client.Cnf.U
s.config.P = client.Cnf.P
s.config.Compress = client.Cnf.Compress
s.config.Crypt = client.Cnf.Crypt
}
} else {
if err == nil {
s.config.U = task.Config.U
s.config.P = task.Config.P
s.config.Compress = task.Config.Compress
s.config.Crypt = task.Config.Crypt
}
}
s.task.Client.Rate = client.Rate
s.config.CompressDecode, s.config.CompressEncode = common.GetCompressType(s.config.Compress)
return true
}
func (s *server) linkCopy(link *conn.Link, c *conn.Conn, rb []byte, tunnel *conn.Conn, flow *file.Flow) {
if rb != nil {
if _, err := tunnel.SendMsg(rb, link); err != nil {
@ -80,6 +46,10 @@ func (s *server) linkCopy(link *conn.Link, c *conn.Conn, rb []byte, tunnel *conn
buf := pool.BufPoolCopy.Get().([]byte)
for {
if err := s.checkFlow(); err != nil {
c.Close()
break
}
if n, err := c.Read(buf); err != nil {
tunnel.SendMsg([]byte(common.IO_EOF), link)
break
@ -108,3 +78,10 @@ func (s *server) auth(r *http.Request, c *conn.Conn, u, p string) error {
}
return nil
}
func (s *server) checkFlow() error {
if s.task.Client.Flow.FlowLimit > 0 && (s.task.Client.Flow.FlowLimit<<20) < (s.task.Client.Flow.ExportFlow+s.task.Client.Flow.InletFlow) {
return errors.New("Traffic exceeded")
}
return nil
}

View File

@ -1,14 +1,14 @@
package server
package proxy
import (
"bufio"
"crypto/tls"
"github.com/cnlh/nps/lib/beego"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/beego"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/lg"
"github.com/cnlh/nps/lib/common"
"log"
"net/http"
"net/http/httputil"
@ -55,7 +55,7 @@ func (s *httpServer) Start() error {
if s.httpPort > 0 {
http = s.NewServer(s.httpPort)
go func() {
lg.Println("启动http监听,端口为", s.httpPort)
lg.Println("Start http listener, port is", s.httpPort)
err := http.ListenAndServe()
if err != nil {
lg.Fatalln(err)
@ -64,14 +64,14 @@ func (s *httpServer) Start() error {
}
if s.httpsPort > 0 {
if !common.FileExists(s.pemPath) {
lg.Fatalf("ssl certFile文件%s不存在", s.pemPath)
lg.Fatalf("ssl certFile %s is not exist", s.pemPath)
}
if !common.FileExists(s.keyPath) {
lg.Fatalf("ssl keyFile文件%s不存在", s.keyPath)
lg.Fatalf("ssl keyFile %s exist", s.keyPath)
}
https = s.NewServer(s.httpsPort)
go func() {
lg.Println("启动https监听,端口为", s.httpsPort)
lg.Println("Start https listener, port is", s.httpsPort)
err := https.ListenAndServeTLS(s.pemPath, s.keyPath)
if err != nil {
lg.Fatalln(err)
@ -111,7 +111,7 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) {
//多客户端域名代理
var (
isConn = true
lk *conn.Link
lk *conn.Link
host *file.Host
tunnel *conn.Conn
err error
@ -119,7 +119,7 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) {
for {
//首次获取conn
if isConn {
if host, err = GetInfoByHost(r.Host); err != nil {
if host, err = file.GetCsvDb().GetInfoByHost(r.Host); err != nil {
lg.Printf("the host %s is not found !", r.Host)
break
}

View File

@ -1,4 +1,4 @@
package server
package proxy
import (
"encoding/binary"
@ -142,7 +142,7 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) {
} else {
ltype = common.CONN_TCP
}
link := conn.NewLink(s.task.Client.GetId(), ltype, addr, s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, conn.NewConn(c), s.task.Flow, nil, s.task.Client.Rate, nil)
link := conn.NewLink(s.task.Client.GetId(), ltype, addr, s.task.Client.Cnf.CompressEncode, s.task.Client.Cnf.CompressDecode, s.task.Client.Cnf.Crypt, conn.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()
@ -245,7 +245,7 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error {
if _, err := io.ReadAtLeast(c, pass, passLen); err != nil {
return err
}
if string(pass) == s.config.U && string(user) == s.config.P {
if string(pass) == s.task.Client.Cnf.U && string(user) == s.task.Client.Cnf.P {
if _, err := c.Write([]byte{userAuthVersion, authSuccess}); err != nil {
return err
}
@ -262,7 +262,7 @@ func (s *Sock5ModeServer) Auth(c net.Conn) error {
//start
func (s *Sock5ModeServer) Start() error {
var err error
s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.task.TcpPort))
s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.task.Port))
if err != nil {
return err
}
@ -274,10 +274,6 @@ func (s *Sock5ModeServer) Start() error {
}
lg.Fatalln("accept error: ", err)
}
if !s.ResetConfig() {
conn.Close()
continue
}
go s.handleConn(conn)
}
return nil
@ -293,8 +289,7 @@ func NewSock5ModeServer(bridge *bridge.Bridge, task *file.Tunnel) *Sock5ModeServ
s := new(Sock5ModeServer)
s.bridge = bridge
s.task = task
s.config = file.DeepCopyConfig(task.Config)
if s.config.U != "" && s.config.P != "" {
if s.task.Client.Cnf.U != "" && s.task.Client.Cnf.P != "" {
s.isVerify = true
} else {
s.isVerify = false

View File

@ -1,9 +1,9 @@
package server
package proxy
import (
"errors"
"github.com/cnlh/nps/lib/beego"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/beego"
"github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/conn"
"github.com/cnlh/nps/lib/file"
@ -25,14 +25,13 @@ func NewTunnelModeServer(process process, bridge *bridge.Bridge, task *file.Tunn
s.bridge = bridge
s.process = process
s.task = task
s.config = file.DeepCopyConfig(task.Config)
return s
}
//开始
func (s *TunnelModeServer) Start() error {
var err error
s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.task.TcpPort, ""})
s.listener, err = net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), s.task.Port, ""})
if err != nil {
return err
}
@ -77,14 +76,14 @@ type WebServer struct {
func (s *WebServer) Start() error {
p, _ := beego.AppConfig.Int("httpport")
if !common.TestTcpPort(p) {
lg.Fatalln("web管理端口", p, "被占用!")
lg.Fatalf("Web management port %d is occupied", p)
}
beego.BConfig.WebConfig.Session.SessionOn = true
lg.Println("web管理启动访问端口为", p)
lg.Println("Web management start, access port is", p)
beego.SetStaticPath("/static", filepath.Join(common.GetRunPath(), "web", "static"))
beego.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views"))
beego.Run()
return errors.New("web管理启动失败")
return errors.New("Web management startup failure")
}
//new
@ -98,26 +97,18 @@ type process func(c *conn.Conn, s *TunnelModeServer) error
//tcp隧道模式
func ProcessTunnel(c *conn.Conn, s *TunnelModeServer) error {
if !s.ResetConfig() {
c.Close()
return errors.New("流量超出")
}
return s.dealClient(c, s.config, s.task.Target, "", nil)
return s.dealClient(c, s.task.Client.Cnf, s.task.Target, "", nil)
}
//http代理模式
func ProcessHttp(c *conn.Conn, s *TunnelModeServer) error {
if !s.ResetConfig() {
c.Close()
return errors.New("流量超出")
}
method, addr, rb, err, r := c.GetHost()
if err != nil {
c.Close()
return err
}
if err := s.auth(r, c, s.config.U, s.config.P); err != nil {
if err := s.auth(r, c, s.task.Client.Cnf.U, s.task.Client.Cnf.P); err != nil {
return err
}
return s.dealClient(c, s.config, addr, method, rb)
return s.dealClient(c, s.task.Client.Cnf, addr, method, rb)
}

View File

@ -1,4 +1,4 @@
package server
package proxy
import (
"github.com/cnlh/nps/bridge"
@ -21,14 +21,13 @@ func NewUdpModeServer(bridge *bridge.Bridge, task *file.Tunnel) *UdpModeServer {
s.bridge = bridge
s.udpMap = make(map[string]*conn.Conn)
s.task = task
s.config = file.DeepCopyConfig(task.Config)
return s
}
//开始
func (s *UdpModeServer) Start() error {
var err error
s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.task.TcpPort, ""})
s.listener, err = net.ListenUDP("udp", &net.UDPAddr{net.ParseIP("0.0.0.0"), s.task.Port, ""})
if err != nil {
return err
}
@ -41,17 +40,16 @@ func (s *UdpModeServer) Start() error {
}
continue
}
if !s.ResetConfig() {
continue
}
go s.process(addr, buf[:n])
}
return nil
}
func (s *UdpModeServer) process(addr *net.UDPAddr, data []byte) {
link := conn.NewLink(s.task.Client.GetId(), common.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 := conn.NewLink(s.task.Client.GetId(), common.CONN_UDP, s.task.Target, s.task.Client.Cnf.CompressEncode, s.task.Client.Cnf.CompressDecode, s.task.Client.Cnf.Crypt, nil, s.task.Flow, s.listener, s.task.Client.Rate, addr)
if err := s.checkFlow(); err != nil {
return
}
if tunnel, err := s.bridge.SendLinkInfo(s.task.Client.Id, link); err != nil {
return
} else {

View File

@ -3,15 +3,17 @@ package server
import (
"errors"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib/beego"
"github.com/cnlh/nps/lib/file"
"github.com/cnlh/nps/lib/lg"
"github.com/cnlh/nps/server/proxy"
"github.com/cnlh/nps/server/tool"
"reflect"
"strings"
)
var (
Bridge *bridge.Bridge
RunList map[int]interface{} //运行中的任务
Bridge *bridge.Bridge
RunList map[int]interface{} //运行中的任务
)
func init() {
@ -20,20 +22,39 @@ func init() {
//从csv文件中恢复任务
func InitFromCsv() {
//Add a public password
c := file.NewClient(beego.AppConfig.String("publicVkey"), true, true)
file.GetCsvDb().NewClient(c)
RunList[c.Id] = nil
//Initialize services in server-side files
for _, v := range file.GetCsvDb().Tasks {
if v.Status {
lg.Println("启动模式:", v.Mode, "监听端口:", v.TcpPort)
lg.Println("启动模式:", v.Mode, "监听端口:", v.Port)
AddTask(v)
}
}
}
func DealBridgeTask() {
for {
select {
case t := <-Bridge.OpenTask:
AddTask(t)
case id := <-Bridge.CloseClient:
DelTunnelAndHostByClientId(id)
file.GetCsvDb().DelClient(id)
}
}
}
//start a new server
func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
Bridge = bridge.NewTunnel(bridgePort, RunList, bridgeType)
Bridge = bridge.NewTunnel(bridgePort, bridgeType)
if err := Bridge.StartTunnel(); err != nil {
lg.Fatalln("服务端开启失败", err)
} else {
lg.Printf("Server startup, the bridge type is %s, the bridge port is %d", bridgeType, bridgePort)
}
go DealBridgeTask()
if svr := NewMode(Bridge, cnf); svr != nil {
RunList[cnf.Id] = svr
err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
@ -41,7 +62,7 @@ func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
lg.Fatalln(err)
}
} else {
lg.Fatalln("启动模式不正确")
lg.Fatalln("启动模式%s不正确", cnf.Mode)
}
}
@ -49,26 +70,25 @@ func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
func NewMode(Bridge *bridge.Bridge, c *file.Tunnel) interface{} {
switch c.Mode {
case "tunnelServer":
return NewTunnelModeServer(ProcessTunnel, Bridge, c)
return proxy.NewTunnelModeServer(proxy.ProcessTunnel, Bridge, c)
case "socks5Server":
return NewSock5ModeServer(Bridge, c)
return proxy.NewSock5ModeServer(Bridge, c)
case "httpProxyServer":
return NewTunnelModeServer(ProcessHttp, Bridge, c)
return proxy.NewTunnelModeServer(proxy.ProcessHttp, Bridge, c)
case "udpServer":
return NewUdpModeServer(Bridge, c)
return proxy.NewUdpModeServer(Bridge, c)
case "webServer":
InitFromCsv()
t := &file.Tunnel{
TcpPort: 0,
Mode: "httpHostServer",
Target: "",
Config: &file.Config{},
Status: true,
Port: 0,
Mode: "httpHostServer",
Target: "",
Status: true,
}
AddTask(t)
return NewWebServer(Bridge)
return proxy.NewWebServer(Bridge)
case "httpHostServer":
return NewHttp(Bridge, c)
return proxy.NewHttp(Bridge, c)
}
return nil
}
@ -83,6 +103,7 @@ func StopServer(id int) error {
t.Status = false
file.GetCsvDb().UpdateTask(t)
}
delete(RunList, id)
return nil
}
return errors.New("未在运行中")
@ -90,17 +111,22 @@ func StopServer(id int) error {
//add task
func AddTask(t *file.Tunnel) error {
if b := tool.TestServerPort(t.Port, t.Mode); !b && t.Mode != "httpHostServer" {
lg.Printf("taskId %d start error Port %d Open Failed", t.Id, t.Port)
return errors.New("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 {
lg.Fatalln("客户端", t.Id, "启动失败,错误:", err)
lg.Println("clientId %d taskId %d start error %s", t.Client.Id, t.Id, err)
delete(RunList, t.Id)
return
}
}()
} else {
return errors.New("启动模式不正确")
return errors.New("the mode is not correct")
}
return nil
}
@ -119,23 +145,12 @@ func StartTask(id int) error {
//delete task
func DelTask(id int) error {
if err := StopServer(id); err != nil {
return err
}
return file.GetCsvDb().DelTask(id)
}
//get key by host from x
func GetInfoByHost(host string) (h *file.Host, err error) {
for _, v := range file.GetCsvDb().Hosts {
s := strings.Split(host, ":")
if s[0] == v.Host {
h = v
return
if _, ok := RunList[id]; ok {
if err := StopServer(id); err != nil {
return err
}
}
err = errors.New("未找到host对应的内网目标")
return
return file.GetCsvDb().DelTask(id)
}
//get task list by page num
@ -155,9 +170,9 @@ func GetTunnel(start, length int, typeVal string, clientId int) ([]*file.Tunnel,
if start--; start < 0 {
if length--; length > 0 {
if _, ok := RunList[v.Id]; ok {
v.Client.Status = true
v.RunStatus = true
} else {
v.Client.Status = false
v.RunStatus = false
}
list = append(list, v)
}
@ -200,11 +215,15 @@ func dealClientData(list []*file.Client) {
//根据客户端id删除其所属的所有隧道和域名
func DelTunnelAndHostByClientId(clientId int) {
var ids []int
for _, v := range file.GetCsvDb().Tasks {
if v.Client.Id == clientId {
DelTask(v.Id)
ids = append(ids, v.Id)
}
}
for _, id := range ids {
DelTask(id)
}
for _, v := range file.GetCsvDb().Hosts {
if v.Client.Id == clientId {
file.GetCsvDb().DelHost(v.Host)

View File

@ -1,4 +1,4 @@
package server
package test
import (
"github.com/cnlh/nps/lib/beego"
@ -13,9 +13,9 @@ func TestServerConfig() {
var postUdpArr []int
for _, v := range file.GetCsvDb().Tasks {
if v.Mode == "udpServer" {
isInArr(&postUdpArr, v.TcpPort, v.Remark, "udp")
isInArr(&postUdpArr, v.Port, v.Remark, "udp")
} else {
isInArr(&postTcpArr, v.TcpPort, v.Remark, "tcp")
isInArr(&postTcpArr, v.Port, v.Remark, "tcp")
}
}
p, err := beego.AppConfig.Int("httpport")

55
server/tool/utils.go Normal file
View File

@ -0,0 +1,55 @@
package tool
import (
"github.com/cnlh/nps/lib/beego"
"github.com/cnlh/nps/lib/common"
"strconv"
"strings"
)
var ports []int
func init() {
p := beego.AppConfig.String("allowPorts")
arr := strings.Split(p, ",")
for _, v := range arr {
fw := strings.Split(v, "-")
if len(fw) == 2 {
if isPort(fw[0]) && isPort(fw[1]) {
start, _ := strconv.Atoi(fw[0])
end, _ := strconv.Atoi(fw[1])
for i := start; i <= end; i++ {
ports = append(ports, i)
}
} else {
continue
}
} else if isPort(v) {
p, _ := strconv.Atoi(v)
ports = append(ports, p)
}
}
}
func isPort(p string) bool {
pi, err := strconv.Atoi(p)
if err != nil {
return false
}
if pi > 65536 || pi < 1 {
return false
}
return true
}
func TestServerPort(p int, m string) (b bool) {
if len(ports) != 0 {
if !common.InIntArr(ports, p) {
return false
}
}
if m == "udpServer" {
b = common.TestUdpPort(p)
} else {
b = common.TestTcpPort(p)
}
return
}

View File

@ -73,17 +73,10 @@ func (s *IndexController) Add() {
s.display()
} else {
t := &file.Tunnel{
TcpPort: s.GetIntNoErr("port"),
Port: s.GetIntNoErr("port"),
Mode: s.GetString("type"),
Target: s.GetString("target"),
Config: &file.Config{
U: s.GetString("u"),
P: s.GetString("p"),
Compress: s.GetString("compress"),
Crypt: s.GetBoolNoErr("crypt"),
},
Id: file.GetCsvDb().GetTaskId(),
UseClientCnf: s.GetBoolNoErr("use_client"),
Status: true,
Remark: s.GetString("remark"),
Flow: &file.Flow{},
@ -126,16 +119,11 @@ func (s *IndexController) Edit() {
if t, err := file.GetCsvDb().GetTask(id); err != nil {
s.error()
} else {
t.TcpPort = s.GetIntNoErr("port")
t.Port = s.GetIntNoErr("port")
t.Mode = s.GetString("type")
t.Target = s.GetString("target")
t.Id = id
t.Client.Id = s.GetIntNoErr("client_id")
t.Config.U = s.GetString("u")
t.Config.P = s.GetString("p")
t.Config.Compress = s.GetString("compress")
t.Config.Crypt = s.GetBoolNoErr("crypt")
t.UseClientCnf = s.GetBoolNoErr("use_client")
t.Remark = s.GetString("remark")
if t.Client, err = file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil {
s.AjaxErr("修改失败")
@ -187,7 +175,7 @@ func (s *IndexController) HostList() {
func (s *IndexController) GetHost() {
if s.Ctx.Request.Method == "POST" {
data := make(map[string]interface{})
if h, err := server.GetInfoByHost(s.GetString("host")); err != nil {
if h, err := file.GetCsvDb().GetInfoByHost(s.GetString("host")); err != nil {
data["code"] = 0
} else {
data["data"] = h
@ -234,7 +222,7 @@ func (s *IndexController) EditHost() {
host := s.GetString("host")
if s.Ctx.Request.Method == "GET" {
s.Data["menu"] = "host"
if h, err := server.GetInfoByHost(host); err != nil {
if h, err := file.GetCsvDb().GetInfoByHost(host); err != nil {
s.error()
} else {
s.Data["h"] = h
@ -242,7 +230,7 @@ func (s *IndexController) EditHost() {
s.SetInfo("修改")
s.display("index/hedit")
} else {
if h, err := server.GetInfoByHost(host); err != nil {
if h, err := file.GetCsvDb().GetInfoByHost(host); err != nil {
s.error()
} else {
h.Host = s.GetString("nhost")

View File

@ -30,35 +30,6 @@
<input value="{{.client_id}}" class="form-control" type="text" name="client_id"
placeholder="客户端id">
</div>
<div class="form-group" id="use_client">
<label class="control-label">使</label>
<select class="form-control" name="use_client">
<option value="1"></option>
<option value="0"></option>
</select>
</div>
<div class="form-group" id="compress">
<label class="control-label"></label>
<select class="form-control" name="compress">
<option value=""></option>
<option value="snappy">snappy</option>
</select>
</div>
<div class="form-group" id="crypt">
<label class="control-label"></label>
<select class="form-control" name="crypt">
<option value="0"></option>
<option value="1"></option>
</select>
</div>
<div class="form-group" id="u">
<label class="control-label">(socks5,web穿)</label>
<input class="form-control" type="text" name="u" placeholder="不填则无需验证">
</div>
<div class="form-group" id="p">
<label class="control-label">(socks5,web穿)</label>
<input class="form-control" type="text" name="p" placeholder="不填则无需验证">
</div>
</form>
</div>
<div class="tile-footer">

View File

@ -21,7 +21,7 @@
</div>
<div class="form-group" id="port">
<label class="control-label"></label>
<input class="form-control" value="{{.t.TcpPort}}" type="text" name="port"
<input class="form-control" value="{{.t.Port}}" type="text" name="port"
placeholder="公网服务器对外访问端口例如8024">
</div>
<div class="form-group" id="target">
@ -34,37 +34,6 @@
<input class="form-control" value="{{.t.Client.Id}}" type="text" name="client_id"
placeholder="客户端id">
</div>
<div class="form-group" id="use_client">
<label class="control-label">使</label>
<select class="form-control" name="use_client">
<option {{if eq false .t.UseClientCnf}}selected{{end}} value="0"></option>
<option {{if eq true .t.UseClientCnf}}selected{{end}} value="1"></option>
</select>
</div>
<div class="form-group" id="compress">
<label class="control-label">()</label>
<select class="form-control" name="compress">
<option {{if eq "" .t.Config.Compress}}selected{{end}} value=""></option>
<option {{if eq "snappy" .t.Config.Compress}}selected{{end}} value="snappy">snappy</option>
</select>
</div>
<div class="form-group" id="crypt">
<label class="control-label">()</label>
<select class="form-control" name="crypt">
<option {{if eq false .t.Config.Crypt}}selected{{end}} value="0"></option>
<option {{if eq true .t.Config.Crypt}}selected{{end}} value="1"></option>
</select>
</div>
<div class="form-group" id="u">
<label class="control-label">(socks5,web穿)</label>
<input class="form-control" value="{{.t.Config.U}}" type="text" name="u"
placeholder="不填则无需验证">
</div>
<div class="form-group" id="p">
<label class="control-label">(socks5,web穿)</label>
<input class="form-control" value="{{.t.Config.P}}" type="text" name="p"
placeholder="不填则无需验证">
</div>
</form>
</div>
<div class="tile-footer">

View File

@ -132,7 +132,7 @@
</div>
<div class="col-md-12">
<div class="tile">
<p><b></b></p>
<p><b></b></p>
</div>
</div>
</div>

View File

@ -15,7 +15,8 @@
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
<th></th>
@ -109,7 +110,7 @@
{data: 'Id'},
{data: 'Remark'},
{data: 'ClientId'},
{data: 'TcpPort'},
{data: 'Port'},
{data: 'Target'},
{data: 'Compress'},
{data: 'Crypt'},
@ -117,6 +118,7 @@
{data: 'P'},
{data: 'ClientStatus'},
{data: 'Status'},
{data: 'RunStatus'},
{data: 'ExportFlow'},
{data: 'InletFlow'},
{data: "Id"}
@ -143,29 +145,17 @@
}, {
targets: 5,
render: function (data, type, row, meta) {
if (row.UseClientCnf == true) {
return row.Client.Cnf.Compress
} else {
return row.Config.Compress
}
return row.Client.Cnf.Compress
}
}, {
targets: 7,
render: function (data, type, row, meta) {
if (row.UseClientCnf == true) {
return row.Client.Cnf.U
} else {
return row.Config.U
}
return row.Client.Cnf.U
}
}, {
targets: 8,
render: function (data, type, row, meta) {
if (row.UseClientCnf == true) {
return row.Client.Cnf.P
} else {
return row.Config.P
}
return row.Client.Cnf.P
}
},
{
@ -179,13 +169,19 @@
}
},
{
targets: -8,
targets: -5,
render: function (data, type, row, meta) {
if (row.UseClientCnf == true) {
crypt = row.Client.Cnf.Crypt
if (data == false) {
return "<span class=\"badge badge-pill badge-secondary\">暂停</span>"
} else {
crypt = row.Config.Crypt
return "<span class=\"badge badge-pill badge-success\">正常</span>"
}
}
},
{
targets: -9,
render: function (data, type, row, meta) {
crypt = row.Client.Cnf.Crypt
if (crypt == "0") {
return "不加密"
} else {
@ -194,7 +190,7 @@
}
},
{
targets: -5,
targets: -6,
render: function (data, type, row, meta) {
if (row.Client.IsConnect == false) {
return "<span class=\"badge badge-pill badge-secondary\">离线</span>"