Browse Source

add functions

刘河 6 years ago
parent
commit
750ecb824a

+ 47 - 23
bridge/bridge.go

@@ -8,11 +8,11 @@ import (
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/crypt"
 	"github.com/cnlh/nps/lib/crypt"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/file"
-	"github.com/cnlh/nps/lib/lg"
 	"github.com/cnlh/nps/lib/pool"
 	"github.com/cnlh/nps/lib/pool"
+	"github.com/cnlh/nps/lib/version"
 	"github.com/cnlh/nps/server/tool"
 	"github.com/cnlh/nps/server/tool"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
 	"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
-	"log"
 	"net"
 	"net"
 	"strconv"
 	"strconv"
 	"sync"
 	"sync"
@@ -48,6 +48,7 @@ type Bridge struct {
 	tunnelType   string //bridge type kcp or tcp
 	tunnelType   string //bridge type kcp or tcp
 	OpenTask     chan *file.Tunnel
 	OpenTask     chan *file.Tunnel
 	CloseClient  chan int
 	CloseClient  chan int
+	SecretChan   chan *conn.Secret
 	clientLock   sync.RWMutex
 	clientLock   sync.RWMutex
 	Register     map[string]time.Time
 	Register     map[string]time.Time
 	registerLock sync.RWMutex
 	registerLock sync.RWMutex
@@ -65,6 +66,7 @@ func NewTunnel(tunnelPort int, tunnelType string, ipVerify bool, runList map[int
 	t.Register = make(map[string]time.Time)
 	t.Register = make(map[string]time.Time)
 	t.ipVerify = ipVerify
 	t.ipVerify = ipVerify
 	t.runList = runList
 	t.runList = runList
+	t.SecretChan = make(chan *conn.Secret)
 	return t
 	return t
 }
 }
 
 
@@ -80,7 +82,7 @@ func (s *Bridge) StartTunnel() error {
 				c, err := s.kcpListener.AcceptKCP()
 				c, err := s.kcpListener.AcceptKCP()
 				conn.SetUdpSession(c)
 				conn.SetUdpSession(c)
 				if err != nil {
 				if err != nil {
-					lg.Println(err)
+					logs.Warn(err)
 					continue
 					continue
 				}
 				}
 				go s.cliProcess(conn.NewConn(c))
 				go s.cliProcess(conn.NewConn(c))
@@ -95,7 +97,7 @@ func (s *Bridge) StartTunnel() error {
 			for {
 			for {
 				c, err := s.tcpListener.Accept()
 				c, err := s.tcpListener.Accept()
 				if err != nil {
 				if err != nil {
-					lg.Println(err)
+					logs.Warn(err)
 					continue
 					continue
 				}
 				}
 				go s.cliProcess(conn.NewConn(c))
 				go s.cliProcess(conn.NewConn(c))
@@ -116,6 +118,12 @@ func (s *Bridge) verifySuccess(c *conn.Conn) {
 }
 }
 
 
 func (s *Bridge) cliProcess(c *conn.Conn) {
 func (s *Bridge) cliProcess(c *conn.Conn) {
+	c.Write([]byte(crypt.Md5(version.GetVersion())))
+	if b, err := c.ReadFlag(); err != nil || string(b) != version.VERSION_OK {
+		logs.Info("The client %s version does not match", c.Conn.RemoteAddr())
+		c.Close()
+		return
+	}
 	c.SetReadDeadline(5, s.tunnelType)
 	c.SetReadDeadline(5, s.tunnelType)
 	var buf []byte
 	var buf []byte
 	var err error
 	var err error
@@ -126,7 +134,7 @@ func (s *Bridge) cliProcess(c *conn.Conn) {
 	//验证
 	//验证
 	id, err := file.GetCsvDb().GetIdByVerifyKey(string(buf), c.Conn.RemoteAddr().String())
 	id, err := file.GetCsvDb().GetIdByVerifyKey(string(buf), c.Conn.RemoteAddr().String())
 	if err != nil {
 	if err != nil {
-		lg.Println("当前客户端连接校验错误,关闭此客户端:", c.Conn.RemoteAddr())
+		logs.Info("Current client connection validation error, close this client:", c.Conn.RemoteAddr())
 		s.verifyError(c)
 		s.verifyError(c)
 		return
 		return
 	} else {
 	} else {
@@ -136,7 +144,7 @@ func (s *Bridge) cliProcess(c *conn.Conn) {
 	if flag, err := c.ReadFlag(); err == nil {
 	if flag, err := c.ReadFlag(); err == nil {
 		s.typeDeal(flag, c, id)
 		s.typeDeal(flag, c, id)
 	} else {
 	} else {
-		log.Println(err, flag)
+		logs.Warn(err, flag)
 	}
 	}
 	return
 	return
 }
 }
@@ -182,7 +190,7 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) {
 			s.Client[id] = NewClient(nil, c, nil)
 			s.Client[id] = NewClient(nil, c, nil)
 			s.clientLock.Unlock()
 			s.clientLock.Unlock()
 		}
 		}
-		lg.Printf("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr())
+		logs.Info("clientId %d connection succeeded, address:%s ", id, c.Conn.RemoteAddr())
 		go s.GetStatus(id)
 		go s.GetStatus(id)
 	case common.WORK_CHAN:
 	case common.WORK_CHAN:
 		s.clientLock.Lock()
 		s.clientLock.Lock()
@@ -200,6 +208,10 @@ func (s *Bridge) typeDeal(typeVal string, c *conn.Conn, id int) {
 		go s.GetConfig(c)
 		go s.GetConfig(c)
 	case common.WORK_REGISTER:
 	case common.WORK_REGISTER:
 		go s.register(c)
 		go s.register(c)
+	case common.WORD_SECRET:
+		if b, err := c.ReadLen(32); err == nil {
+			s.SecretChan <- conn.NewSecret(string(b), c)
+		}
 	case common.WORK_SEND_STATUS:
 	case common.WORK_SEND_STATUS:
 		s.clientLock.Lock()
 		s.clientLock.Lock()
 		if v, ok := s.Client[id]; ok {
 		if v, ok := s.Client[id]; ok {
@@ -293,7 +305,7 @@ func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, linkAddr string) (t
 
 
 		v.signal.SendLinkInfo(link)
 		v.signal.SendLinkInfo(link)
 		if err != nil {
 		if err != nil {
-			lg.Println("send link information error:", err, link.Id)
+			logs.Warn("send link information error:", err, link.Id)
 			s.DelClient(clientId)
 			s.DelClient(clientId)
 			return
 			return
 		}
 		}
@@ -314,7 +326,7 @@ func (s *Bridge) SendLinkInfo(clientId int, link *conn.Link, linkAddr string) (t
 		}
 		}
 	} else {
 	} else {
 		s.clientLock.Unlock()
 		s.clientLock.Unlock()
-		err = errors.New("the connection is not connect")
+		err = errors.New(fmt.Sprintf("the client %d is not connect", clientId))
 	}
 	}
 	return
 	return
 }
 }
@@ -328,6 +340,7 @@ func (s *Bridge) DelClient(id int) {
 func (s *Bridge) GetConfig(c *conn.Conn) {
 func (s *Bridge) GetConfig(c *conn.Conn) {
 	var client *file.Client
 	var client *file.Client
 	var fail bool
 	var fail bool
+
 	for {
 	for {
 		flag, err := c.ReadFlag()
 		flag, err := c.ReadFlag()
 		if err != nil {
 		if err != nil {
@@ -357,19 +370,15 @@ func (s *Bridge) GetConfig(c *conn.Conn) {
 				binary.Write(c, binary.LittleEndian, []byte(str))
 				binary.Write(c, binary.LittleEndian, []byte(str))
 			}
 			}
 		case common.NEW_CONF:
 		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 {
+			var err error
+			if client, err = c.GetConfigInfo(); err != nil {
+				c.Write([]byte(client.VerifyKey))
 				fail = true
 				fail = true
 				c.WriteAddFail()
 				c.WriteAddFail()
 				break
 				break
 			} else {
 			} else {
-				client.Cnf = config
+				c.Write([]byte(client.VerifyKey))
+				file.GetCsvDb().NewClient(client)
 				c.WriteAddOk()
 				c.WriteAddOk()
 			}
 			}
 		case common.NEW_HOST:
 		case common.NEW_HOST:
@@ -380,6 +389,7 @@ func (s *Bridge) GetConfig(c *conn.Conn) {
 			} else if file.GetCsvDb().IsHostExist(h) {
 			} else if file.GetCsvDb().IsHostExist(h) {
 				fail = true
 				fail = true
 				c.WriteAddFail()
 				c.WriteAddFail()
+				break
 			} else {
 			} else {
 				h.Client = client
 				h.Client = client
 				file.GetCsvDb().NewHost(h)
 				file.GetCsvDb().NewHost(h)
@@ -397,6 +407,13 @@ func (s *Bridge) GetConfig(c *conn.Conn) {
 					fail = true
 					fail = true
 					c.WriteAddFail()
 					c.WriteAddFail()
 					break
 					break
+				} else if t.Mode == "secretServer" {
+					ports = append(ports, 0)
+				}
+				if len(ports) == 0 {
+					fail = true
+					c.WriteAddFail()
+					break
 				}
 				}
 				for i := 0; i < len(ports); i++ {
 				for i := 0; i < len(ports); i++ {
 					tl := new(file.Tunnel)
 					tl := new(file.Tunnel)
@@ -407,17 +424,24 @@ func (s *Bridge) GetConfig(c *conn.Conn) {
 						tl.Remark = t.Remark
 						tl.Remark = t.Remark
 					} else {
 					} else {
 						tl.Remark = t.Remark + "_" + strconv.Itoa(tl.Port)
 						tl.Remark = t.Remark + "_" + strconv.Itoa(tl.Port)
-						tl.Target = strconv.Itoa(targets[i])
+						tl.Target = t.TargetAddr + ":" + strconv.Itoa(targets[i])
 					}
 					}
 					tl.Id = file.GetCsvDb().GetTaskId()
 					tl.Id = file.GetCsvDb().GetTaskId()
 					tl.Status = true
 					tl.Status = true
 					tl.Flow = new(file.Flow)
 					tl.Flow = new(file.Flow)
 					tl.NoStore = true
 					tl.NoStore = true
 					tl.Client = client
 					tl.Client = client
-					file.GetCsvDb().NewTask(tl)
-					if b := tool.TestServerPort(tl.Port, tl.Mode); !b {
+					tl.Password = t.Password
+					if err := file.GetCsvDb().NewTask(tl); err != nil {
+						logs.Notice("Add task error ", err.Error())
+						fail = true
+						c.WriteAddFail()
+						break
+					}
+					if b := tool.TestServerPort(tl.Port, tl.Mode); !b && t.Mode != "secretServer" {
 						fail = true
 						fail = true
 						c.WriteAddFail()
 						c.WriteAddFail()
+						break
 					} else {
 					} else {
 						s.OpenTask <- tl
 						s.OpenTask <- tl
 					}
 					}
@@ -460,7 +484,7 @@ func (s *Bridge) clientCopy(clientId int) {
 
 
 	for {
 	for {
 		if id, err := client.tunnel.GetLen(); err != nil {
 		if id, err := client.tunnel.GetLen(); err != nil {
-			lg.Println("read msg content length error close client")
+			logs.Info("read msg content length error close client")
 			s.delClient(clientId)
 			s.delClient(clientId)
 			break
 			break
 		} else {
 		} else {
@@ -470,7 +494,7 @@ func (s *Bridge) clientCopy(clientId int) {
 				if content, err := client.tunnel.GetMsgContent(link); err != nil {
 				if content, err := client.tunnel.GetMsgContent(link); err != nil {
 					pool.PutBufPoolCopy(content)
 					pool.PutBufPoolCopy(content)
 					s.delClient(clientId)
 					s.delClient(clientId)
-					lg.Println("read msg content error", err, "close client")
+					logs.Notice("read msg content error", err, "close client")
 					break
 					break
 				} else {
 				} else {
 					link.MsgCh <- content
 					link.MsgCh <- content

+ 14 - 11
client/client.go

@@ -3,9 +3,10 @@ package client
 import (
 import (
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/conn"
-	"github.com/cnlh/nps/lib/lg"
 	"github.com/cnlh/nps/lib/pool"
 	"github.com/cnlh/nps/lib/pool"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"net"
 	"net"
+	"os"
 	"sync"
 	"sync"
 	"time"
 	"time"
 )
 )
@@ -40,11 +41,11 @@ func (s *TRPClient) Start() {
 retry:
 retry:
 	c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN, s.proxyUrl)
 	c, err := NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_MAIN, s.proxyUrl)
 	if err != nil {
 	if err != nil {
-		lg.Println("The connection server failed and will be reconnected in five seconds")
+		logs.Error("The connection server failed and will be reconnected in five seconds")
 		time.Sleep(time.Second * 5)
 		time.Sleep(time.Second * 5)
 		goto retry
 		goto retry
 	}
 	}
-	lg.Printf("Successful connection with server %s", s.svrAddr)
+	logs.Info("Successful connection with server %s", s.svrAddr)
 	s.processor(c)
 	s.processor(c)
 }
 }
 
 
@@ -65,12 +66,13 @@ func (s *TRPClient) processor(c *conn.Conn) {
 	for {
 	for {
 		flags, err := c.ReadFlag()
 		flags, err := c.ReadFlag()
 		if err != nil {
 		if err != nil {
-			lg.Printf("Accept server data error %s, end this service", err.Error())
+			logs.Error("Accept server data error %s, end this service", err.Error())
 			break
 			break
 		}
 		}
 		switch flags {
 		switch flags {
 		case common.VERIFY_EER:
 		case common.VERIFY_EER:
-			lg.Fatalf("VKey:%s is incorrect, the server refuses to connect, please check", s.vKey)
+			logs.Error("VKey:%s is incorrect, the server refuses to connect, please check", s.vKey)
+			os.Exit(0)
 		case common.NEW_CONN:
 		case common.NEW_CONN:
 			if link, err := c.GetLinkInfo(); err != nil {
 			if link, err := c.GetLinkInfo(); err != nil {
 				break
 				break
@@ -83,12 +85,13 @@ func (s *TRPClient) processor(c *conn.Conn) {
 				link.Run(false)
 				link.Run(false)
 			}
 			}
 		case common.RES_CLOSE:
 		case common.RES_CLOSE:
-			lg.Fatalln("The authentication key is connected by another client or the server closes the client.")
+			logs.Error("The authentication key is connected by another client or the server closes the client.")
+			os.Exit(0)
 		case common.RES_MSG:
 		case common.RES_MSG:
-			lg.Println("Server-side return error")
+			logs.Error("Server-side return error")
 			break
 			break
 		default:
 		default:
-			lg.Println("The error could not be resolved")
+			logs.Warn("The error could not be resolved")
 			break
 			break
 		}
 		}
 	}
 	}
@@ -103,7 +106,7 @@ func (s *TRPClient) linkProcess(link *conn.Link, c *conn.Conn) {
 
 
 	if err != nil {
 	if err != nil {
 		c.WriteFail(link.Id)
 		c.WriteFail(link.Id)
-		lg.Println("connect to ", link.Host, "error:", err)
+		logs.Warn("connect to ", link.Host, "error:", err)
 		return
 		return
 	}
 	}
 	c.WriteSuccess(link.Id)
 	c.WriteSuccess(link.Id)
@@ -134,7 +137,7 @@ func (s *TRPClient) getMsgStatus() {
 	var err error
 	var err error
 	s.msgTunnel, err = NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_SEND_STATUS, s.proxyUrl)
 	s.msgTunnel, err = NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_SEND_STATUS, s.proxyUrl)
 	if err != nil {
 	if err != nil {
-		lg.Println("connect to ", s.svrAddr, "error:", err)
+		logs.Error("connect to ", s.svrAddr, "error:", err)
 		return
 		return
 	}
 	}
 	go func() {
 	go func() {
@@ -160,7 +163,7 @@ func (s *TRPClient) dealChan() {
 	var err error
 	var err error
 	s.tunnel, err = NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_CHAN, s.proxyUrl)
 	s.tunnel, err = NewConn(s.bridgeConnType, s.vKey, s.svrAddr, common.WORK_CHAN, s.proxyUrl)
 	if err != nil {
 	if err != nil {
-		lg.Println("connect to ", s.svrAddr, "error:", err)
+		logs.Error("connect to ", s.svrAddr, "error:", err)
 		return
 		return
 	}
 	}
 	go func() {
 	go func() {

+ 43 - 21
client/control.go

@@ -1,11 +1,14 @@
 package client
 package client
 
 
 import (
 import (
+	"encoding/binary"
 	"errors"
 	"errors"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/config"
 	"github.com/cnlh/nps/lib/config"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/conn"
-	"github.com/cnlh/nps/lib/lg"
+	"github.com/cnlh/nps/lib/crypt"
+	"github.com/cnlh/nps/lib/version"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
 	"github.com/cnlh/nps/vender/github.com/xtaci/kcp"
 	"github.com/cnlh/nps/vender/golang.org/x/net/proxy"
 	"github.com/cnlh/nps/vender/golang.org/x/net/proxy"
 	"io/ioutil"
 	"io/ioutil"
@@ -39,7 +42,7 @@ func GetTaskStatus(path string) {
 	if l, err := c.GetLen(); err != nil {
 	if l, err := c.GetLen(); err != nil {
 		log.Fatalln(err)
 		log.Fatalln(err)
 	} else if b, err := c.ReadLen(l); err != nil {
 	} else if b, err := c.ReadLen(l); err != nil {
-		lg.Fatalln(err)
+		log.Fatalln(err)
 	} else {
 	} else {
 		arr := strings.Split(string(b), common.CONN_DATA_SEQ)
 		arr := strings.Split(string(b), common.CONN_DATA_SEQ)
 		for _, v := range cnf.Hosts {
 		for _, v := range cnf.Hosts {
@@ -74,14 +77,16 @@ var errAdd = errors.New("The server returned an error, which port or host may ha
 func StartFromFile(path string) {
 func StartFromFile(path string) {
 	first := true
 	first := true
 	cnf, err := config.NewConfig(path)
 	cnf, err := config.NewConfig(path)
-	if err != nil {
-		lg.Fatalln(err)
+	if err != nil || cnf.CommonConfig == nil {
+		logs.Error("Config file %s loading error", path)
+		os.Exit(0)
 	}
 	}
-	lg.Printf("Loading configuration file %s successfully", path)
+
+	logs.Info("Loading configuration file %s successfully", path)
 re:
 re:
 	if first || cnf.CommonConfig.AutoReconnection {
 	if first || cnf.CommonConfig.AutoReconnection {
 		if !first {
 		if !first {
-			lg.Println("Reconnecting...")
+			logs.Info("Reconnecting...")
 			time.Sleep(time.Second * 5)
 			time.Sleep(time.Second * 5)
 		}
 		}
 	} else {
 	} else {
@@ -90,48 +95,51 @@ re:
 	first = false
 	first = false
 	c, err := NewConn(cnf.CommonConfig.Tp, cnf.CommonConfig.VKey, cnf.CommonConfig.Server, common.WORK_CONFIG, cnf.CommonConfig.ProxyUrl)
 	c, err := NewConn(cnf.CommonConfig.Tp, cnf.CommonConfig.VKey, cnf.CommonConfig.Server, common.WORK_CONFIG, cnf.CommonConfig.ProxyUrl)
 	if err != nil {
 	if err != nil {
-		lg.Println(err)
+		logs.Error(err)
 		goto re
 		goto re
 	}
 	}
-	if _, err := c.SendConfigInfo(cnf.CommonConfig.Cnf); err != nil {
-		lg.Println(err)
+	if _, err := c.SendConfigInfo(cnf.CommonConfig); err != nil {
+		logs.Error(err)
 		goto re
 		goto re
 	}
 	}
 	var b []byte
 	var b []byte
 	if b, err = c.ReadLen(16); err != nil {
 	if b, err = c.ReadLen(16); err != nil {
-		lg.Println(err)
+		logs.Error(err)
 		goto re
 		goto re
 	} else {
 	} else {
 		ioutil.WriteFile(filepath.Join(common.GetTmpPath(), "npc_vkey.txt"), []byte(string(b)), 0600)
 		ioutil.WriteFile(filepath.Join(common.GetTmpPath(), "npc_vkey.txt"), []byte(string(b)), 0600)
 	}
 	}
 	if !c.GetAddStatus() {
 	if !c.GetAddStatus() {
-		lg.Println(errAdd)
+		logs.Error(errAdd)
 		goto re
 		goto re
 	}
 	}
+
 	for _, v := range cnf.Hosts {
 	for _, v := range cnf.Hosts {
 		if _, err := c.SendHostInfo(v); err != nil {
 		if _, err := c.SendHostInfo(v); err != nil {
-			lg.Println(err)
+			logs.Error(err)
 			goto re
 			goto re
 		}
 		}
 		if !c.GetAddStatus() {
 		if !c.GetAddStatus() {
-			lg.Println(errAdd, v.Host)
+			logs.Error(errAdd, v.Host)
 			goto re
 			goto re
 		}
 		}
 	}
 	}
 	for _, v := range cnf.Tasks {
 	for _, v := range cnf.Tasks {
 		if _, err := c.SendTaskInfo(v); err != nil {
 		if _, err := c.SendTaskInfo(v); err != nil {
-			lg.Println(err)
+			logs.Error(err)
 			goto re
 			goto re
 		}
 		}
 		if !c.GetAddStatus() {
 		if !c.GetAddStatus() {
-			lg.Println(errAdd, v.Ports)
+			logs.Error(errAdd, v.Ports)
 			goto re
 			goto re
 		}
 		}
 	}
 	}
-
+	for _, v := range cnf.LocalServer {
+		go StartLocalServer(v, cnf.CommonConfig)
+	}
 	c.Close()
 	c.Close()
-
 	NewRPClient(cnf.CommonConfig.Server, string(b), cnf.CommonConfig.Tp, cnf.CommonConfig.ProxyUrl).Start()
 	NewRPClient(cnf.CommonConfig.Server, string(b), cnf.CommonConfig.Tp, cnf.CommonConfig.ProxyUrl).Start()
+	CloseLocalServer()
 	goto re
 	goto re
 }
 }
 
 
@@ -163,16 +171,30 @@ func NewConn(tp string, vkey string, server string, connType string, proxyUrl st
 		return nil, err
 		return nil, err
 	}
 	}
 	c := conn.NewConn(connection)
 	c := conn.NewConn(connection)
+	if b, err := c.ReadLen(32); err != nil {
+		logs.Error(err)
+		os.Exit(0)
+	} else if crypt.Md5(version.GetVersion()) != string(b) {
+		logs.Error("The client does not match the server version. The current version of the client is", version.GetVersion())
+		os.Exit(0)
+	} else if binary.Write(c, binary.LittleEndian, []byte(version.VERSION_OK)); err != nil {
+		logs.Error(err)
+		os.Exit(0)
+	}
 	if _, err := c.Write([]byte(common.Getverifyval(vkey))); err != nil {
 	if _, err := c.Write([]byte(common.Getverifyval(vkey))); err != nil {
-		lg.Println(err)
+		logs.Error(err)
+		os.Exit(0)
 	}
 	}
 	if s, err := c.ReadFlag(); err != nil {
 	if s, err := c.ReadFlag(); err != nil {
-		lg.Println(err)
+		logs.Error(err)
+		os.Exit(0)
 	} else if s == common.VERIFY_EER {
 	} else if s == common.VERIFY_EER {
-		lg.Fatalf("Validation key %s incorrect", vkey)
+		logs.Error("Validation key %s incorrect", vkey)
+		os.Exit(0)
 	}
 	}
 	if _, err := c.Write([]byte(connType)); err != nil {
 	if _, err := c.Write([]byte(connType)); err != nil {
-		lg.Println(err)
+		logs.Error(err)
+		os.Exit(0)
 	}
 	}
 	c.SetAlive(tp)
 	c.SetAlive(tp)
 
 

+ 54 - 0
client/local.go

@@ -0,0 +1,54 @@
+package client
+
+import (
+	"github.com/cnlh/nps/lib/common"
+	"github.com/cnlh/nps/lib/config"
+	"github.com/cnlh/nps/lib/crypt"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
+	"net"
+	"strings"
+)
+
+var LocalServer []*net.TCPListener
+
+func CloseLocalServer() {
+	for _, v := range LocalServer {
+		v.Close()
+	}
+}
+
+func StartLocalServer(l *config.LocalServer, config *config.CommonConfig) error {
+	listener, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), l.Port, ""})
+	if err != nil {
+		logs.Error("Local listener startup failed port %d, error %s", l.Port, err.Error())
+		return err
+	}
+	LocalServer = append(LocalServer, listener)
+	logs.Info("Successful start-up of local monitoring, port", l.Port)
+	for {
+		c, err := listener.AcceptTCP()
+		if err != nil {
+			if strings.Contains(err.Error(), "use of closed network connection") {
+				break
+			}
+			logs.Info(err)
+			continue
+		}
+		go process(c, config, l)
+	}
+	return nil
+}
+
+func process(conn net.Conn, config *config.CommonConfig, l *config.LocalServer) {
+	c, err := NewConn(config.Tp, config.VKey, config.Server, common.WORD_SECRET, config.ProxyUrl)
+	if err != nil {
+		logs.Error("Local connection server failed ", err.Error())
+	}
+	if _, err := c.Write([]byte(crypt.Md5(l.Password))); err != nil {
+		logs.Error("Local connection server failed ", err.Error())
+	}
+	go common.CopyBuffer(c, conn)
+	common.CopyBuffer(conn, c)
+	c.Close()
+	conn.Close()
+}

+ 5 - 6
cmd/npc/npc.go

@@ -5,14 +5,12 @@ import (
 	"github.com/cnlh/nps/client"
 	"github.com/cnlh/nps/client"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/daemon"
 	"github.com/cnlh/nps/lib/daemon"
-	"github.com/cnlh/nps/lib/lg"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"os"
 	"os"
 	"strings"
 	"strings"
 	"time"
 	"time"
 )
 )
 
 
-const VERSION = "v0.0.15"
-
 var (
 var (
 	serverAddr   = flag.String("server", "", "Server addr (ip:port)")
 	serverAddr   = flag.String("server", "", "Server addr (ip:port)")
 	configPath   = flag.String("config", "npc.conf", "Configuration file path")
 	configPath   = flag.String("config", "npc.conf", "Configuration file path")
@@ -20,6 +18,7 @@ var (
 	logType      = flag.String("log", "stdout", "Log output mode(stdout|file)")
 	logType      = flag.String("log", "stdout", "Log output mode(stdout|file)")
 	connType     = flag.String("type", "tcp", "Connection type with the server(kcp|tcp)")
 	connType     = flag.String("type", "tcp", "Connection type with the server(kcp|tcp)")
 	proxyUrl     = flag.String("proxy", "", "proxy socks5 url(eg:socks5://111:222@127.0.0.1:9007)")
 	proxyUrl     = flag.String("proxy", "", "proxy socks5 url(eg:socks5://111:222@127.0.0.1:9007)")
+	logLevel     = flag.String("log_level", "7", "log level 0~7")
 	registerTime = flag.Int("time", 2, "register time long /h")
 	registerTime = flag.Int("time", 2, "register time long /h")
 )
 )
 
 
@@ -37,14 +36,14 @@ func main() {
 	}
 	}
 	daemon.InitDaemon("npc", common.GetRunPath(), common.GetTmpPath())
 	daemon.InitDaemon("npc", common.GetRunPath(), common.GetTmpPath())
 	if *logType == "stdout" {
 	if *logType == "stdout" {
-		lg.InitLogFile("npc", true, common.GetLogPath())
+		logs.SetLogger(logs.AdapterConsole, `{"level":`+*logLevel+`,"color":true}`)
 	} else {
 	} else {
-		lg.InitLogFile("npc", false, common.GetLogPath())
+		logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"npc_log.log"}`)
 	}
 	}
 	if *verifyKey != "" && *serverAddr != "" {
 	if *verifyKey != "" && *serverAddr != "" {
 		for {
 		for {
 			client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl).Start()
 			client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl).Start()
-			lg.Println("It will be reconnected in five seconds")
+			logs.Info("It will be reconnected in five seconds")
 			time.Sleep(time.Second * 5)
 			time.Sleep(time.Second * 5)
 		}
 		}
 	} else {
 	} else {

+ 10 - 6
cmd/nps/nps.go

@@ -6,19 +6,18 @@ import (
 	"github.com/cnlh/nps/lib/daemon"
 	"github.com/cnlh/nps/lib/daemon"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/install"
 	"github.com/cnlh/nps/lib/install"
-	"github.com/cnlh/nps/lib/lg"
 	"github.com/cnlh/nps/server"
 	"github.com/cnlh/nps/server"
 	"github.com/cnlh/nps/server/test"
 	"github.com/cnlh/nps/server/test"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	_ "github.com/cnlh/nps/web/routers"
 	_ "github.com/cnlh/nps/web/routers"
 	"log"
 	"log"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 )
 )
 
 
-const VERSION = "v0.0.15"
-
 var (
 var (
+	level   string
 	logType = flag.String("log", "stdout", "Log output mode(stdout|file)")
 	logType = flag.String("log", "stdout", "Log output mode(stdout|file)")
 )
 )
 
 
@@ -37,17 +36,22 @@ func main() {
 			return
 			return
 		}
 		}
 	}
 	}
+	if level = beego.AppConfig.String("logLevel"); level == "" {
+		level = "7"
+	}
+	logs.Reset()
 	if *logType == "stdout" {
 	if *logType == "stdout" {
-		lg.InitLogFile("nps", true, common.GetLogPath())
+		logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
 	} else {
 	} else {
-		lg.InitLogFile("nps", false, common.GetLogPath())
+		logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"nps_log.log"}`)
 	}
 	}
 	task := &file.Tunnel{
 	task := &file.Tunnel{
 		Mode: "webServer",
 		Mode: "webServer",
 	}
 	}
 	bridgePort, err := beego.AppConfig.Int("bridgePort")
 	bridgePort, err := beego.AppConfig.Int("bridgePort")
 	if err != nil {
 	if err != nil {
-		lg.Fatalln("Getting bridgePort error", err)
+		logs.Error("Getting bridgePort error", err)
+		os.Exit(0)
 	}
 	}
 	beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "app.conf"))
 	beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "app.conf"))
 	server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridgeType"))
 	server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridgeType"))

+ 8 - 1
conf/app.conf

@@ -36,4 +36,11 @@ bridgeType=tcp
 # After the connection, the server will be able to open relevant ports and parse related domain names according to its own configuration file.
 # 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
 publicVkey=123
 
 
-
+#Traffic data persistence interval(minute)
+#Ignorance means no persistence
+flowStoreInterval=1
+
+#log level
+#LevelEmergency->0  LevelAlert->1 LevelCritical->2 LevelError->3 LevelWarning->4
+#LevelNotice->5 LevelInformational->6 LevelDebug->7
+logLevel=7

+ 1 - 1
conf/clients.csv

@@ -1 +1 @@
-7,7hv3avgeg2ldzvx7,,true,,,0,,0,0
+7,7hv3avgeg2ldzvx7,,true,,,1,,0,999,10

+ 1 - 0
conf/hosts.csv

@@ -0,0 +1 @@
+b.o.com,127.0.0.1:8082,7,,,,/,3,12995709,38827

+ 12 - 20
conf/npc.conf

@@ -4,32 +4,24 @@ tp=tcp
 vkey=123
 vkey=123
 auto_reconnection=true
 auto_reconnection=true
 crypt=true
 crypt=true
+
 [web1]
 [web1]
 host=a.o.com
 host=a.o.com
 host_change=www.proxy.com
 host_change=www.proxy.com
-target=127.0.0.1:8082
+target=127.0.0.1:8080
 location=/
 location=/
 
 
 [web2]
 [web2]
-host=a.proxy.com
-target=127.0.0.1:8080,127.0.0.1:8082
+host=127.0.0.1
 host_change=www.proxy.com
 host_change=www.proxy.com
-header_set_proxy=nps
-
-[tcp]
-mode=tcpServer
-target=8001-8005,8082
-port=9001-9005,9006
-
-[socks5]
-mode=socks5Server
-port=9007
+target=127.0.0.1:8080
+location=/cdn
 
 
-[http]
-mode=httpProxyServer
-port=9008
+[ssh_1118]
+mode=secretServer
+password=1111
+target=123.206.77.88:22
 
 
-[udp]
-mode=udpServer
-port=53
-target=114.114.114.114:53
+[secret_ssh]
+password=1111
+port=1000

+ 3 - 1
conf/tasks.csv

@@ -1 +1,3 @@
-9010,socks5Server,,1,27,7,
+9010,socks5Server,,1,27,7,,0,0,
+9002,tcpServer,127.0.0.1:8082,1,28,7,,9175971,17054,
+0,secretServer,123.206.77.88:22,1,30,7,私密隧道测试,15620,12628,tests

+ 16 - 16
lib/common/const.go

@@ -6,22 +6,22 @@ const (
 	COMPRESS_NONE_DECODE
 	COMPRESS_NONE_DECODE
 	COMPRESS_SNAPY_ENCODE
 	COMPRESS_SNAPY_ENCODE
 	COMPRESS_SNAPY_DECODE
 	COMPRESS_SNAPY_DECODE
-	VERIFY_EER       = "vkey"
-	VERIFY_SUCCESS   = "sucs"
-	WORK_MAIN        = "main"
-	WORK_CHAN        = "chan"
-	WORK_SEND_STATUS = "sdst"
-	WORK_CONFIG      = "conf"
-	WORK_REGISTER    = "rgst"
-	WORK_STATUS      = "stus"
-	RES_SIGN         = "sign"
-	RES_MSG          = "msg0"
-	RES_CLOSE        = "clse"
-	NEW_CONN         = "conn" //新连接标志
-	NEW_TASK         = "task" //新连接标志
-	NEW_CONF         = "conf" //新连接标志
-	NEW_HOST         = "host" //新连接标志
-
+	VERIFY_EER        = "vkey"
+	VERIFY_SUCCESS    = "sucs"
+	WORK_MAIN         = "main"
+	WORK_CHAN         = "chan"
+	WORK_SEND_STATUS  = "sdst"
+	WORK_CONFIG       = "conf"
+	WORK_REGISTER     = "rgst"
+	WORD_SECRET       = "sert"
+	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_TCP          = "tcp"
 	CONN_UDP          = "udp"
 	CONN_UDP          = "udp"
 	UnauthorizedBytes = `HTTP/1.1 401 Unauthorized
 	UnauthorizedBytes = `HTTP/1.1 401 Unauthorized

+ 9 - 0
lib/common/util.go

@@ -5,6 +5,8 @@ import (
 	"encoding/base64"
 	"encoding/base64"
 	"encoding/binary"
 	"encoding/binary"
 	"github.com/cnlh/nps/lib/crypt"
 	"github.com/cnlh/nps/lib/crypt"
+	"github.com/cnlh/nps/lib/pool"
+	"io"
 	"io/ioutil"
 	"io/ioutil"
 	"net"
 	"net"
 	"net/http"
 	"net/http"
@@ -246,3 +248,10 @@ func GetIpByAddr(addr string) string {
 	arr := strings.Split(addr, ":")
 	arr := strings.Split(addr, ":")
 	return arr[0]
 	return arr[0]
 }
 }
+
+func CopyBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
+	buf := pool.BufPoolCopy.Get().([]byte)
+	io.CopyBuffer(dst, src, buf)
+	pool.PutBufPoolCopy(buf)
+	return written, err
+}

+ 54 - 0
lib/config/config.go

@@ -1,6 +1,7 @@
 package config
 package config
 
 
 import (
 import (
+	"errors"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/file"
 	"regexp"
 	"regexp"
@@ -14,6 +15,11 @@ type CommonConfig struct {
 	AutoReconnection bool
 	AutoReconnection bool
 	Cnf              *file.Config
 	Cnf              *file.Config
 	ProxyUrl         string
 	ProxyUrl         string
+	Client           *file.Client
+}
+type LocalServer struct {
+	Port     int
+	Password string
 }
 }
 type Config struct {
 type Config struct {
 	content      string
 	content      string
@@ -21,6 +27,7 @@ type Config struct {
 	CommonConfig *CommonConfig
 	CommonConfig *CommonConfig
 	Hosts        []*file.Host
 	Hosts        []*file.Host
 	Tasks        []*file.Tunnel
 	Tasks        []*file.Tunnel
+	LocalServer  []*LocalServer
 }
 }
 
 
 func NewConfig(path string) (c *Config, err error) {
 func NewConfig(path string) (c *Config, err error) {
@@ -44,6 +51,11 @@ func NewConfig(path string) (c *Config, err error) {
 				nextIndex = len(c.content)
 				nextIndex = len(c.content)
 			}
 			}
 			nowContent = c.content[nowIndex:nextIndex]
 			nowContent = c.content[nowIndex:nextIndex]
+
+			if strings.Index(getTitleContent(c.title[i]), "secret") == 0 {
+				c.LocalServer = append(c.LocalServer, delLocalService(nowContent))
+				continue
+			}
 			switch c.title[i] {
 			switch c.title[i] {
 			case "[common]":
 			case "[common]":
 				c.CommonConfig = dealCommon(nowContent)
 				c.CommonConfig = dealCommon(nowContent)
@@ -68,9 +80,11 @@ func getTitleContent(s string) string {
 	re, _ := regexp.Compile(`[\[\]]`)
 	re, _ := regexp.Compile(`[\[\]]`)
 	return re.ReplaceAllString(s, "")
 	return re.ReplaceAllString(s, "")
 }
 }
+
 func dealCommon(s string) *CommonConfig {
 func dealCommon(s string) *CommonConfig {
 	c := &CommonConfig{}
 	c := &CommonConfig{}
 	c.Cnf = new(file.Config)
 	c.Cnf = new(file.Config)
+	c.Client = file.NewClient("", true, true)
 	for _, v := range strings.Split(s, "\n") {
 	for _, v := range strings.Split(s, "\n") {
 		item := strings.Split(v, "=")
 		item := strings.Split(v, "=")
 		if len(item) == 0 {
 		if len(item) == 0 {
@@ -97,10 +111,19 @@ func dealCommon(s string) *CommonConfig {
 			c.Cnf.Crypt = common.GetBoolByStr(item[1])
 			c.Cnf.Crypt = common.GetBoolByStr(item[1])
 		case "proxy_socks5_url":
 		case "proxy_socks5_url":
 			c.ProxyUrl = item[1]
 			c.ProxyUrl = item[1]
+		case "rate_limit":
+			c.Client.RateLimit = common.GetIntNoErrByStr(item[1])
+		case "flow_limit":
+			c.Client.Flow.FlowLimit = int64(common.GetIntNoErrByStr(item[1]))
+		case "max_conn":
+			c.Client.MaxConn = common.GetIntNoErrByStr(item[1])
+		case "remark":
+			c.Client.Remark = item[1]
 		}
 		}
 	}
 	}
 	return c
 	return c
 }
 }
+
 func dealHost(s string) *file.Host {
 func dealHost(s string) *file.Host {
 	h := &file.Host{}
 	h := &file.Host{}
 	var headerChange string
 	var headerChange string
@@ -146,12 +169,35 @@ func dealTunnel(s string) *file.Tunnel {
 			t.Mode = item[1]
 			t.Mode = item[1]
 		case "target":
 		case "target":
 			t.Target = item[1]
 			t.Target = item[1]
+		case "targetAddr":
+			t.TargetAddr = item[1]
+		case "password":
+			t.Password = item[1]
 		}
 		}
 	}
 	}
 	return t
 	return t
 
 
 }
 }
 
 
+func delLocalService(s string) *LocalServer {
+	l := new(LocalServer)
+	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":
+			l.Port = common.GetIntNoErrByStr(item[1])
+		case "password":
+			l.Password = item[1]
+		}
+	}
+	return l
+}
+
 func getAllTitle(content string) (arr []string, err error) {
 func getAllTitle(content string) (arr []string, err error) {
 	var re *regexp.Regexp
 	var re *regexp.Regexp
 	re, err = regexp.Compile(`\[.+?\]`)
 	re, err = regexp.Compile(`\[.+?\]`)
@@ -159,5 +205,13 @@ func getAllTitle(content string) (arr []string, err error) {
 		return
 		return
 	}
 	}
 	arr = re.FindAllString(content, -1)
 	arr = re.FindAllString(content, -1)
+	m := make(map[string]bool)
+	for _, v := range arr {
+		if _, ok := m[v]; ok {
+			err = errors.New("Item names are not allowed to be duplicated")
+			return
+		}
+		m[v] = true
+	}
 	return
 	return
 }
 }

+ 19 - 10
lib/conn/conn.go

@@ -6,6 +6,8 @@ import (
 	"encoding/binary"
 	"encoding/binary"
 	"errors"
 	"errors"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/common"
+	"github.com/cnlh/nps/lib/config"
+	"github.com/cnlh/nps/lib/crypt"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/pool"
 	"github.com/cnlh/nps/lib/pool"
 	"github.com/cnlh/nps/lib/rate"
 	"github.com/cnlh/nps/lib/rate"
@@ -317,7 +319,7 @@ func (s *Conn) GetHostInfo() (h *file.Host, err error) {
 }
 }
 
 
 //send task info
 //send task info
-func (s *Conn) SendConfigInfo(c *file.Config) (int, error) {
+func (s *Conn) SendConfigInfo(c *config.CommonConfig) (int, error) {
 	/*
 	/*
 		The task info is formed as follows:
 		The task info is formed as follows:
 		+----+-----+---------+
 		+----+-----+---------+
@@ -328,14 +330,15 @@ func (s *Conn) SendConfigInfo(c *file.Config) (int, error) {
 	*/
 	*/
 	raw := bytes.NewBuffer([]byte{})
 	raw := bytes.NewBuffer([]byte{})
 	binary.Write(raw, binary.LittleEndian, []byte(common.NEW_CONF))
 	binary.Write(raw, binary.LittleEndian, []byte(common.NEW_CONF))
-	common.BinaryWrite(raw, c.U, c.P, common.GetStrByBool(c.Crypt), c.Compress)
+	common.BinaryWrite(raw, c.Cnf.U, c.Cnf.P, common.GetStrByBool(c.Cnf.Crypt), c.Cnf.Compress, strconv.Itoa(c.Client.RateLimit),
+		strconv.Itoa(int(c.Client.Flow.FlowLimit)), strconv.Itoa(c.Client.MaxConn), c.Client.Remark)
 	s.Lock()
 	s.Lock()
 	defer s.Unlock()
 	defer s.Unlock()
 	return s.Write(raw.Bytes())
 	return s.Write(raw.Bytes())
 }
 }
 
 
 //get task info
 //get task info
-func (s *Conn) GetConfigInfo() (c *file.Config, err error) {
+func (s *Conn) GetConfigInfo() (c *file.Client, err error) {
 	var l int
 	var l int
 	var b []byte
 	var b []byte
 	if l, err = s.GetLen(); err != nil {
 	if l, err = s.GetLen(); err != nil {
@@ -344,12 +347,16 @@ func (s *Conn) GetConfigInfo() (c *file.Config, err error) {
 		return
 		return
 	} else {
 	} else {
 		arr := strings.Split(string(b), common.CONN_DATA_SEQ)
 		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])
+		c = file.NewClient(crypt.GetRandomString(16), true, false)
+		c.Cnf.U = arr[0]
+		c.Cnf.P = arr[1]
+		c.Cnf.Crypt = common.GetBoolByStr(arr[2])
+		c.Cnf.Compress = arr[3]
+		c.RateLimit = common.GetIntNoErrByStr(arr[4])
+		c.Flow.FlowLimit = int64(common.GetIntNoErrByStr(arr[5]))
+		c.MaxConn = common.GetIntNoErrByStr(arr[6])
+		c.Remark = arr[7]
+		c.Cnf.CompressDecode, c.Cnf.CompressDecode = common.GetCompressType(arr[3])
 	}
 	}
 	return
 	return
 }
 }
@@ -366,7 +373,7 @@ func (s *Conn) SendTaskInfo(t *file.Tunnel) (int, error) {
 	*/
 	*/
 	raw := bytes.NewBuffer([]byte{})
 	raw := bytes.NewBuffer([]byte{})
 	binary.Write(raw, binary.LittleEndian, []byte(common.NEW_TASK))
 	binary.Write(raw, binary.LittleEndian, []byte(common.NEW_TASK))
-	common.BinaryWrite(raw, t.Mode, t.Ports, t.Target, t.Remark)
+	common.BinaryWrite(raw, t.Mode, t.Ports, t.Target, t.Remark, t.TargetAddr, t.Password)
 	s.Lock()
 	s.Lock()
 	defer s.Unlock()
 	defer s.Unlock()
 	return s.Write(raw.Bytes())
 	return s.Write(raw.Bytes())
@@ -390,6 +397,8 @@ func (s *Conn) GetTaskInfo() (t *file.Tunnel, err error) {
 		t.Status = true
 		t.Status = true
 		t.Flow = new(file.Flow)
 		t.Flow = new(file.Flow)
 		t.Remark = arr[3]
 		t.Remark = arr[3]
+		t.TargetAddr = arr[4]
+		t.Password = arr[5]
 		t.NoStore = true
 		t.NoStore = true
 	}
 	}
 	return
 	return

+ 12 - 0
lib/conn/link.go

@@ -8,6 +8,18 @@ import (
 	"net"
 	"net"
 )
 )
 
 
+type Secret struct {
+	Password string
+	Conn     *Conn
+}
+
+func NewSecret(p string, conn *Conn) *Secret {
+	return &Secret{
+		Password: p,
+		Conn:     conn,
+	}
+}
+
 type Link struct {
 type Link struct {
 	Id            int    //id
 	Id            int    //id
 	ConnType      string //连接类型
 	ConnType      string //连接类型

+ 3 - 1
lib/file/csv.go

@@ -14,7 +14,9 @@ var (
 func GetCsvDb() *Csv {
 func GetCsvDb() *Csv {
 	once.Do(func() {
 	once.Do(func() {
 		CsvDb = NewCsv(common.GetRunPath())
 		CsvDb = NewCsv(common.GetRunPath())
-		CsvDb.Init()
+		CsvDb.LoadClientFromCsv()
+		CsvDb.LoadTaskFromCsv()
+		CsvDb.LoadHostFromCsv()
 	})
 	})
 	return CsvDb
 	return CsvDb
 }
 }

+ 53 - 22
lib/file/file.go

@@ -3,9 +3,11 @@ package file
 import (
 import (
 	"encoding/csv"
 	"encoding/csv"
 	"errors"
 	"errors"
+	"fmt"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/common"
-	"github.com/cnlh/nps/lib/lg"
+	"github.com/cnlh/nps/lib/crypt"
 	"github.com/cnlh/nps/lib/rate"
 	"github.com/cnlh/nps/lib/rate"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"net/http"
 	"net/http"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
@@ -33,17 +35,11 @@ type Csv struct {
 	sync.Mutex
 	sync.Mutex
 }
 }
 
 
-func (s *Csv) Init() {
-	s.LoadClientFromCsv()
-	s.LoadTaskFromCsv()
-	s.LoadHostFromCsv()
-}
-
 func (s *Csv) StoreTasksToCsv() {
 func (s *Csv) StoreTasksToCsv() {
 	// 创建文件
 	// 创建文件
 	csvFile, err := os.Create(filepath.Join(s.RunPath, "conf", "tasks.csv"))
 	csvFile, err := os.Create(filepath.Join(s.RunPath, "conf", "tasks.csv"))
 	if err != nil {
 	if err != nil {
-		lg.Fatalf(err.Error())
+		logs.Error(err.Error())
 	}
 	}
 	defer csvFile.Close()
 	defer csvFile.Close()
 	writer := csv.NewWriter(csvFile)
 	writer := csv.NewWriter(csvFile)
@@ -59,10 +55,13 @@ func (s *Csv) StoreTasksToCsv() {
 			strconv.Itoa(task.Id),
 			strconv.Itoa(task.Id),
 			strconv.Itoa(task.Client.Id),
 			strconv.Itoa(task.Client.Id),
 			task.Remark,
 			task.Remark,
+			strconv.Itoa(int(task.Flow.ExportFlow)),
+			strconv.Itoa(int(task.Flow.InletFlow)),
+			task.Password,
 		}
 		}
 		err := writer.Write(record)
 		err := writer.Write(record)
 		if err != nil {
 		if err != nil {
-			lg.Fatalf(err.Error())
+			logs.Error(err.Error())
 		}
 		}
 	}
 	}
 	writer.Flush()
 	writer.Flush()
@@ -90,20 +89,24 @@ func (s *Csv) LoadTaskFromCsv() {
 	path := filepath.Join(s.RunPath, "conf", "tasks.csv")
 	path := filepath.Join(s.RunPath, "conf", "tasks.csv")
 	records, err := s.openFile(path)
 	records, err := s.openFile(path)
 	if err != nil {
 	if err != nil {
-		lg.Fatalln("配置文件打开错误:", path)
+		logs.Error("Profile Opening Error:", path)
+		os.Exit(0)
 	}
 	}
 	var tasks []*Tunnel
 	var tasks []*Tunnel
 	// 将每一行数据保存到内存slice中
 	// 将每一行数据保存到内存slice中
 	for _, item := range records {
 	for _, item := range records {
 		post := &Tunnel{
 		post := &Tunnel{
-			Port:   common.GetIntNoErrByStr(item[0]),
-			Mode:   item[1],
-			Target: item[2],
-			Status: common.GetBoolByStr(item[3]),
-			Id:     common.GetIntNoErrByStr(item[4]),
-			Remark: item[6],
+			Port:     common.GetIntNoErrByStr(item[0]),
+			Mode:     item[1],
+			Target:   item[2],
+			Status:   common.GetBoolByStr(item[3]),
+			Id:       common.GetIntNoErrByStr(item[4]),
+			Remark:   item[6],
+			Password: item[9],
 		}
 		}
 		post.Flow = new(Flow)
 		post.Flow = new(Flow)
+		post.Flow.ExportFlow = int64(common.GetIntNoErrByStr(item[7]))
+		post.Flow.InletFlow = int64(common.GetIntNoErrByStr(item[8]))
 		if post.Client, err = s.GetClient(common.GetIntNoErrByStr(item[5])); err != nil {
 		if post.Client, err = s.GetClient(common.GetIntNoErrByStr(item[5])); err != nil {
 			continue
 			continue
 		}
 		}
@@ -142,10 +145,16 @@ func (s *Csv) GetIdByVerifyKey(vKey string, addr string) (int, error) {
 	return 0, errors.New("not found")
 	return 0, errors.New("not found")
 }
 }
 
 
-func (s *Csv) NewTask(t *Tunnel) {
+func (s *Csv) NewTask(t *Tunnel) error {
+	for _, v := range s.Tasks {
+		if v.Mode == "secretServer" && v.Password == t.Password {
+			return errors.New(fmt.Sprintf("Secret mode keys %s must be unique", t.Password))
+		}
+	}
 	t.Flow = new(Flow)
 	t.Flow = new(Flow)
 	s.Tasks = append(s.Tasks, t)
 	s.Tasks = append(s.Tasks, t)
 	s.StoreTasksToCsv()
 	s.StoreTasksToCsv()
+	return nil
 }
 }
 
 
 func (s *Csv) UpdateTask(t *Tunnel) error {
 func (s *Csv) UpdateTask(t *Tunnel) error {
@@ -171,6 +180,16 @@ func (s *Csv) DelTask(id int) error {
 	return errors.New("不存在")
 	return errors.New("不存在")
 }
 }
 
 
+//md5 password
+func (s *Csv) GetSecretTask(p string) *Tunnel {
+	for _, v := range s.Tasks {
+		if crypt.Md5(v.Password) == p {
+			return v
+		}
+	}
+	return nil
+}
+
 func (s *Csv) GetTask(id int) (v *Tunnel, err error) {
 func (s *Csv) GetTask(id int) (v *Tunnel, err error) {
 	for _, v = range s.Tasks {
 	for _, v = range s.Tasks {
 		if v.Id == id {
 		if v.Id == id {
@@ -205,6 +224,8 @@ func (s *Csv) StoreHostToCsv() {
 			host.Remark,
 			host.Remark,
 			host.Location,
 			host.Location,
 			strconv.Itoa(host.Id),
 			strconv.Itoa(host.Id),
+			strconv.Itoa(int(host.Flow.ExportFlow)),
+			strconv.Itoa(int(host.Flow.InletFlow)),
 		}
 		}
 		err1 := writer.Write(record)
 		err1 := writer.Write(record)
 		if err1 != nil {
 		if err1 != nil {
@@ -219,7 +240,8 @@ func (s *Csv) LoadClientFromCsv() {
 	path := filepath.Join(s.RunPath, "conf", "clients.csv")
 	path := filepath.Join(s.RunPath, "conf", "clients.csv")
 	records, err := s.openFile(path)
 	records, err := s.openFile(path)
 	if err != nil {
 	if err != nil {
-		lg.Fatalln("配置文件打开错误:", path)
+		logs.Error("Profile Opening Error:", path)
+		os.Exit(0)
 	}
 	}
 	var clients []*Client
 	var clients []*Client
 	// 将每一行数据保存到内存slice中
 	// 将每一行数据保存到内存slice中
@@ -236,6 +258,7 @@ func (s *Csv) LoadClientFromCsv() {
 				Crypt:    common.GetBoolByStr(item[6]),
 				Crypt:    common.GetBoolByStr(item[6]),
 				Compress: item[7],
 				Compress: item[7],
 			},
 			},
+			MaxConn: common.GetIntNoErrByStr(item[10]),
 		}
 		}
 		if post.Id > s.ClientIncreaseId {
 		if post.Id > s.ClientIncreaseId {
 			s.ClientIncreaseId = post.Id
 			s.ClientIncreaseId = post.Id
@@ -255,7 +278,8 @@ func (s *Csv) LoadHostFromCsv() {
 	path := filepath.Join(s.RunPath, "conf", "hosts.csv")
 	path := filepath.Join(s.RunPath, "conf", "hosts.csv")
 	records, err := s.openFile(path)
 	records, err := s.openFile(path)
 	if err != nil {
 	if err != nil {
-		lg.Fatalln("配置文件打开错误:", path)
+		logs.Error("Profile Opening Error:", path)
+		os.Exit(0)
 	}
 	}
 	var hosts []*Host
 	var hosts []*Host
 	// 将每一行数据保存到内存slice中
 	// 将每一行数据保存到内存slice中
@@ -273,6 +297,8 @@ func (s *Csv) LoadHostFromCsv() {
 			continue
 			continue
 		}
 		}
 		post.Flow = new(Flow)
 		post.Flow = new(Flow)
+		post.Flow.ExportFlow = int64(common.GetIntNoErrByStr(item[8]))
+		post.Flow.InletFlow = int64(common.GetIntNoErrByStr(item[9]))
 		hosts = append(hosts, post)
 		hosts = append(hosts, post)
 		if post.Id > s.HostIncreaseId {
 		if post.Id > s.HostIncreaseId {
 			s.HostIncreaseId = post.Id
 			s.HostIncreaseId = post.Id
@@ -350,7 +376,9 @@ func (s *Csv) NewClient(c *Client) {
 	if c.Id == 0 {
 	if c.Id == 0 {
 		c.Id = s.GetClientId()
 		c.Id = s.GetClientId()
 	}
 	}
-	c.Flow = new(Flow)
+	if c.Flow == nil {
+		c.Flow = new(Flow)
+	}
 	s.Lock()
 	s.Lock()
 	defer s.Unlock()
 	defer s.Unlock()
 	s.Clients = append(s.Clients, c)
 	s.Clients = append(s.Clients, c)
@@ -433,6 +461,8 @@ func (s *Csv) GetHostById(id int) (h *Host, err error) {
 //get key by host from x
 //get key by host from x
 func (s *Csv) GetInfoByHost(host string, r *http.Request) (h *Host, err error) {
 func (s *Csv) GetInfoByHost(host string, r *http.Request) (h *Host, err error) {
 	var hosts []*Host
 	var hosts []*Host
+	//Handling Ported Access
+	host = common.GetIpByAddr(host)
 	for _, v := range s.Hosts {
 	for _, v := range s.Hosts {
 		//Remove http(s) http(s)://a.proxy.com
 		//Remove http(s) http(s)://a.proxy.com
 		//*.proxy.com *.a.proxy.com  Do some pan-parsing
 		//*.proxy.com *.a.proxy.com  Do some pan-parsing
@@ -467,7 +497,7 @@ func (s *Csv) StoreClientsToCsv() {
 	// 创建文件
 	// 创建文件
 	csvFile, err := os.Create(filepath.Join(s.RunPath, "conf", "clients.csv"))
 	csvFile, err := os.Create(filepath.Join(s.RunPath, "conf", "clients.csv"))
 	if err != nil {
 	if err != nil {
-		lg.Fatalln(err.Error())
+		logs.Error(err.Error())
 	}
 	}
 	defer csvFile.Close()
 	defer csvFile.Close()
 	writer := csv.NewWriter(csvFile)
 	writer := csv.NewWriter(csvFile)
@@ -486,10 +516,11 @@ func (s *Csv) StoreClientsToCsv() {
 			client.Cnf.Compress,
 			client.Cnf.Compress,
 			strconv.Itoa(client.RateLimit),
 			strconv.Itoa(client.RateLimit),
 			strconv.Itoa(int(client.Flow.FlowLimit)),
 			strconv.Itoa(int(client.Flow.FlowLimit)),
+			strconv.Itoa(int(client.MaxConn)),
 		}
 		}
 		err := writer.Write(record)
 		err := writer.Write(record)
 		if err != nil {
 		if err != nil {
-			lg.Fatalln(err.Error())
+			logs.Error(err.Error())
 		}
 		}
 	}
 	}
 	writer.Flush()
 	writer.Flush()

+ 35 - 23
lib/file/obj.go

@@ -33,6 +33,8 @@ type Client struct {
 	Rate      *rate.Rate //速度控制
 	Rate      *rate.Rate //速度控制
 	NoStore   bool
 	NoStore   bool
 	NoDisplay bool
 	NoDisplay bool
+	MaxConn   int //客户端最大连接数
+	NowConn   int //当前连接数
 	id        int
 	id        int
 	sync.RWMutex
 	sync.RWMutex
 }
 }
@@ -62,18 +64,40 @@ func (s *Client) GetId() int {
 	return s.id
 	return s.id
 }
 }
 
 
+func (s *Client) CutConn() {
+	s.Lock()
+	defer s.Unlock()
+	s.NowConn++
+}
+
+func (s *Client) AddConn() {
+	s.Lock()
+	defer s.Unlock()
+	s.NowConn--
+}
+
+func (s *Client) GetConn() bool {
+	s.CutConn()
+	if s.MaxConn == 0 || s.NowConn < s.MaxConn {
+		return true
+	}
+	return false
+}
+
 type Tunnel struct {
 type Tunnel struct {
-	Id        int     //Id
-	Port      int     //服务端监听端口
-	Mode      string  //启动方式
-	Target    string  //目标
-	Status    bool    //设置是否开启
-	RunStatus bool    //当前运行状态
-	Client    *Client //所属客户端id
-	Ports     string  //客户端与服务端传递
-	Flow      *Flow
-	Remark    string //备注
-	NoStore   bool
+	Id         int     //Id
+	Port       int     //服务端监听端口
+	Mode       string  //启动方式
+	Target     string  //目标
+	Status     bool    //设置是否开启
+	RunStatus  bool    //当前运行状态
+	Client     *Client //所属客户端id
+	Ports      string  //客户端与服务端传递
+	Flow       *Flow
+	Password   string //私密模式密码,唯一
+	Remark     string //备注
+	TargetAddr string
+	NoStore    bool
 }
 }
 
 
 type Config struct {
 type Config struct {
@@ -114,15 +138,3 @@ func (s *Host) GetRandomTarget() string {
 	}
 	}
 	return s.TargetArr[s.NowIndex]
 	return s.TargetArr[s.NowIndex]
 }
 }
-
-//深拷贝Config
-func DeepCopyConfig(c *Config) *Config {
-	return &Config{
-		U:              c.U,
-		P:              c.P,
-		Compress:       c.Compress,
-		Crypt:          c.Crypt,
-		CompressEncode: c.CompressEncode,
-		CompressDecode: c.CompressDecode,
-	}
-}

+ 0 - 45
lib/lg/log.go

@@ -1,45 +0,0 @@
-package lg
-
-import (
-	"log"
-	"os"
-	"path/filepath"
-	"runtime"
-)
-
-var Log *log.Logger
-
-func InitLogFile(f string, isStdout bool, logPath string) {
-	var prefix string
-	if !isStdout {
-		logFile, err := os.OpenFile(filepath.Join(logPath, f+"_log.txt"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)
-		if err != nil {
-			log.Fatalln("open file error !", err)
-		}
-		if runtime.GOOS == "windows" {
-			prefix = "\r\n"
-		}
-		Log = log.New(logFile, prefix, log.Ldate|log.Ltime)
-	} else {
-		Log = log.New(os.Stdout, "", log.Ldate|log.Ltime)
-	}
-}
-
-func Println(v ...interface{}) {
-	Log.Println(v...)
-}
-
-func Fatalln(v ...interface{}) {
-	Log.SetPrefix("error ")
-	Log.Fatalln(v...)
-	Log.SetPrefix("")
-}
-func Fatalf(format string, v ...interface{}) {
-	Log.SetPrefix("error ")
-	Log.Fatalf(format, v...)
-	Log.SetPrefix("")
-}
-
-func Printf(format string, v ...interface{}) {
-	Log.Printf(format, v...)
-}

+ 8 - 0
lib/version/version.go

@@ -0,0 +1,8 @@
+package version
+
+const VERSION = "0.0.16"
+const VERSION_OK = "vrok"
+
+func GetVersion() string {
+	return VERSION
+}

+ 32 - 8
server/proxy/base.go

@@ -17,8 +17,8 @@ type Service interface {
 	Close() error
 	Close() error
 }
 }
 
 
-//server base struct
-type server struct {
+//Server BaseServer struct
+type BaseServer struct {
 	id           int
 	id           int
 	bridge       *bridge.Bridge
 	bridge       *bridge.Bridge
 	task         *file.Tunnel
 	task         *file.Tunnel
@@ -26,21 +26,30 @@ type server struct {
 	sync.Mutex
 	sync.Mutex
 }
 }
 
 
-func (s *server) FlowAdd(in, out int64) {
+func NewBaseServer(bridge *bridge.Bridge, task *file.Tunnel) *BaseServer {
+	return &BaseServer{
+		bridge:       bridge,
+		task:         task,
+		errorContent: nil,
+		Mutex:        sync.Mutex{},
+	}
+}
+
+func (s *BaseServer) FlowAdd(in, out int64) {
 	s.Lock()
 	s.Lock()
 	defer s.Unlock()
 	defer s.Unlock()
 	s.task.Flow.ExportFlow += out
 	s.task.Flow.ExportFlow += out
 	s.task.Flow.InletFlow += in
 	s.task.Flow.InletFlow += in
 }
 }
 
 
-func (s *server) FlowAddHost(host *file.Host, in, out int64) {
+func (s *BaseServer) FlowAddHost(host *file.Host, in, out int64) {
 	s.Lock()
 	s.Lock()
 	defer s.Unlock()
 	defer s.Unlock()
 	host.Flow.ExportFlow += out
 	host.Flow.ExportFlow += out
 	host.Flow.InletFlow += in
 	host.Flow.InletFlow += in
 }
 }
 
 
-func (s *server) linkCopy(link *conn.Link, c *conn.Conn, rb []byte, tunnel *conn.Conn, flow *file.Flow) {
+func (s *BaseServer) linkCopy(link *conn.Link, c *conn.Conn, rb []byte, tunnel *conn.Conn, flow *file.Flow) {
 	if rb != nil {
 	if rb != nil {
 		if _, err := tunnel.SendMsg(rb, link); err != nil {
 		if _, err := tunnel.SendMsg(rb, link); err != nil {
 			c.Close()
 			c.Close()
@@ -68,16 +77,17 @@ func (s *server) linkCopy(link *conn.Link, c *conn.Conn, rb []byte, tunnel *conn
 		}
 		}
 		<-link.StatusCh
 		<-link.StatusCh
 	}
 	}
+	s.task.Client.AddConn()
 	pool.PutBufPoolCopy(buf)
 	pool.PutBufPoolCopy(buf)
 }
 }
 
 
-func (s *server) writeConnFail(c net.Conn) {
+func (s *BaseServer) writeConnFail(c net.Conn) {
 	c.Write([]byte(common.ConnectionFailBytes))
 	c.Write([]byte(common.ConnectionFailBytes))
 	c.Write(s.errorContent)
 	c.Write(s.errorContent)
 }
 }
 
 
 //权限认证
 //权限认证
-func (s *server) auth(r *http.Request, c *conn.Conn, u, p string) error {
+func (s *BaseServer) auth(r *http.Request, c *conn.Conn, u, p string) error {
 	if u != "" && p != "" && !common.CheckAuth(r, u, p) {
 	if u != "" && p != "" && !common.CheckAuth(r, u, p) {
 		c.Write([]byte(common.UnauthorizedBytes))
 		c.Write([]byte(common.UnauthorizedBytes))
 		c.Close()
 		c.Close()
@@ -86,9 +96,23 @@ func (s *server) auth(r *http.Request, c *conn.Conn, u, p string) error {
 	return nil
 	return nil
 }
 }
 
 
-func (s *server) checkFlow() error {
+func (s *BaseServer) 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) {
 	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 errors.New("Traffic exceeded")
 	}
 	}
 	return nil
 	return nil
 }
 }
+
+//与客户端建立通道
+func (s *BaseServer) DealClient(c *conn.Conn, addr string, rb []byte) error {
+	link := conn.NewLink(s.task.Client.GetId(), common.CONN_TCP, addr, s.task.Client.Cnf.CompressEncode, s.task.Client.Cnf.CompressDecode, s.task.Client.Cnf.Crypt, c, s.task.Flow, nil, s.task.Client.Rate, nil)
+
+	if tunnel, err := s.bridge.SendLinkInfo(s.task.Client.Id, link, c.Conn.RemoteAddr().String()); err != nil {
+		c.Close()
+		return err
+	} else {
+		link.Run(true)
+		s.linkCopy(link, c, rb, tunnel, s.task.Flow)
+	}
+	return nil
+}

+ 27 - 12
server/proxy/http.go

@@ -7,17 +7,18 @@ import (
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/file"
-	"github.com/cnlh/nps/lib/lg"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"net/http"
 	"net/http"
 	"net/http/httputil"
 	"net/http/httputil"
+	"os"
 	"path/filepath"
 	"path/filepath"
 	"strconv"
 	"strconv"
 	"sync"
 	"sync"
 )
 )
 
 
 type httpServer struct {
 type httpServer struct {
-	server
+	BaseServer
 	httpPort  int //http端口
 	httpPort  int //http端口
 	httpsPort int //https监听端口
 	httpsPort int //https监听端口
 	pemPath   string
 	pemPath   string
@@ -31,7 +32,7 @@ func NewHttp(bridge *bridge.Bridge, c *file.Tunnel) *httpServer {
 	pemPath := beego.AppConfig.String("pemPath")
 	pemPath := beego.AppConfig.String("pemPath")
 	keyPath := beego.AppConfig.String("keyPath")
 	keyPath := beego.AppConfig.String("keyPath")
 	return &httpServer{
 	return &httpServer{
-		server: server{
+		BaseServer: BaseServer{
 			task:   c,
 			task:   c,
 			bridge: bridge,
 			bridge: bridge,
 			Mutex:  sync.Mutex{},
 			Mutex:  sync.Mutex{},
@@ -54,26 +55,30 @@ func (s *httpServer) Start() error {
 	if s.httpPort > 0 {
 	if s.httpPort > 0 {
 		http = s.NewServer(s.httpPort)
 		http = s.NewServer(s.httpPort)
 		go func() {
 		go func() {
-			lg.Println("Start http listener, port is", s.httpPort)
+			logs.Info("Start http listener, port is", s.httpPort)
 			err := http.ListenAndServe()
 			err := http.ListenAndServe()
 			if err != nil {
 			if err != nil {
-				lg.Fatalln(err)
+				logs.Error(err)
+				os.Exit(0)
 			}
 			}
 		}()
 		}()
 	}
 	}
 	if s.httpsPort > 0 {
 	if s.httpsPort > 0 {
 		if !common.FileExists(s.pemPath) {
 		if !common.FileExists(s.pemPath) {
-			lg.Fatalf("ssl certFile %s is not exist", s.pemPath)
+			logs.Error("ssl certFile %s is not exist", s.pemPath)
+			os.Exit(0)
 		}
 		}
 		if !common.FileExists(s.keyPath) {
 		if !common.FileExists(s.keyPath) {
-			lg.Fatalf("ssl keyFile %s exist", s.keyPath)
+			logs.Error("ssl keyFile %s exist", s.keyPath)
+			os.Exit(0)
 		}
 		}
 		https = s.NewServer(s.httpsPort)
 		https = s.NewServer(s.httpsPort)
 		go func() {
 		go func() {
-			lg.Println("Start https listener, port is", s.httpsPort)
+			logs.Info("Start https listener, port is", s.httpsPort)
 			err := https.ListenAndServeTLS(s.pemPath, s.keyPath)
 			err := https.ListenAndServeTLS(s.pemPath, s.keyPath)
 			if err != nil {
 			if err != nil {
-				lg.Fatalln(err)
+				logs.Error(err)
+				os.Exit(0)
 			}
 			}
 		}()
 		}()
 	}
 	}
@@ -118,9 +123,14 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) {
 		err      error
 		err      error
 	)
 	)
 	if host, err = file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil {
 	if host, err = file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil {
-		lg.Printf("the url %s %s can't be parsed!", r.Host, r.RequestURI)
+		logs.Notice("the url %s %s can't be parsed!", r.Host, r.RequestURI)
 		goto end
 		goto end
+	} else if !host.Client.GetConn() {
+		logs.Notice("Connections exceed the current client %d limit", host.Client.Id)
+		c.Close()
+		return
 	} else {
 	} else {
+		logs.Trace("New http(s) connection,clientId %d,host %s,url %s,remote address %s", host.Client.Id, r.Host, r.URL, r.RemoteAddr)
 		lastHost = host
 		lastHost = host
 	}
 	}
 	for {
 	for {
@@ -137,22 +147,24 @@ func (s *httpServer) process(c *conn.Conn, r *http.Request) {
 			}
 			}
 			lk = conn.NewLink(host.Client.GetId(), common.CONN_TCP, host.GetRandomTarget(), host.Client.Cnf.CompressEncode, host.Client.Cnf.CompressDecode, host.Client.Cnf.Crypt, c, host.Flow, nil, host.Client.Rate, nil)
 			lk = conn.NewLink(host.Client.GetId(), common.CONN_TCP, host.GetRandomTarget(), host.Client.Cnf.CompressEncode, host.Client.Cnf.CompressDecode, host.Client.Cnf.Crypt, c, host.Flow, nil, host.Client.Rate, nil)
 			if tunnel, err = s.bridge.SendLinkInfo(host.Client.Id, lk, c.Conn.RemoteAddr().String()); err != nil {
 			if tunnel, err = s.bridge.SendLinkInfo(host.Client.Id, lk, c.Conn.RemoteAddr().String()); err != nil {
-				lg.Println(err)
+				logs.Notice(err)
 				break
 				break
 			}
 			}
 			lk.Run(true)
 			lk.Run(true)
 			isConn = false
 			isConn = false
 		} else {
 		} else {
 			r, err = http.ReadRequest(bufio.NewReader(c))
 			r, err = http.ReadRequest(bufio.NewReader(c))
+			logs.Trace("New http(s) connection,clientId %d,host %s,url %s,remote address %s", host.Client.Id, r.Host, r.URL, r.RemoteAddr)
 			if err != nil {
 			if err != nil {
 				break
 				break
 			}
 			}
 			if host, err = file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil {
 			if host, err = file.GetCsvDb().GetInfoByHost(r.Host, r); err != nil {
-				lg.Printf("the url %s %s is not found !", r.Host, r.RequestURI)
+				logs.Notice("the url %s %s can't be parsed!", r.Host, r.RequestURI)
 				break
 				break
 			} else if host != lastHost {
 			} else if host != lastHost {
 				lastHost = host
 				lastHost = host
 				isConn = true
 				isConn = true
+				host.Client.AddConn()
 				goto start
 				goto start
 			}
 			}
 		}
 		}
@@ -176,6 +188,9 @@ end:
 		tunnel.SendMsg([]byte(common.IO_EOF), lk)
 		tunnel.SendMsg([]byte(common.IO_EOF), lk)
 	}
 	}
 	c.Close()
 	c.Close()
+	if host != nil {
+		host.Client.AddConn()
+	}
 }
 }
 
 
 func (s *httpServer) NewServer(port int) *http.Server {
 func (s *httpServer) NewServer(port int) *http.Server {

+ 16 - 11
server/proxy/socks5.go

@@ -7,7 +7,7 @@ import (
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/file"
-	"github.com/cnlh/nps/lib/lg"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"io"
 	"io"
 	"net"
 	"net"
 	"strconv"
 	"strconv"
@@ -48,7 +48,7 @@ const (
 )
 )
 
 
 type Sock5ModeServer struct {
 type Sock5ModeServer struct {
-	server
+	BaseServer
 	listener net.Listener
 	listener net.Listener
 }
 }
 
 
@@ -67,7 +67,7 @@ func (s *Sock5ModeServer) handleRequest(c net.Conn) {
 	_, err := io.ReadFull(c, header)
 	_, err := io.ReadFull(c, header)
 
 
 	if err != nil {
 	if err != nil {
-		lg.Println("illegal request", err)
+		logs.Warn("illegal request", err)
 		c.Close()
 		c.Close()
 		return
 		return
 	}
 	}
@@ -165,7 +165,6 @@ func (s *Sock5ModeServer) handleBind(c net.Conn) {
 
 
 //udp
 //udp
 func (s *Sock5ModeServer) handleUDP(c net.Conn) {
 func (s *Sock5ModeServer) handleUDP(c net.Conn) {
-	lg.Println("UDP Associate")
 	/*
 	/*
 	   +----+------+------+----------+----------+----------+
 	   +----+------+------+----------+----------+----------+
 	   |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
 	   |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
@@ -178,7 +177,7 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) {
 	// relay udp datagram silently, without any notification to the requesting client
 	// relay udp datagram silently, without any notification to the requesting client
 	if buf[2] != 0 {
 	if buf[2] != 0 {
 		// does not support fragmentation, drop it
 		// does not support fragmentation, drop it
-		lg.Println("does not support fragmentation, drop")
+		logs.Warn("does not support fragmentation, drop")
 		dummy := make([]byte, maxUDPPacketSize)
 		dummy := make([]byte, maxUDPPacketSize)
 		c.Read(dummy)
 		c.Read(dummy)
 	}
 	}
@@ -190,13 +189,13 @@ func (s *Sock5ModeServer) handleUDP(c net.Conn) {
 func (s *Sock5ModeServer) handleConn(c net.Conn) {
 func (s *Sock5ModeServer) handleConn(c net.Conn) {
 	buf := make([]byte, 2)
 	buf := make([]byte, 2)
 	if _, err := io.ReadFull(c, buf); err != nil {
 	if _, err := io.ReadFull(c, buf); err != nil {
-		lg.Println("negotiation err", err)
+		logs.Warn("negotiation err", err)
 		c.Close()
 		c.Close()
 		return
 		return
 	}
 	}
 
 
 	if version := buf[0]; version != 5 {
 	if version := buf[0]; version != 5 {
-		lg.Println("only support socks5, request from: ", c.RemoteAddr())
+		logs.Warn("only support socks5, request from: ", c.RemoteAddr())
 		c.Close()
 		c.Close()
 		return
 		return
 	}
 	}
@@ -204,7 +203,7 @@ func (s *Sock5ModeServer) handleConn(c net.Conn) {
 
 
 	methods := make([]byte, nMethods)
 	methods := make([]byte, nMethods)
 	if len, err := c.Read(methods); len != int(nMethods) || err != nil {
 	if len, err := c.Read(methods); len != int(nMethods) || err != nil {
-		lg.Println("wrong method")
+		logs.Warn("wrong method")
 		c.Close()
 		c.Close()
 		return
 		return
 	}
 	}
@@ -213,7 +212,7 @@ func (s *Sock5ModeServer) handleConn(c net.Conn) {
 		c.Write(buf)
 		c.Write(buf)
 		if err := s.Auth(c); err != nil {
 		if err := s.Auth(c); err != nil {
 			c.Close()
 			c.Close()
-			lg.Println("Validation failed:", err)
+			logs.Warn("Validation failed:", err)
 			return
 			return
 		}
 		}
 	} else {
 	} else {
@@ -271,9 +270,15 @@ func (s *Sock5ModeServer) Start() error {
 			if strings.Contains(err.Error(), "use of closed network connection") {
 			if strings.Contains(err.Error(), "use of closed network connection") {
 				break
 				break
 			}
 			}
-			lg.Fatalln("accept error: ", err)
+			logs.Warn("accept error: ", err)
+		}
+		if s.task.Client.GetConn() {
+			logs.Trace("New socks5 connection,client %d,remote address %s", s.task.Client.Id, conn.RemoteAddr())
+			go s.handleConn(conn)
+		} else {
+			logs.Warn("Connections exceed the current client %d limit", s.task.Client.Id)
+			conn.Close()
 		}
 		}
-		go s.handleConn(conn)
 	}
 	}
 	return nil
 	return nil
 }
 }

+ 20 - 26
server/proxy/tcp.go

@@ -6,15 +6,16 @@ import (
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/file"
-	"github.com/cnlh/nps/lib/lg"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"net"
 	"net"
+	"os"
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 )
 )
 
 
 type TunnelModeServer struct {
 type TunnelModeServer struct {
-	server
+	BaseServer
 	process  process
 	process  process
 	listener *net.TCPListener
 	listener *net.TCPListener
 }
 }
@@ -41,24 +42,16 @@ func (s *TunnelModeServer) Start() error {
 			if strings.Contains(err.Error(), "use of closed network connection") {
 			if strings.Contains(err.Error(), "use of closed network connection") {
 				break
 				break
 			}
 			}
-			lg.Println(err)
+			logs.Info(err)
 			continue
 			continue
 		}
 		}
-		go s.process(conn.NewConn(c), s)
-	}
-	return nil
-}
-
-//与客户端建立通道
-func (s *TunnelModeServer) dealClient(c *conn.Conn, cnf *file.Config, addr string, method string, rb []byte) error {
-	link := conn.NewLink(s.task.Client.GetId(), common.CONN_TCP, addr, cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, c, s.task.Flow, nil, s.task.Client.Rate, nil)
-
-	if tunnel, err := s.bridge.SendLinkInfo(s.task.Client.Id, link, c.Conn.RemoteAddr().String()); err != nil {
-		c.Close()
-		return err
-	} else {
-		link.Run(true)
-		s.linkCopy(link, c, rb, tunnel, s.task.Flow)
+		if s.task.Client.GetConn() {
+			logs.Trace("New tcp connection,client %d,remote address %s", s.task.Client.Id, c.RemoteAddr())
+			go s.process(conn.NewConn(c), s)
+		} else {
+			logs.Info("Connections exceed the current client %d limit", s.task.Client.Id)
+			c.Close()
+		}
 	}
 	}
 	return nil
 	return nil
 }
 }
@@ -70,17 +63,18 @@ func (s *TunnelModeServer) Close() error {
 
 
 //web管理方式
 //web管理方式
 type WebServer struct {
 type WebServer struct {
-	server
+	BaseServer
 }
 }
 
 
 //开始
 //开始
 func (s *WebServer) Start() error {
 func (s *WebServer) Start() error {
 	p, _ := beego.AppConfig.Int("httpport")
 	p, _ := beego.AppConfig.Int("httpport")
 	if !common.TestTcpPort(p) {
 	if !common.TestTcpPort(p) {
-		lg.Fatalf("Web management port %d is occupied", p)
+		logs.Error("Web management port %d is occupied", p)
+		os.Exit(0)
 	}
 	}
 	beego.BConfig.WebConfig.Session.SessionOn = true
 	beego.BConfig.WebConfig.Session.SessionOn = true
-	lg.Println("Web management start, access port is", p)
+	logs.Info("Web management start, access port is", p)
 	beego.SetStaticPath("/static", filepath.Join(common.GetRunPath(), "web", "static"))
 	beego.SetStaticPath("/static", filepath.Join(common.GetRunPath(), "web", "static"))
 	beego.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views"))
 	beego.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views"))
 	beego.Run()
 	beego.Run()
@@ -102,23 +96,23 @@ type process func(c *conn.Conn, s *TunnelModeServer) error
 
 
 //tcp隧道模式
 //tcp隧道模式
 func ProcessTunnel(c *conn.Conn, s *TunnelModeServer) error {
 func ProcessTunnel(c *conn.Conn, s *TunnelModeServer) error {
-	return s.dealClient(c, s.task.Client.Cnf, s.task.Target, "", nil)
+	return s.DealClient(c, s.task.Target, nil)
 }
 }
 
 
 //http代理模式
 //http代理模式
 func ProcessHttp(c *conn.Conn, s *TunnelModeServer) error {
 func ProcessHttp(c *conn.Conn, s *TunnelModeServer) error {
-	method, addr, rb, err, r := c.GetHost()
+	_, addr, rb, err, r := c.GetHost()
 	if err != nil {
 	if err != nil {
 		c.Close()
 		c.Close()
-		lg.Println(err)
+		logs.Info(err)
 		return err
 		return err
 	}
 	}
 	if r.Method == "CONNECT" {
 	if r.Method == "CONNECT" {
 		c.Write([]byte("HTTP/1.1 200 Connection Established\r\n"))
 		c.Write([]byte("HTTP/1.1 200 Connection Established\r\n"))
-		rb = nil //reset
+		rb = nil
 	}
 	}
 	if err := s.auth(r, c, s.task.Client.Cnf.U, s.task.Client.Cnf.P); err != nil {
 	if err := s.auth(r, c, s.task.Client.Cnf.U, s.task.Client.Cnf.P); err != nil {
 		return err
 		return err
 	}
 	}
-	return s.dealClient(c, s.task.Client.Cnf, addr, method, rb)
+	return s.DealClient(c, addr, rb)
 }
 }

+ 3 - 1
server/proxy/udp.go

@@ -6,12 +6,13 @@ import (
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/conn"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/pool"
 	"github.com/cnlh/nps/lib/pool"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
 	"net"
 	"net"
 	"strings"
 	"strings"
 )
 )
 
 
 type UdpModeServer struct {
 type UdpModeServer struct {
-	server
+	BaseServer
 	listener *net.UDPConn
 	listener *net.UDPConn
 	udpMap   map[string]*conn.Conn
 	udpMap   map[string]*conn.Conn
 }
 }
@@ -40,6 +41,7 @@ func (s *UdpModeServer) Start() error {
 			}
 			}
 			continue
 			continue
 		}
 		}
+		logs.Trace("New ydo connection,client %d,remote address %s", s.task.Client.Id, addr)
 		go s.process(addr, buf[:n])
 		go s.process(addr, buf[:n])
 	}
 	}
 	return nil
 	return nil

+ 54 - 14
server/server.go

@@ -5,10 +5,12 @@ import (
 	"github.com/cnlh/nps/bridge"
 	"github.com/cnlh/nps/bridge"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/file"
-	"github.com/cnlh/nps/lib/lg"
 	"github.com/cnlh/nps/server/proxy"
 	"github.com/cnlh/nps/server/proxy"
 	"github.com/cnlh/nps/server/tool"
 	"github.com/cnlh/nps/server/tool"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego"
 	"github.com/cnlh/nps/vender/github.com/astaxie/beego"
+	"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
+	"os"
+	"time"
 )
 )
 
 
 var (
 var (
@@ -31,7 +33,6 @@ func InitFromCsv() {
 	//Initialize services in server-side files
 	//Initialize services in server-side files
 	for _, v := range file.GetCsvDb().Tasks {
 	for _, v := range file.GetCsvDb().Tasks {
 		if v.Status {
 		if v.Status {
-			lg.Println("task start info: mode:", v.Mode, "port:", v.Port)
 			AddTask(v)
 			AddTask(v)
 		}
 		}
 	}
 	}
@@ -45,6 +46,19 @@ func DealBridgeTask() {
 		case id := <-Bridge.CloseClient:
 		case id := <-Bridge.CloseClient:
 			DelTunnelAndHostByClientId(id)
 			DelTunnelAndHostByClientId(id)
 			file.GetCsvDb().DelClient(id)
 			file.GetCsvDb().DelClient(id)
+		case s := <-Bridge.SecretChan:
+			logs.Trace("New secret connection, addr", s.Conn.Conn.RemoteAddr())
+			if t := file.GetCsvDb().GetSecretTask(s.Password); t != nil {
+				if !t.Client.GetConn() {
+					logs.Info("Connections exceed the current client %d limit", t.Client.Id)
+					s.Conn.Close()
+				} else {
+					go proxy.NewBaseServer(Bridge, t).DealClient(s.Conn, t.Target, nil)
+				}
+			} else {
+				logs.Trace("This key %s cannot be processed", s.Password)
+				s.Conn.Close()
+			}
 		}
 		}
 	}
 	}
 }
 }
@@ -53,18 +67,19 @@ func DealBridgeTask() {
 func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
 func StartNewServer(bridgePort int, cnf *file.Tunnel, bridgeType string) {
 	Bridge = bridge.NewTunnel(bridgePort, bridgeType, common.GetBoolByStr(beego.AppConfig.String("ipLimit")), RunList)
 	Bridge = bridge.NewTunnel(bridgePort, bridgeType, common.GetBoolByStr(beego.AppConfig.String("ipLimit")), RunList)
 	if err := Bridge.StartTunnel(); err != nil {
 	if err := Bridge.StartTunnel(); err != nil {
-		lg.Fatalln("服务端开启失败", err)
+		logs.Error("服务端开启失败", err)
+		os.Exit(0)
 	} else {
 	} else {
-		lg.Printf("Server startup, the bridge type is %s, the bridge port is %d", bridgeType, bridgePort)
+		logs.Info("Server startup, the bridge type is %s, the bridge port is %d", bridgeType, bridgePort)
 	}
 	}
 	go DealBridgeTask()
 	go DealBridgeTask()
 	if svr := NewMode(Bridge, cnf); svr != nil {
 	if svr := NewMode(Bridge, cnf); svr != nil {
 		if err := svr.Start(); err != nil {
 		if err := svr.Start(); err != nil {
-			lg.Fatalln(err)
+			logs.Error(err)
 		}
 		}
 		RunList[cnf.Id] = svr
 		RunList[cnf.Id] = svr
 	} else {
 	} else {
-		lg.Fatalln("启动模式%s不正确", cnf.Mode)
+		logs.Error("Incorrect startup mode %s", cnf.Mode)
 	}
 	}
 }
 }
 
 
@@ -103,12 +118,12 @@ func StopServer(id int) error {
 			if err := svr.Close(); err != nil {
 			if err := svr.Close(); err != nil {
 				return err
 				return err
 			}
 			}
-			if t, err := file.GetCsvDb().GetTask(id); err != nil {
-				return err
-			} else {
-				t.Status = false
-				file.GetCsvDb().UpdateTask(t)
-			}
+		}
+		if t, err := file.GetCsvDb().GetTask(id); err != nil {
+			return err
+		} else {
+			t.Status = false
+			file.GetCsvDb().UpdateTask(t)
 		}
 		}
 		delete(RunList, id)
 		delete(RunList, id)
 		return nil
 		return nil
@@ -118,15 +133,24 @@ func StopServer(id int) error {
 
 
 //add task
 //add task
 func AddTask(t *file.Tunnel) error {
 func AddTask(t *file.Tunnel) error {
+	if t.Mode == "secretServer" {
+		logs.Info("secret task %s start ", t.Remark)
+		RunList[t.Id] = nil
+		return nil
+	}
 	if b := tool.TestServerPort(t.Port, t.Mode); !b && t.Mode != "httpHostServer" {
 	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)
+		logs.Error("taskId %d start error port %d open failed", t.Id, t.Port)
 		return errors.New("the port open error")
 		return errors.New("the port open error")
 	}
 	}
+	if minute, err := beego.AppConfig.Int("flowStoreInterval"); err == nil && minute > 0 {
+		go flowSession(time.Minute * time.Duration(minute))
+	}
 	if svr := NewMode(Bridge, t); svr != nil {
 	if svr := NewMode(Bridge, t); svr != nil {
+		logs.Info("tunnel task %s start mode:%s port %d", t.Remark, t.Mode, t.Port)
 		RunList[t.Id] = svr
 		RunList[t.Id] = svr
 		go func() {
 		go func() {
 			if err := svr.Start(); err != nil {
 			if err := svr.Start(); err != nil {
-				lg.Println("clientId %d taskId %d start error %s", t.Client.Id, t.Id, err)
+				logs.Error("clientId %d taskId %d start error %s", t.Client.Id, t.Id, err)
 				delete(RunList, t.Id)
 				delete(RunList, t.Id)
 				return
 				return
 			}
 			}
@@ -272,5 +296,21 @@ func GetDashboardData() map[string]int {
 			data["udpServerCount"] += 1
 			data["udpServerCount"] += 1
 		}
 		}
 	}
 	}
+	tcpCount := 0
+	for _, v := range file.GetCsvDb().Clients {
+		tcpCount += v.NowConn
+	}
+	data["tcpCount"] = tcpCount
 	return data
 	return data
 }
 }
+
+func flowSession(m time.Duration) {
+	ticker := time.NewTicker(m)
+	for {
+		select {
+		case <-ticker.C:
+			file.GetCsvDb().StoreHostToCsv()
+			file.GetCsvDb().StoreTasksToCsv()
+		}
+	}
+}

+ 3 - 0
server/tool/utils.go

@@ -13,6 +13,9 @@ func init() {
 }
 }
 
 
 func TestServerPort(p int, m string) (b bool) {
 func TestServerPort(p int, m string) (b bool) {
+	if p > 65535 || p <= 0 {
+		return false
+	}
 	if len(ports) != 0 {
 	if len(ports) != 0 {
 		if !common.InIntArr(ports, p) {
 		if !common.InIntArr(ports, p) {
 			return false
 			return false

+ 2 - 0
web/controllers/client.go

@@ -42,6 +42,7 @@ func (s *ClientController) Add() {
 				Crypt:    s.GetBoolNoErr("crypt"),
 				Crypt:    s.GetBoolNoErr("crypt"),
 			},
 			},
 			RateLimit: s.GetIntNoErr("rate_limit"),
 			RateLimit: s.GetIntNoErr("rate_limit"),
+			MaxConn:   s.GetIntNoErr("max_conn"),
 			Flow: &file.Flow{
 			Flow: &file.Flow{
 				ExportFlow: 0,
 				ExportFlow: 0,
 				InletFlow:  0,
 				InletFlow:  0,
@@ -94,6 +95,7 @@ func (s *ClientController) Edit() {
 			c.Cnf.Crypt = s.GetBoolNoErr("crypt")
 			c.Cnf.Crypt = s.GetBoolNoErr("crypt")
 			c.Flow.FlowLimit = int64(s.GetIntNoErr("flow_limit"))
 			c.Flow.FlowLimit = int64(s.GetIntNoErr("flow_limit"))
 			c.RateLimit = s.GetIntNoErr("rate_limit")
 			c.RateLimit = s.GetIntNoErr("rate_limit")
+			c.MaxConn = s.GetIntNoErr("max_conn")
 			if c.Rate != nil {
 			if c.Rate != nil {
 				c.Rate.Stop()
 				c.Rate.Stop()
 			}
 			}

+ 15 - 7
web/controllers/index.go

@@ -44,6 +44,12 @@ func (s *IndexController) Http() {
 	s.display("index/list")
 	s.display("index/list")
 }
 }
 
 
+func (s *IndexController) Secret() {
+	s.SetInfo("私密代理管理")
+	s.SetType("secretServer")
+	s.display("index/list")
+}
+
 func (s *IndexController) Host() {
 func (s *IndexController) Host() {
 	s.SetInfo("host模式管理")
 	s.SetInfo("host模式管理")
 	s.SetType("hostServer")
 	s.SetType("hostServer")
@@ -74,13 +80,14 @@ func (s *IndexController) Add() {
 		s.display()
 		s.display()
 	} else {
 	} else {
 		t := &file.Tunnel{
 		t := &file.Tunnel{
-			Port:   s.GetIntNoErr("port"),
-			Mode:   s.GetString("type"),
-			Target: s.GetString("target"),
-			Id:     file.GetCsvDb().GetTaskId(),
-			Status: true,
-			Remark: s.GetString("remark"),
-			Flow:   &file.Flow{},
+			Port:     s.GetIntNoErr("port"),
+			Mode:     s.GetString("type"),
+			Target:   s.GetString("target"),
+			Id:       file.GetCsvDb().GetTaskId(),
+			Status:   true,
+			Remark:   s.GetString("remark"),
+			Password: s.GetString("password"),
+			Flow:     &file.Flow{},
 		}
 		}
 		if !tool.TestServerPort(t.Port, t.Mode) {
 		if !tool.TestServerPort(t.Port, t.Mode) {
 			s.AjaxErr("The port cannot be opened because it may has been occupied or is no longer allowed.")
 			s.AjaxErr("The port cannot be opened because it may has been occupied or is no longer allowed.")
@@ -126,6 +133,7 @@ func (s *IndexController) Edit() {
 			t.Port = s.GetIntNoErr("port")
 			t.Port = s.GetIntNoErr("port")
 			t.Mode = s.GetString("type")
 			t.Mode = s.GetString("type")
 			t.Target = s.GetString("target")
 			t.Target = s.GetString("target")
+			t.Password = s.GetString("password")
 			t.Id = id
 			t.Id = id
 			t.Remark = s.GetString("remark")
 			t.Remark = s.GetString("remark")
 			if t.Client, err = file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil {
 			if t.Client, err = file.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil {

+ 4 - 0
web/views/client/add.html

@@ -16,6 +16,10 @@
                         <label class="control-label">速度限制(单位:KB,为空不限制)</label>
                         <label class="control-label">速度限制(单位:KB,为空不限制)</label>
                         <input class="form-control" type="text" name="rate_limit" placeholder="为空不限制">
                         <input class="form-control" type="text" name="rate_limit" placeholder="为空不限制">
                     </div>
                     </div>
+                    <div class="form-group" id="max_conn">
+                        <label class="control-label">最大客户端连接数</label>
+                        <input class="form-control" type="text" name="max_conn" placeholder="为空不限制">
+                    </div>
                     <div class="form-group" id="u">
                     <div class="form-group" id="u">
                         <label class="control-label">验证用户名(仅socks5,web穿透支持)</label>
                         <label class="control-label">验证用户名(仅socks5,web穿透支持)</label>
                         <input class="form-control" type="text" name="u" placeholder="不填则无需验证">
                         <input class="form-control" type="text" name="u" placeholder="不填则无需验证">

+ 5 - 0
web/views/client/edit.html

@@ -19,6 +19,11 @@
                         <input class="form-control" value="{{.c.RateLimit}}" type="text" name="rate_limit"
                         <input class="form-control" value="{{.c.RateLimit}}" type="text" name="rate_limit"
                                placeholder="为空不限制">
                                placeholder="为空不限制">
                     </div>
                     </div>
+                    <div class="form-group" id="max_conn">
+                        <label class="control-label">最大客户端连接数</label>
+                        <input class="form-control" value="{{.c.MaxConn}}" type="text" name="max_conn"
+                               placeholder="为空不限制">
+                    </div>
                     <div class="form-group" id="u">
                     <div class="form-group" id="u">
                         <label class="control-label">验证用户名(仅socks5,web穿透支持)</label>
                         <label class="control-label">验证用户名(仅socks5,web穿透支持)</label>
                         <input class="form-control" value="{{.c.Cnf.U}}" type="text" name="u"
                         <input class="form-control" value="{{.c.Cnf.U}}" type="text" name="u"

+ 7 - 0
web/views/index/add.html

@@ -11,6 +11,7 @@
                             <option {{if eq "udpServer" .type}}selected{{end}} value="udpServer">udp隧道</option>
                             <option {{if eq "udpServer" .type}}selected{{end}} value="udpServer">udp隧道</option>
                             <option {{if eq "socks5Server" .type}}selected{{end}} value="socks5Server">socks5代理</option>
                             <option {{if eq "socks5Server" .type}}selected{{end}} value="socks5Server">socks5代理</option>
                             <option {{if eq "httpProxyServer" .type}}selected{{end}} value="httpProxyServer">http代理
                             <option {{if eq "httpProxyServer" .type}}selected{{end}} value="httpProxyServer">http代理
+                            <option {{if eq "secretServer" .type}}selected{{end}} value="secretServer">私密代理
                         </select>
                         </select>
                     </div>
                     </div>
                     <div class="form-group">
                     <div class="form-group">
@@ -30,6 +31,11 @@
                         <input value="{{.client_id}}" class="form-control" type="text" name="client_id"
                         <input value="{{.client_id}}" class="form-control" type="text" name="client_id"
                                placeholder="客户端id">
                                placeholder="客户端id">
                     </div>
                     </div>
+                    <div class="form-group" id="password">
+                        <label class="control-label">私密模式唯一密钥</label>
+                        <input class="form-control" type="text" name="password"
+                               placeholder="私密模式唯一密钥">
+                    </div>
                 </form>
                 </form>
             </div>
             </div>
             <div class="tile-footer">
             <div class="tile-footer">
@@ -48,6 +54,7 @@
     arr["udpServer"] = ["type", "port", "target", "compress", "udp隧道模式,提供一条udp隧道,适用于dns、内网dns访问等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,访问公网服务器的设定端口,则相当于访问内网目标地址的udp目标端口"]
     arr["udpServer"] = ["type", "port", "target", "compress", "udp隧道模式,提供一条udp隧道,适用于dns、内网dns访问等,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,访问公网服务器的设定端口,则相当于访问内网目标地址的udp目标端口"]
     arr["socks5Server"] = ["type", "port", "compress", "u", "p", "socks5代理模式,内网socks5代理,配合proxifer,可如同使用vpn一样访问内网设备或资源,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置socks5代理,即访问内网设备或者资源 "]
     arr["socks5Server"] = ["type", "port", "compress", "u", "p", "socks5代理模式,内网socks5代理,配合proxifer,可如同使用vpn一样访问内网设备或资源,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置socks5代理,即访问内网设备或者资源 "]
     arr["httpProxyServer"] = ["type", "port", "compress", "u", "p", " http代理模式,内网http代理,可访问内网网站,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置http代理,即访问内网站点"]
     arr["httpProxyServer"] = ["type", "port", "compress", "u", "p", " http代理模式,内网http代理,可访问内网网站,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置http代理,即访问内网站点"]
+    arr["secretServer"] = ["type", "target", "compress", "password", "u", "p", " http代理模式,内网http代理,可访问内网网站,添加后会自动生成一个客户端验证key<br>在内网机器执行<span style='color: red'>./easyProxy -vkey=生成的key -server=公网服务器ip:下面设定的端口</span><br>建立成功后,在外网环境下本机配置http代理,即访问内网站点"]
     arrClientHide = ["compress", "u", "p", "crypt", "mux"]
     arrClientHide = ["compress", "u", "p", "crypt", "mux"]
 
 
     function resetForm() {
     function resetForm() {

+ 7 - 0
web/views/index/edit.html

@@ -13,6 +13,7 @@
                             <option {{if eq "socks5Server" .t.Mode}}selected{{end}} value="socks5Server">socks5代理
                             <option {{if eq "socks5Server" .t.Mode}}selected{{end}} value="socks5Server">socks5代理
                             </option>
                             </option>
                             <option {{if eq "httpProxyServer" .t.Mode}}selected{{end}} value="httpProxyServer">http代理
                             <option {{if eq "httpProxyServer" .t.Mode}}selected{{end}} value="httpProxyServer">http代理
+                            <option {{if eq "secretServer" .t.Mode}}selected{{end}} value="secretServer">私密代理
                         </select>
                         </select>
                     </div>
                     </div>
                     <div class="form-group">
                     <div class="form-group">
@@ -34,6 +35,11 @@
                         <input class="form-control" value="{{.t.Client.Id}}" type="text" name="client_id"
                         <input class="form-control" value="{{.t.Client.Id}}" type="text" name="client_id"
                                placeholder="客户端id">
                                placeholder="客户端id">
                     </div>
                     </div>
+                    <div class="form-group" id="password">
+                        <label class="control-label">私密模式唯一密钥</label>
+                        <input class="form-control" value="{{.t.Password}}" type="text" name="password"
+                               placeholder="私密模式唯一密钥">
+                    </div>
                 </form>
                 </form>
             </div>
             </div>
             <div class="tile-footer">
             <div class="tile-footer">
@@ -52,6 +58,7 @@
     arr["udpServer"] = ["type", "port", "target", "compress"]
     arr["udpServer"] = ["type", "port", "target", "compress"]
     arr["socks5Server"] = ["type", "port", "compress", "u", "p"]
     arr["socks5Server"] = ["type", "port", "compress", "u", "p"]
     arr["httpProxyServer"] = ["type", "port", "compress", "u", "p"]
     arr["httpProxyServer"] = ["type", "port", "compress", "u", "p"]
+    arr["secretServer"] = ["type", "target", "compress", "u", "p","password"]
     arrClientHide = ["compress", "u", "p", "crypt", "mux"]
     arrClientHide = ["compress", "u", "p", "crypt", "mux"]
 
 
     function resetForm() {
     function resetForm() {

+ 2 - 2
web/views/index/index.html

@@ -10,8 +10,8 @@
     <div class="col-md-3">
     <div class="col-md-3">
         <div class="widget-small danger coloured-icon"><i class="icon fa fa-home fa-3x"></i>
         <div class="widget-small danger coloured-icon"><i class="icon fa fa-home fa-3x"></i>
             <div class="info">
             <div class="info">
-                <h4>域名解析数</h4>
-                <p><b>{{.data.hostCount}}</b></p>
+                <h4>当前TCP连接总数</h4>
+                <p><b>{{.data.tcpCount}}</b></p>
             </div>
             </div>
         </div>
         </div>
     </div>
     </div>

+ 4 - 2
web/views/public/layout.html

@@ -51,9 +51,11 @@
         <li><a class="app-menu__item {{if eq "udp" .menu}}active{{end}}" href="/index/udp"><i
         <li><a class="app-menu__item {{if eq "udp" .menu}}active{{end}}" href="/index/udp"><i
                 class="app-menu__icon fa fa-laptop"></i><span class="app-menu__label">udp隧道管理</span></a></li>
                 class="app-menu__icon fa fa-laptop"></i><span class="app-menu__label">udp隧道管理</span></a></li>
         <li><a class="app-menu__item {{if eq "socks5" .menu}}active{{end}}" href="/index/socks5"><i
         <li><a class="app-menu__item {{if eq "socks5" .menu}}active{{end}}" href="/index/socks5"><i
-                class="app-menu__icon fa fa-lightbulb-o"></i><span class="app-menu__label">socks5代理</span></a></li>
+                class="app-menu__icon fa fa-lightbulb-o"></i><span class="app-menu__label">socks5代理管理</span></a></li>
         <li><a class="app-menu__item {{if eq "http" .menu}}active{{end}}" href="/index/http"><i
         <li><a class="app-menu__item {{if eq "http" .menu}}active{{end}}" href="/index/http"><i
-                class="app-menu__icon fa fa-magic"></i><span class="app-menu__label">http代理</span></a></li>
+                class="app-menu__icon fa fa-magic"></i><span class="app-menu__label">http代理管理</span></a></li>
+        <li><a class="app-menu__item {{if eq "secret" .menu}}active{{end}}" href="/index/secret"><i
+                class="app-menu__icon fa fa-dashcube"></i><span class="app-menu__label">私密代理管理</span></a></li>
         <li><a class="app-menu__item {{if eq "help" .menu}}active{{end}}" href="/index/help"><i
         <li><a class="app-menu__item {{if eq "help" .menu}}active{{end}}" href="/index/help"><i
                 class="app-menu__icon fa fa-question-circle"></i><span class="app-menu__label">使用说明</span></a></li>
                 class="app-menu__icon fa fa-question-circle"></i><span class="app-menu__label">使用说明</span></a></li>
     </ul>
     </ul>