mirror of https://github.com/ehang-io/nps
客户端配置,端口白名单等
parent
59d789d253
commit
44d314515b
151
bridge/bridge.go
151
bridge/bridge.go
|
@ -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]
|
||||
|
|
218
client/client.go
218
client/client.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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 mode(stdout|file)")
|
||||
connType = flag.String("type", "tcp", "Connection type with the server(kcp|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
|
||||
}
|
||||
|
|
|
@ -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 mode(stdout|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"))
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
1,ydiigrm4ghu7mym1,测试,true,,,0,,0,0
|
|
|
@ -1,2 +0,0 @@
|
|||
a.o.com,127.0.0.1:8080,1,,,测试
|
||||
b.o.com,127.0.0.1:8082,1,,,
|
|
|
@ -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
|
|
@ -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,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
|
||||
|
|
|
@ -56,7 +56,7 @@ func GetLogPath() string {
|
|||
}
|
||||
|
||||
//interface pid file path
|
||||
func GetPidPath() string {
|
||||
func GetTmpPath() string {
|
||||
var path string
|
||||
if IsWindows() {
|
||||
path = "./"
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
120
lib/conn/conn.go
120
lib/conn/conn.go
|
@ -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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
}
|
|
@ -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 {
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
|
@ -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
|
||||
}
|
|
@ -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")
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -132,7 +132,7 @@
|
|||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="tile">
|
||||
<p><b>单个客户端可以田间多条隧道或者域名解析</b></p>
|
||||
<p><b>单个客户端可以添加多条隧道或者域名解析</b></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -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>"
|
||||
|
|
Loading…
Reference in New Issue